热爱技术
专注分享

【超详细】使用python3做一个爬虫,监控网站信息下篇(循环对比,发送邮件)

广告:有长期刷销量需求,需要的小伙伴可以私聊我,或者加群, 一单10元。点击查看详情

接上文:

https://www.xiaoweigod.com/code/1609.html

上文我们已经利用python3的urllib模块和BeautifulSoup模块实现了这几个页面的抓取和分析提取信息。接下来要做的就是对抓取的信息进行循环比较,能体现出更新提示。上文中我们也说了,这个程序分为:信息提取模块(从网页中提取有用信息)、对比模块、还有邮件模块。这么多模块如果要直接写在程序里,一旦需要循环调用,那代码量可以翻好几倍。这里我们开始使用python的函数。

函数可以看做一个黑箱子,有输入和输出。输入东西(传递参数),函数处理完毕之后输出(return),在需要的时候,直接调用函数处理即可,无需再写代码。比如上一篇文章里,最后实现的功能,就是输入url_list,输出抓取到的多个页面的需要的信息。

 

一、把上一篇文章的代码封装成函数

我们先把上一篇文章的代码封装成两个函数,第一个函数输入url,return出当前url需要提取的信息

#定义一个名为get_webInfo的函数,传入参数url
def get_webInfo(url):
    req = urllib.request.Request(url)
    rsp = urllib.request.urlopen(req)
    html = rsp.read().decode('utf8','ignore')
    html = BeautifulSoup(html,'html.parser')
    for link in html.find_all('a',limit=3):
        info_link = link.get('href')
        info_text = link.get_text(strip=True)
    #函数执行完后,return(输出)执行的结果
    return info_text+'\n'+url[:-50]+info_link+'\n'

另一个函数输入url_list,调用get_webInfo函数,return出所有url需要提取的信息:

def parseWeb(url_list):
    初始化result为一个列表
    result = []
    for url in url_list:
        #每循环一次,就调用get_webInfo,传入参数url,解析出结果,存入变量webInfo
        webInfo = get_webInfo(url)
        print(webInfo)
        #每循环一次,就将解析结果放入result列表中
        result.append(webInfo)
    函数执行结束后,return(输出) result
    return result

 

二、写一个循环对比函数

在上一步中,我们封装了2个函数,get_webInfo()parseWeb,其中parseWeb()中调用了函数get_webInfo(),相当于执行parseWeb()并传入参数url_list,就可以实现多个页面第一条信息的获取并解析。那么接下来我们可以开始对解析出来的结果进行循环对比了。再看一遍程序流程图:

从图中可以看到,程序开始运行的时候,会抓取一次页面。这里我们运用定义一个全局字典tmp,保存抓取的结果,并跟最新抓取的结果进行对比,写最外面的大循环,判断是否为第一次执行。

先定义(初始化)一个字典tmp作为存储中间内容,值为None (空),再定义一个函数check(),用于循环对比,写最外层的大循环:

#定义一个字典,包含一个空元素history
tmp = {'history':None}


定义一个比对函数check()

def check():     #判断字典内的元素history不为空     if (tmp['history']):         #把临时值给tmp字典内的history元素 用于循环比较         hisroty = tmp['history']         now = parseWeb(url_list)             ...比较过程...         #比较完成后把值覆盖传递         tmp [history] = now     else:         #如果tmp里的history元素为空则判定第一次运行         tmp['history'] = parseWeb(url_list)

这样就完成了一个基本的逻辑,可以对上一次对比和本次获取到的内容进行循环对比了。接下来我们要做的是,在tmp不为空(非第一次运行)的情况下,判断信息是否更新,当然,使用if判断就行了。

首先为了排除因为网络原因导致的数据错误(获取不到数据、数据获取缺失等情况),需要对前后次获取的列表的长度(列表内字符个数)进行判断,比如本次抓取10个页面的第一条信息,那么列表长度固定为10。以下为比较过程:

#大前提,history的列表长度等于now的列表长度
if len(history) == len(now):
    #定义一个空的变量 result
    result = ''
    #使用zip函数,对history和now函数按顺序进行对比
    for a,b in zip(history,now):
        if a == b:
            print('未发现更新!')
        else:
            print('发现更新')
            #等价于result=result+b 发现更新就在变量result内添加内容,不会覆盖
            result+=b
            
            ...发送邮件...
            
    #注意空格,上面for循环执行后才会执行下面的if判断
    #为防止误判,两次获取内容都为空也满足len(history)==len(now),对result进行非空判断
    if result != '':
        #输出结果
        print('更新内容如下:'+result)
