如何使用Python爬虫获取offcn上的公考信息及写入Excel表格并发送至指定邮箱
如何使用Python爬虫获取offcn上的公考信息及写入Excel表格并发送至指定邮箱
目录
又到了一年毕业季,应届毕业生们又该忙碌起来寻找各种工作了,offcn.com是一个不错的网站,所以我想着如何将上面的信息爬下来并用Excel显示出来,顺便也能练练很久没用的爬虫技巧。
package的使用
在这个Python程序里主要要用到的packages是
- selenium(非常好用的自动化测试工具)
- xlwt(用来对Excel进行写入,顺带一提读取是xlrd,这两者可单独使用)
- smtplib(对简单邮件传输协议(也就是大名鼎鼎的SMTP)进行封装的库)
- MIMEText和MIMEMultipart(允许Python发送附带HTML格式的文字以及附件)
主要代码块
from selenium import webdriver
import xlwt
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
chrome_driver = r'C:\Users\算师妙\AppData\Local\Programs\Python\Python36\chromedriver.exe' #这个是Chromedriver的储存地址
chrome_options = webdriver.ChromeOptions()# 使用headless*面浏览器模式
chrome_options.add_argument('--headless') # 增加*面选项
chrome_options.add_argument('--disable-gpu') # 如果不加这个选项,有时定位会出现问题
browser = webdriver.Chrome(executable_path=chrome_driver)
browser.implicitly_wait(10) # 隐性等待,如等待时间过长,请使用显性等待
browser.get('http://www.offcn.com/sydw/kaoshi/zj/1.html') # 请将zj改成其他省份的缩写
lists1 = [] #用来储存类型
lists2 = [] #用来储存发布时间
lists3 = [] #用来储存标题
lists4 = [] #用来储存访问网址
for i in range(58): #一页有58项需要爬取
assemble1 = 'body > div:nth-child(5) > div > div.lh_left > div.lh_Hotrecommend > ul.lh_newBobotm02 > li:nth-child('
assemble2 = ') > a.lh_olistCatename'
str1 = browser.find_elements_by_css_selector(assemble1 + str(i) + assemble2)
for j in str1:
a = j.text
lists1.append(a)
print(a)
assemble3 = ') > span'
str2 = browser.find_elements_by_css_selector(assemble1 + str(i) + assemble3)
for k in str2:
a = k.text
lists2.append(a)
print(a)
assemble4 = ') > a:nth-child(3)'
str3 = browser.find_elements_by_css_selector(assemble1 + str(i) + assemble4)
for l in str3:
a = l.text
b = l.get_attribute('href')
lists3.append(a)
lists4.append(b)
print(a, b)
print(lists1, lists2, lists3, lists4)
browser.quit() #关闭浏览器
# 写入Excel部分
wtbook = xlwt.Workbook(encoding='utf-8')
sheet = wtbook.add_sheet('sheet1', cell_overwrite_ok=True) # 新增一个sheet工作表
row0 = [u'类型', u'时间', u'标题', u'网址']
for i in range(0, len(row0)): #写入数据头
sheet.write(0, i, row0[i])
for i in range(len(lists1)):
sheet.write(i + 1, 0, lists1[i]) #写入第i+1行第0列,在Excel中行列都是从0开始计数的
sheet.write(i + 1, 1, lists2[i])
sheet.write(i + 1, 2, lists3[i])
sheet.write(i + 1, 3, lists4[i])
wtbook.save('工作簿1.xls') #保存Excel文件
#发送邮件部分
# 设置邮箱的域名
HOST = 'smtp.qq.com'
# 设置邮件标题
SUBJECT = '%s日份招聘信息' % today_time
# 设置发件人邮箱
FROM = 'XXXXXXX@qq.com'
# 设置收件人邮箱
TO = 'XXXXXXXX@qq.com' # 可以同时发送到多个邮箱
message = MIMEMultipart('related')
# --------------------------------------发送文本-----------------
# 邮件正文内容
message.attach(MIMEText('今日份的招聘信息,请查收', 'plain', 'utf-8'))
# 发送附件
att1 = MIMEText(open('工作簿1.xls', 'rb').read(), 'base64', 'utf-8')
att1["Content-Type"] = 'application/octet-stream'
# 这里的filename可以任意写,写什么名字,邮件中显示什么名字
att1["Content-Disposition"] = 'attachment; filename="工作簿1.xls"'
message.attach(att1)
# 设置邮件发件人
message['From'] = FROM
# 设置邮件收件人
message['To'] = TO
# 设置邮件标题
message['Subject'] = SUBJECT
# 获取简单邮件传输协议的证书
email_client = smtplib.SMTP_SSL()
# 设置发件人邮箱的域名和端口,端口为465
email_client.connect(HOST, '465')
# ---------------------------邮箱授权码------------------------------
result = email_client.login(FROM, 'zkumuwfdhgzjcaef') # 授权码填写
print('登录结果', result)
email_client.sendmail(from_addr=FROM, to_addrs=TO.split(','), msg=message.as_string())
# 关闭邮件发送客户端
email_client.close()
Chromedriver块的解释
要使用selenium,各种浏览器的driver是必不可少的,因为selenium本身就是一个自动化测试工具,除去Chrome,你也可以使用Firefox甚至IE(气抖冷,IE什么时候才能站起来),Chromedriver需要在本机安装Chrome的前提下去官网上下载drivers,本机的Chrome版本号在设置的关于Chrome里
如图中楼主的Chrome版本号是83.0.4103.116,那么在官网上的83.0.4103.14或者83.0.4103.39都是可以使用的,进入对应的文件夹后下载适合自己操作系统的文件就行了。(顺带一提,请给与Chromedriver管理员权限,pycharm也是如此,不然会报权限不足的错误)
爬虫代码块的解释
这大概是最有技术含量的一块了,其实说是最有技术含量,爬虫写多了也就觉得不难了。
首先,想要写好爬虫,要对目标网站的网页结构进行一定的分析,在Chrome中对目标网页按下F12,进入开发者工具模式,会跳出来网页的源代码,会有一大段,看到先别慌,因为真正难的还在后面(笑),将你的鼠标在源代码上一行行往下挪,鼠标光标在有一行上停留时你会突然发现你想要爬的数据变蓝了
就像图中一样,当我把鼠标移至div class="zg_box zg_1600 zg_1366"上时,整个块都变蓝了,然后我们将这个div点开来,会发现有一块全是li标签,那就表示你成功找到了目标源代码
然后我们把li标签点开,发现时间是在span标签下的,消息类型是在lh_olistCatename class里的,标题在title=“XXXXX”里,意味着我们需要将他们分门别类的爬出来,我们固然可以用browser.find_elements_by_class或者browser.find_elements_by_id,但这显然太繁琐了
其实还有一种更加简(lan)便(duo)的方法,那就是用css sector,在代码行上右键复制css sector
例如图中的2020-07-02,它的sector地址就是body > div:nth-child(5) > div > div.lh_left > div.lh_Hotrecommend > ul.lh_newBobotm02 > li:nth-child(1) > span > font,这里说一句,从图中很明显可以看出来,网站制作者为了突出最新上架的消息,将日期标红了,这其实是font的作用,而且对后几行日期的分析可以看出来,其实后面日期的sector就是将 li:nth-child(1)里的数字进行逐步增大而已,所以我们可以套用一个循环将browser.find_elements_by_css_selector()里的sector改成body > div:nth-child(5) > div > div.lh_left > div.lh_Hotrecommend > ul.lh_newBobotm02 > li:nth-child(i) > span就行(前文已经讲到font只是将字号以及颜色进行改变,并不印象信息的爬取)
但这又会产生另一个问题,如果我们直接套用browser.find_elements_by_css_selector(‘body > div:nth-child(5) > div > div.lh_left > div.lh_Hotrecommend > ul.lh_newBobotm02 > li:nth-child(1) > span’),i会被程序认为是一个普通的string,而不是变量i,所以我在原程序中使用了三层组合string,将原string拆成了三段,然后将变量i转string合成了sector地址
同样的道理,对标题,类型,以及网址也是一样处理,然后将数据存入不同数组中以便写入Excel表格,顺带一提,如果我不想看其中的’考试成绩’这个类型怎么办
解决方案就是对爬到的类型数据进行检测,如果是[成绩查询],就直接continue跳出这次循环
for i in range(58): #一页有58项需要爬取
assemble1 = 'body > div:nth-child(5) > div > div.lh_left > div.lh_Hotrecommend > ul.lh_newBobotm02 > li:nth-child('
assemble2 = ') > a.lh_olistCatename'
str1 = browser.find_elements_by_css_selector(assemble1 + str(i) + assemble2)
for j in str1:
a = j.text
if a == '[成绩查询]':
continue
lists1.append(a)
print(a)
assemble3 = ') > span'
str2 = browser.find_elements_by_css_selector(assemble1 + str(i) + assemble3)
for k in str2:
a = k.text
lists2.append(a)
print(a)
assemble4 = ') > a:nth-child(3)'
str3 = browser.find_elements_by_css_selector(assemble1 + str(i) + assemble4)
for l in str3:
a = l.text
b = l.get_attribute('href')
lists3.append(a)
lists4.append(b)
print(a, b)
print(lists1, lists2, lists3, lists4)
对于smtplib以及MIMEText和MIMEMultipart,请移步至菜鸟教程,这个网站对这些库有着更加详尽的解释。至于对邮箱的POP3/SMTP的设置,请移步至该网址,顺带给一个爬取日本东京天气以及当地新闻的爬虫,也是用Python写的,当时准备去日本时无聊花了一天写完的,大家凑活着看,希望有所收获XD
# coding=utf-8
import sys
import time
import json
import requests
import smtplib
import random
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from bs4 import BeautifulSoup
url = r'https://free-api.heweather.net/s6/weather/forecast?location=tokyo&key=xxxxxxxxxx'
today_time = time.strftime('%Y-%m-%d', time.localtime(time.time()))
res = requests.get(url)
res.encoding = 'utf-8'
res = json.loads(res.text)
print(res)
result = res['HeWeather6'][0]['daily_forecast'][0]
date_tomorrow = result['date']
hum_tomorrow = result['hum']
sr_tomorrow = result['sr']
ss_tomorrow = result['ss']
cond_tomorrow = result['cond_txt_d']
max_tomorrow = result['tmp_max']
min_tomorrow = result['tmp_min']
pop_tomorrow = result['pop']
pcpn_tomorrow = result['pcpn']
uv_tomorrow = result['uv_index']
vis_tomorrow = result['vis']
location = res['HeWeather6'][0]['basic']['location']
info = ' 城市: ' + location + "\n" + ' 时间: ' + date_tomorrow + "\n" + ' 天气状况: ' + cond_tomorrow + "\n" + ' 最高气温: ' + max_tomorrow + "\n" + \
' 最低气温: ' + min_tomorrow + "\n" + ' 日出: ' + sr_tomorrow + "\n" + ' 日落: ' + ss_tomorrow + "\n" + ' 相对湿度: ' + hum_tomorrow + '\n' + \
' 降水概率: ' + pop_tomorrow + '\n' + ' 降水量:' + pcpn_tomorrow + '\n' + ' 紫外线强度:' + uv_tomorrow + '\n' + " 能见度:" + vis_tomorrow + '\n\n'
time.sleep(3)
sess = requests.sessions
sess.keep_alive = False
proxies = {
'http': 'http://117.95.192.106:9999',
}
user_agents = ['Mozilla/5.0 (Windows NT 6.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1',
'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50',
'Opera/9.80 (Windows NT 6.1; U; en) Presto/2.8.131 Version/11.11']
headers = {'User-Agent': random.choice(user_agents)}
url = 'https://www.517japan.com/newsflash-3.html#box'
news = requests.get(url, headers=headers, proxies=proxies)
news.encoding = 'utf8'
soup = BeautifulSoup(news.text, 'lxml')
data1 = soup.select('body > div.newsflashes.clear > div.newsflashes_left > div.news_list > div:nth-child(1) > a > div.txt > h2')
brief1 = soup.select('body > div.newsflashes.clear > div.newsflashes_left > div.news_list > div:nth-child(1) > a > div.txt > p')
link1 = soup.select('body > div.newsflashes.clear > div.newsflashes_left > div.news_list > div:nth-child(1) > a')
for item in data1:
title1 = item.get_text()
for item in brief1:
sub_title1 = item.get_text()
for item in link1:
href1 = item.get('href')
data2 = soup.select('body > div.newsflashes.clear > div.newsflashes_left > div.news_list > div:nth-child(2) > a > div.txt > h2')
brief2 = soup.select('body > div.newsflashes.clear > div.newsflashes_left > div.news_list > div:nth-child(2) > a > div.txt > p')
link2 = soup.select('body > div.newsflashes.clear > div.newsflashes_left > div.news_list > div:nth-child(2) > a')
for item in data2:
title2 = item.get_text()
for item in brief2:
sub_title2 = item.get_text()
for item in link2:
href2 = item.get('href')
data3 = soup.select('body > div.newsflashes.clear > div.newsflashes_left > div.news_list > div:nth-child(3) > a > div.txt > h2')
brief3 = soup.select('body > div.newsflashes.clear > div.newsflashes_left > div.news_list > div:nth-child(3) > a > div.txt > p')
link3 = soup.select('body > div.newsflashes.clear > div.newsflashes_left > div.news_list > div:nth-child(3) > a')
for item in data3:
title3 = item.get_text()
for item in brief3:
sub_title3 = item.get_text()
for item in link3:
href3 = item.get('href')
news_jp = title1 + "\n" + sub_title1 + "\n" + "https://www.517japan.com" + href1 + "\n\n" + \
title2 + "\n" + sub_title2 + "\n" + "https://www.517japan.com" + href2 + "\n\n" + \
title3 + "\n" + sub_title3 + "\n" + "https://www.517japan.com" + href3 + '\n\n'
# 设置邮箱的域名
HOST = 'smtp.qq.com'
# 设置邮件标题
SUBJECT = '%s日份东京地区信息,请查收' % today_time
# 设置发件人邮箱
FROM = 'xxxxxxxxx@qq.com'
# 设置收件人邮箱
TO = 'xxxxxxxxxx@qq.com' # 可以同时发送到多个邮箱
message = MIMEMultipart('related')
# --------------------------------------发送文本-----------------
# 发送邮件正文到对方的邮箱中
message_html = MIMEText("%s%s" % (info, news_jp), 'plain', 'utf-8')
message.attach(message_html)
# 设置邮件发件人
message['From'] = FROM
# 设置邮件收件人
message['To'] = TO
# 设置邮件标题
message['Subject'] = SUBJECT
# 获取简单邮件传输协议的证书
email_client = smtplib.SMTP_SSL()
# 设置发件人邮箱的域名和端口,端口为465
email_client.connect(HOST, '465')
# ---------------------------邮箱授权码------------------------------
result = email_client.login(FROM, 'xxxxxxxxxx') # 授权码填写
print('登录结果', result)
email_client.sendmail(from_addr=FROM, to_addrs=TO.split(','), msg=message.as_string())
# 关闭邮件发送客户端
email_client.close()
顺带一提,有时候爬取速度过于频繁可能会被禁止访问,可以用以下代码来降低被检测概率,这里就贴一下代码,不做深入探讨,爬虫和反爬虫这个话题可以讲上一礼拜不停歇
sess = requests.sessions
sess.keep_alive = False
proxies = {
'http': 'http://117.95.192.106:9999',
}
user_agents = ['Mozilla/5.0 (Windows NT 6.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1',
'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50',
'Opera/9.80 (Windows NT 6.1; U; en) Presto/2.8.131 Version/11.11']
headers = {'User-Agent': random.choice(user_agents)}
本文地址:https://blog.csdn.net/qq_38184898/article/details/107083468