python每天自动爬取所需新冠肺炎疫情数据并发送到邮箱(无需selenium)

python每天自动爬取所需新冠肺炎疫情数据并发送到邮箱

一、前言

这个寒假真是又长又无聊,我大概有两个星期没出门了。为了给自己找点事做,这两天弄了个爬虫玩玩,有不严谨的地方望大家指教。

二、项目简介

这次项目主要是想做一个爬虫,可以每天早上定时爬取当天的疫情数据,然后把数据发到我的邮箱里,让自己可以一大早醒来就实时了解到最新情况。为了简单起见,我只爬取湖北武汉,海南海口,江苏南京三个省市,一个是疫情主要战场,一个是我目前居住地,一个是我学校所在地。当然原理都是一样的,大家想爬取别的地方也可以。

三、原理

整个项目分成三个部分,第一部分是爬虫部分,第二部分是邮件部分,第三部分是云服务器部分,接下来我会一一介绍。

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>&nbsp;&nbsp;&nbsp;&nbsp;武汉确诊人数:'+str(wuhan_confirmedCount) + '</p>' +
                   '<p><b>海南确诊人数:'+str(hainan_confirmedCount) + '</b>' +
                   '<br>&nbsp;&nbsp;&nbsp;&nbsp;海口确诊人数:'+str(haikou_confirmedCount) + '</p>' +
                   '<p><b>江苏确诊人数:'+str(jiangsu_confirmedCount) + '</b>' +
                   '<br>&nbsp;&nbsp;&nbsp;&nbsp;南京确诊人数:'+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 = '[email protected]'
to_addr = '[email protected]'

message = MIMEText('<html><body><h1>今日疫情</h1>' +
                   '<p><b>湖北确诊人数:'+str(hubei_confirmedCount) + '</b>' +
                   '<br>&nbsp;&nbsp;&nbsp;&nbsp;武汉确诊人数:'+str(wuhan_confirmedCount) + '</p>' +
                   '<p><b>海南确诊人数:'+str(hainan_confirmedCount) + '</b>' +
                   '<br>&nbsp;&nbsp;&nbsp;&nbsp;海口确诊人数:'+str(haikou_confirmedCount) + '</p>' +
                   '<p><b>江苏确诊人数:'+str(jiangsu_confirmedCount) + '</b>' +
                   '<br>&nbsp;&nbsp;&nbsp;&nbsp;南京确诊人数:'+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()


五、结果展示

在这里插入图片描述

发布了3 篇原创文章 · 获赞 8 · 访问量 806

猜你喜欢

转载自blog.csdn.net/qq_38679612/article/details/104264843