您的位置:首页 > 编程语言 > Python开发

python3下为scrapy爬虫添加邮件提醒功能

2017-09-17 23:43 531 查看

python3下为scrapy爬虫添加邮件提醒功能

1. 前言。

1.1. 需求背景。

主要用于监控爬虫的运行状态。前面的文章已经实现了爬虫每天自动运行一次,所以在无人监控的情况下,需要知道爬虫每天的运行情况。

1.2. 实现功能。

爬虫启动时,发送邮件通知:启动时间。

爬虫结束时,发送邮件通知:结束时间,reason,统计数据。

2. 环境。

python 3.6.1

系统:win7

IDE:pycharm

安装过scrapy

3. 邮箱基础知识_以及邮箱设置。

3.1. SMTP协议

SMTP(Simple Mail Transfer Protocol)即简单邮件传输协议,它是一组用于由源地址到目的地址传送邮件的规则,由它来控制信件的中转方式。SMTP协议属于TCP/IP协议簇,它帮助每台计算机在发送或中转信件时找到下一个目的地。通过SMTP协议所指定的服务器,就可以把E-mail寄到收信人的服务器上了,整个过程只要几分钟。SMTP服务器则是遵循SMTP协议的发送邮件服务器,用来发送或中转发出的电子邮件。

简单来说:

第一,大多数的邮件发送服务器(比如163,QQ)都是使用SMTP协议来发送邮件的。

第二,邮件传送代理程序使用SMTP协议来发送电子邮件到接收者的邮件服务器。

第三,SMTP协议只能用来发送邮件,不能用来接收邮件。

第四,SMTP协议的默认TCP端口号是25 。

第五,SMTP协议的默认SSL端口号是465 。

3.2. 邮箱设置

当我们使用程序来发送邮件时,必须做到以下两点:

第一,将发信人邮箱的SMTP协议开启。如下图:





第二,拿到邮箱授权码。作为程序登录邮件服务器的凭证。如上图,点击“生成授权码”。会拿到一个授权码:rkasdfghjklrbhag, 特别注意:这个授权码一定要保管好,如果被别人盗走,滥用,结果你懂的。

点击“如何使用Foxmail等软件收发邮件”,查看如何使用外部程序收发邮件,如下:



此时我们拿到了SMTP服务器地址和SSL端口号: smtp.qq.com, 465

4. 实现代码。

4.1. 创建爬虫_并用pycharm导入。





4.2. 添加发信模块:emailSender。

# 添加文件 emailSender.py
import smtplib
import datetime
from email.mime.text import MIMEText

class emailSender(object):
def __init__(self):
self.smtp_host = "smtp.qq.com"      # 发送邮件的smtp服务器(从QQ邮箱中取得)
self.smtp_user = "566666520@qq.com" # 用于登录smtp服务器的用户名,也就是发送者的邮箱
self.smtp_pwd = "rkasdfghjklrbhag"  # 授权码,和用户名user一起,用于登录smtp, 非邮箱密码
self.smtp_port = 465                # smtp服务器SSL端口号,默认是465
self.sender = "566666520@qq.com"    # 发送方的邮箱

def sendEmail(self, toLst, subject, body):
'''
发送邮件
:param toLst: 收件人的邮箱列表["465482631@qq.com", "77789713@qq.com"]
:param subject: 邮件标题
:param body: 邮件内容
:return:
'''
message = MIMEText(body, 'plain', 'utf-8')  # 邮件内容,格式,编码
message['From'] = self.sender               # 发件人
message['To'] = ",".join(toLst)             # 收件人列表
message['Subject'] = subject                # 邮件标题
try:
smtpSSLClient = smtplib.SMTP_SSL(self.smtp_host, self.smtp_port)   # 实例化一个SMTP_SSL对象
loginRes = smtpSSLClient.login(self.smtp_user, self.smtp_pwd)      # 登录smtp服务器
print(f"登录结果:loginRes = {loginRes}")    # loginRes = (235, b'Authentication successful')
if loginRes and loginRes[0] == 235:
print(f"登录成功,code = {loginRes[0]}")
smtpSSLClient.sendmail(self.sender, toLst, message.as_string())
print(f"mail has been send successfully. message:{message.as_string()}")
else:
print(f"登陆失败,code = {loginRes[0]}")
except Exception as e:
print(f"发送失败,Exception: e={e}")


登录SMTP服务器返回的状态码说明:

