python每天自动爬取所需新冠肺炎疫情数据并发送到邮箱(无需selenium)
一、前言
这个寒假真是又长又无聊,我大概有两个星期没出门了。为了给自己找点事做,这两天弄了个爬虫玩玩,有不严谨的地方望大家指教。
二、项目简介
这次项目主要是想做一个爬虫,可以每天早上定时爬取当天的疫情数据,然后把数据发到我的邮箱里,让自己可以一大早醒来就实时了解到最新情况。为了简单起见,我只爬取湖北武汉,海南海口,江苏南京三个省市,一个是疫情主要战场,一个是我目前居住地,一个是我学校所在地。当然原理都是一样的,大家想爬取别的地方也可以。
三、原理
整个项目分成三个部分,第一部分是爬虫部分,第二部分是邮件部分,第三部分是云服务器部分,接下来我会一一介绍。
1、爬虫
这里我用到的库如下:
import urllib
from bs4 import BeautifulSoup
import json
urllib是用来获取网站源码的,bs4是用来解析html标签的,解析完后得到的是字符串,所以又用了json来转化成列表。
数据源我选用的是丁香园的,网站上相关数据显示的是这样:
我们来看看源码中的相关部分:
可以看到各个地区的数据被放在了id为“getAreaStat”的script标签里,通过findAll方法可以很容易定位到。
html = urllib.urlopen("https://ncov.dxy.cn/ncovh5/view/pneumonia?scene=2&clicktime=1579582238&enterid=1579582238&from=singlemessage&isappinstalled=0")
soup = BeautifulSoup(html.read())
block = soup.findAll("script",{"id":"getAreaStat"})
block0 = block[0]
blo_text = block0.get_text()
goal_text = blo_text[27:-11]
这里返回的block是bs4.element.ResultSet类型的,block0是bs4.element.Tag类型的,我们需要的是第二个(这里我对bs4的学习也还不够深入没法讲的太仔细)。然后再提取它的text部分即得到了一列字符串,这个字符串里是我们要的对于每一个省份数据的列表,但是头尾有一些我们不要的字符串,要把它掐掉,就可以得到goal_text。
然后用json将这个字符串转化成列表类型。
goal_list = json.loads(goal_text)
这个列表有34个元素,对应34个省直辖市特别行政区,每一个元素又是一个字典,包括某个省的名称、确诊人数、市等等,市的索引值又是一个列表,对应不同市,列表里面又是一个字典…
总之,理清它的数据结构我们就能通过遍历找到我们想要的省市数据。
for i in range(len(goal_list)):#这里用的是中文的unicode编码
if(goal_list[i]['provinceShortName']==u'\u6e56\u5317'):
hubei_num = i #湖北
if(goal_list[i]['provinceShortName']==u'\u6d77\u5357'):
hainan_num = i #海南
if(goal_list[i]['provinceShortName']==u'\u6c5f\u82cf'):
jiangsu_num = i #江苏
#三个省的确诊人数
hubei_confirmedCount = goal_list[hubei_num]['confirmedCount']
hainan_confirmedCount = goal_list[hainan_num]['confirmedCount']
jiangsu_confirmedCount = goal_list[jiangsu_num]['confirmedCount']
#武汉
for i in range(len(goal_list[hubei_num]['cities'])):
if(goal_list[hubei_num]['cities'][i]['cityName']==u'\u6b66\u6c49'):
wuhan_num = i
wuhan_confirmedCount = goal_list[hubei_num]['cities'][wuhan_num]['confirmedCount']
#海口
for i in range(len(goal_list[hainan_num]['cities'])):
if(goal_list[hainan_num]['cities'][i]['cityName']==u'\u6d77\u53e3'):
haikou_num = i
haikou_confirmedCount = goal_list[hainan_num]['cities'][haikou_num]['confirmedCount']
#南京
for i in range(len(goal_list[jiangsu_num]['cities'])):
if(goal_list[jiangsu_num]['cities'][i]['cityName']==u'\u5357\u4eac'):
nanjing_num = i
nanjing_confirmedCount = goal_list[jiangsu_num]['cities'][nanjing_num]['confirmedCount']
2、邮件
发邮件的代码比较套路了,这里就简单介绍一下。
用到的就两个库(smtplib,email),一个是负责传输协议,发送邮件,一个是用来编写邮件。
import smtplib
from email.mime.text import MIMEText
from email.header import Header
先编写邮件内容,这里邮件的内容我写的是html格式,为了好看一点。
message = MIMEText('<html><body><h1>今日疫情</h1>' +
'<p><b>湖北确诊人数:'+str(hubei_confirmedCount) + '</b>' +
'<br> 武汉确诊人数:'+str(wuhan_confirmedCount) + '</p>' +
'<p><b>海南确诊人数:'+str(hainan_confirmedCount) + '</b>' +
'<br> 海口确诊人数:'+str(haikou_confirmedCount) + '</p>' +
'<p><b>江苏确诊人数:'+str(jiangsu_confirmedCount) + '</b>' +
'<br> 南京确诊人数:'+str(nanjing_confirmedCount) + '</p>' +
'</body></html>','html','utf-8')
然后发送邮件四部曲。
server = smtplib.SMTP()
server.connect('smtp.qq.com',587) #smtp服务器和端口,端口是固定的
server.login(from_addr,'xxx') #第二个参数是邮箱授权码,需要自己去邮箱里找
server.sendmail(from_addr,to_addr,message.as_string()) #发送邮箱地址和接收邮箱地址都是我的地址
其他细枝末节的代码参见第四部分完整代码。
3、云服务器
为了让程序能每天准时自动运行,需要挂到云服务器上,这里我用的是阿里云的学生云服务器,价格便宜也够用。
定时运行程序步骤如下:
控制面板→系统和安全→管理工具→计划任务
→任务计划程序(本地)→任务计划程序库→创建任务
然后写任务名称,触发器条件和执行操作,就行了。其中执行操作可以参考我这么填:
四、完整代码
-*- coding: UTF-8 -*-
import urllib
from bs4 import BeautifulSoup
import json
import smtplib
from email.mime.text import MIMEText
from email.header import Header
html = urllib.urlopen("https://ncov.dxy.cn/ncovh5/view/pneumonia?scene=2&clicktime=1579582238&enterid=1579582238&from=singlemessage&isappinstalled=0")
soup = BeautifulSoup(html.read())
block = soup.findAll("script",{"id":"getAreaStat"})
block0 = block[0]
blo_text = block0.get_text()
goal_text = blo_text[27:-11]
#goal_list = eval(goal_text.decode())
goal_list = json.loads(goal_text)
for i in range(len(goal_list)): #这里用的是中文的unicode编码
if(goal_list[i]['provinceShortName']==u'\u6e56\u5317'):
hubei_num = i #湖北
if(goal_list[i]['provinceShortName']==u'\u6d77\u5357'):
hainan_num = i #海南
if(goal_list[i]['provinceShortName']==u'\u6c5f\u82cf'):
jiangsu_num = i #江苏
#三个省的确诊人数
hubei_confirmedCount = goal_list[hubei_num]['confirmedCount']
hainan_confirmedCount = goal_list[hainan_num]['confirmedCount']
jiangsu_confirmedCount = goal_list[jiangsu_num]['confirmedCount']
#武汉
for i in range(len(goal_list[hubei_num]['cities'])):
if(goal_list[hubei_num]['cities'][i]['cityName']==u'\u6b66\u6c49'):
wuhan_num = i
wuhan_confirmedCount = goal_list[hubei_num]['cities'][wuhan_num]['confirmedCount']
#海口
for i in range(len(goal_list[hainan_num]['cities'])):
if(goal_list[hainan_num]['cities'][i]['cityName']==u'\u6d77\u53e3'):
haikou_num = i
haikou_confirmedCount = goal_list[hainan_num]['cities'][haikou_num]['confirmedCount']
#南京
for i in range(len(goal_list[jiangsu_num]['cities'])):
if(goal_list[jiangsu_num]['cities'][i]['cityName']==u'\u5357\u4eac'):
nanjing_num = i
nanjing_confirmedCount = goal_list[jiangsu_num]['cities'][nanjing_num]['confirmedCount']
#################################################email
from_addr = 'aaa@qq.com'
to_addr = 'aaa@qq.com'
message = MIMEText('<html><body><h1>今日疫情</h1>' +
'<p><b>湖北确诊人数:'+str(hubei_confirmedCount) + '</b>' +
'<br> 武汉确诊人数:'+str(wuhan_confirmedCount) + '</p>' +
'<p><b>海南确诊人数:'+str(hainan_confirmedCount) + '</b>' +
'<br> 海口确诊人数:'+str(haikou_confirmedCount) + '</p>' +
'<p><b>江苏确诊人数:'+str(jiangsu_confirmedCount) + '</b>' +
'<br> 南京确诊人数:'+str(nanjing_confirmedCount) + '</p>' +
'</body></html>','html','utf-8')
message['From'] = Header(from_addr)
message['To'] = Header(to_addr)
message['Subject'] = Header(u'新冠肺炎疫情自动通报')
server = smtplib.SMTP()
server.connect('smtp.qq.com',587) #smtp服务器和端口,端口是固定的
server.login(from_addr,'xxx') #第二个参数是邮箱授权码,需要自己去邮箱里找
server.sendmail(from_addr,to_addr,message.as_string())
server.quit()
五、结果展示
上一篇: RAC—单机异地备份