else:
    print('数据错误!')

 

三、使用smtp发送邮件

pyhon3自带email和smtplib模块,可以使用smtp发送邮件。由于云服务器默认屏蔽25端口,这里就使用465端口来发送加密邮件。

这里我们定义一个发送邮件的函数 send_mail(),传入参数邮件标题(title)、邮件正文(article)、邮件接收人(receiver)。由于只需要发送文本内容,所以邮件模块比较简单:

#导入需要使用的模块
import smtplib
from email.header import Header
from email.mime.text import MIMEText


定义发送邮件的函数,传入title,article,receiver参数

def send_mail(title,article,receiver):     #定义邮件地址、账号密码等变量     host = 'smtp.mxhichina.com'     user = 'admin@xiaoweigod.com'     passwd = 'xxxxxxxxxx'     sender = user     coding = 'utf8'     #定义message变量,写邮件内容、邮件头     message = MIMEText (article,'plain',coding)     message ['From'] = Header(sender,coding)     message ['To'] = Header(receiver,coding)     message ['subject'] = Header(title,coding)          #错误处理     try:         #定义mail_client变量,开启SSL邮件,传入邮件服务器地址和端口         mail_client = smtplib.SMTP_SSL(host,465)         #连接smtp服务器         mail_client.connect(host)         #登录smtp服务器         mail_client.login(user,passwd)         #发送邮件         mail_client.sendmail(sender,receiver,message.as_string())         #发送完成关闭连接         mail_client.close()         print('邮件已成功发送给:'+receiver)     except:         #如果过程中抛出异常则提示用户         print('发送失败!')

我们弄好了发送邮件的函数,可以单独把邮件内容拎出来测试下,在函数前面加几个用户输入动作:

title = input(str('输入邮件标题:'))
article = input(str('输入邮件内容:'))
receiver = input(str('输入接收人:'))

在函数下方加入:

send_mail(title,article,receiver)

这几个变量会自动传入send_mail()函数中。 保存为send_mail.py,运行一下:

image.png

成功接收到邮件:

 image.png

四、整合成一个完整的程序并优化

最后我们把整个程序整合一下,拼成一个完整的爬虫程序。(只写架构和优化部分)

#coding=utf-8


author=xiaoweigod

import urllib.request from bs4 import BeautifulSoup import smtplib from email.header import Header from email.mime.text import MIMEText import time url_list=['  tmp = {'history':None} receiver = input(str('请输入邮件接收人:')) def get_webInfo(url)    #加入UA,防止被网站封    head = {}    head['User-Agent']='Mozilla/5.0 (Linux; Android 4.0.4; Galaxy Nexus Build/IMM76B) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.133 Mobile Safari/535.19'     req = urllib.request.Request(url,header=head)        ......         return info_text+'\n'+url[:-50]+info_link+'\n'      def parseWeb(url_list):     ......     return result def check():     ......     print('发现更新')     #美化输出的格式     result+='-----------------------------------------\n'     result+=b     result+='-----------------------------------------\n'     ......     print('更新内容如下:+result')     #将result传入article变量,作为邮件正文     send_mail('你关注的网站有更新',result,receiver)

无限循环

while True:     check()     print('\n休息30秒继续运行!')     time.sleep(30)     print('继续工作...')

运行效果如下:

image.png
image.png

赞(20) 打赏
未经允许不得转载:小伟博客 » 【超详细】使用python3做一个爬虫,监控网站信息下篇(循环对比,发送邮件)

评论 4

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
  1. #1

    url_list=[‘
    tmp = {‘history’:None}
    receiver = input(str(‘请输入邮件接收人:’))
    这是什么写法?

    哈哈5年前 (2019-09-23)回复
  2. #2

    博主tql,之前一直想写一个类似于这样爬教务处公告并发送邮件的程序,但一想想要想这么多逻辑写这么多行代码我就劝退了?

    冰茶5年前 (2020-03-25)回复
    • 慢慢写! 你可以的

      misery4年前 (2020-08-04)回复
  3. #3

    不错!!!不错老实说。你花了多少时间写这个呀,直到最终获得成品 。

    Joey4年前 (2020-09-15)回复

觉得文章有用就打赏一下文章作者

非常感谢你的打赏,我们将继续给力更多优质内容,让我们一起创建更加美好的网络世界!

支付宝扫一扫打赏

微信扫一扫打赏