# 查一下smtp协议:
# '*************************
# '* 邮件服务返回代码含义
# '* 500 格式错误,命令不可识别(此错误也包括命令行过长)
# '* 501 参数格式错误
# '* 502 命令不可实现
# '* 503 错误的命令序列
# '* 504 命令参数不可实现
# '* 211 系统状态或系统帮助响应
# '* 214 帮助信息
# '* 220  服务就绪
# '* 221  服务关闭传输信道
# '* 421  服务未就绪,关闭传输信道(当必须关闭时,此应答可以作为对任何命令的响应)
# '* 250 要求的邮件操作完成
# '* 251 用户非本地,将转发向
# '* 450 要求的邮件操作未完成,邮箱不可用(例如,邮箱忙)
# '* 550 要求的邮件操作未完成,邮箱不可用(例如,邮箱未找到,或不可访问)
# '* 451 放弃要求的操作;处理过程中出错
# '* 551 用户非本地,请尝试
# '* 452 系统存储不足,要求的操作未执行
# '* 552 过量的存储分配,要求的操作未执行
# '* 553 邮箱名不可用,要求的操作未执行(例如邮箱格式错误)
# '* 354 开始邮件输入,以.结束
# '* 554 操作失败
# '* 535 用户验证失败
# '* 235 用户验证成功
# '* 334 等待用户输入验证信息


4.3. 在爬虫启动/结束时调用发信模块emailSender发送邮件

# -*- coding: utf-8 -*-
import scrapy
import datetime
from baiduClawer.emailSender import emailSender  # 导入发信模块

class BaiduSpider(scrapy.Spider):
name = 'baidu'
allowed_domains = ['baidu.com']
start_urls = ['http://baidu.com/']

def start_requests(self):

emailSenderClient = emailSender()
toSendEmailLst = ['988888834@qq.com', '566666520@qq.com']
startTime = datetime.datetime.now()
subject = f"爬虫启动状态汇报:name = baidu, startTime = {startTime}"
body = f"细节:start successs! at:{startTime}"
emailSenderClient.sendEmail(t
be9a
oSendEmailLst, subject, body)  # 发送邮件

for eachUrl in self.start_urls:
yield scrapy.Request(
url = eachUrl,
meta={'dont_redirect':True},
callback=self.parse,
errback=self.error
)

def parse(self, response):
print(f"success response.url = {response.url}")

def closed(self, reason):  # 爬取结束的时候发送邮件
emailSenderClient = emailSender()
toSendEmailLst = ['988888834@qq.com', '566666520@qq.com']
finishTime = datetime.datetime.now()
subject = f"爬虫结束状态汇报:name = baidu, reason = {reason}, finishedTime = {finishTime}"
body = f"细节:reason = {reason}, successs! at:{finishTime}"
emailSenderClient.sendEmail(toSendEmailLst, subject, body)

def error(self, failure):
pass


4.4. 运行效果



4.5. 特别需要注意的小细节

一般情况下,如果爬虫发送的内容比较单一频繁,这样的邮件很容易被当成垃圾邮件,放入垃圾箱,这样明明已经发送了,但是收信方会认为没有收到。



所以需要将发件人加入到白名单中,制定这样的收信规则。



结果如下所示:



最后,将邮箱绑定在微信上,就能很方便的收到提醒了。

4.6. 最后提醒!!!

因为经常使用这个授权码,发同样的邮件,有时候,会被QQ邮件服务器认为存在账户的安全隐患,导致授权码无法使用(会提示登录失败)。所以如果出现收不到邮件的问题,一方面要检查爬虫的运行状态,另一方面需要检查邮箱的安全状态。

5. 为什么不使用scrapy自带的邮件发信功能?

5.1. 目前scrapy对python3的支持尚不完善



参考文章:

https://blog.scrapinghub.com/2016/02/04/python-3-support-with-scrapy-1-1rc1/

5.2. 尝试:使用scrapy的邮件发信功能

-*- coding: utf-8 -*-
from scrapy.mail import MailSender

smtphost = "smtp.qq.com"        # 发送邮件的服务器(此处用腾讯的)
mailfrom = "566666520@qq.com"   # 发送方邮箱
smtpuser = "988888834@qq.com"   # 发送方用户名
smtppass = "rkasdfghjklrbhag"   # 发送方,邮箱的授权码
smtpport = 25

body = u"Just test, my auto send firstly. 内容"         # 邮件的内容
subject = u"daily test for scrapy send email. 标题"     # 邮件的标题

# bodys = body.encode("utf-8")
# subjects = subject.encode("utf-8")

mailer = MailSender(smtphost=smtphost,
mailfrom=mailfrom,
smtpuser=smtpuser,
smtppass=smtppass,
smtpport=smtpport)

recievers = ["988888834@qq.com", "566666520@qq.com"]
sendRes = mailer.send(to=recievers, subject=subject, body=body)
print(sendRes)


测试结果显示,不管对subject,body进行何种加解码,都会提示编码错误,猜测这就是scrapy email尚未完善的地方

参考文章:

http://blog.csdn.net/peade/article/details/51327208

http://blog.csdn.net/you_are_my_dream/article/details/60868329

http://blog.csdn.net/sunhuaqiang1/article/details/70833199

http://help.163.com/09/1224/17/5RAJ4LMH00753VB8.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: