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

接上文:

【超详细】使用python3做一个爬虫,监控网站信息(一)

上文我们已经利用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

评论

目前评论:0   

点击加载更多评