如何使用Python爬虫获取offcn上的公考信息及写入Excel表格并发送至指定邮箱

    技术2022-07-15  82

    如何使用Python爬虫获取offcn上的公考信息及写入Excel表格并发送至指定邮箱

    目录package的使用主要代码块Chromedriver块的解释爬虫代码块的解释

    目录

    又到了一年毕业季,应届毕业生们又该忙碌起来寻找各种工作了,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)}
    Processed: 0.009, SQL: 9