如何给你的爬虫添加预警系统

1,016 阅读6分钟

之前皮爷的文章里面,讲述了怎样编写爬虫,怎样把爬虫通过Scrapyd部署到远端的服务器上,也讲了怎样通过SpringBoot来实现每天自动执行爬虫。

那么今天我们就来讲一个可以“保证生产环节”的操作,预警系统。

为啥要有预警

为啥要有预警系统?是因为你的爬虫的功能是爬取别人网页上面的信息。一旦别人的网页结果做了修改,或者域名发生变化。在爬虫每天自动执行的时代,就会对你的数据造成确实。因为别人的修改导致了你的爬虫失效。这个时候就要预警系统进来参与。

预警系统有两个作用:

  1. 当爬虫爬取信息,如果某些信息需要及时通知工作人员,这可时候可以使用预警来通知相关人员。
  2. 当爬虫爬取数据产生异常的时候,需要及时通知相关人员。

本文背景

这篇文章里面的项目和代码,均出自皮爷之前写的文章里面。比如之前的Scrapy爬虫,还有Spring Boot为基础写的的 PeekpaHub 项目。

下文会详细讲解两种情况。

第一种情况

当爬虫爬到你需要的数据的时候,要及时通知你。

这部分代码主要写在了爬虫里面。以下通过一个例子来给大家讲解一下。

背景知识:
皮爷曾经写爬虫爬取过日本气象局的地震网站:http://www.jma.go.jp/jp/quake/quake_local_index.html


网页里面是一张表格,里面列出了地震的情况。一般来说,一旦有地震发生,这个网站的更新速度是很快的。所以我写的爬虫通过每两分钟爬取这个网站,在一定延迟的基础上,获取最新的地震信息。

当每次爬虫爬取信息的时候,如果发现爬取的新数据里面,マグニチュード 或者 最大震度 超过一定数字的时候,这些数据就应该发送到我的邮箱里面。

做法很简单,这个操作步骤只需要在Scrapy的 pipelines.py 文件中的 process_item(self, item, spider) 函数中完成就可以。

因为 process_item 里面的调用时刻就是在爬虫爬取完信息之后,存入数据库之前的这个时刻。所以当数据传到这个方法的时候,我们可以在里面做判断处理,如果条件符合,就发送邮件。

代码部分截取如下:

def process_item(self, item, spider):    try:        if self.jpearth2.find_one({"jp_id": item['jp_id']}) is None:            if self.needToSendHigh(item):                self.sendEmail(item, True)            if self.needToSendLow(item):                self.sendEmail(item, False)            self.jpearth2.insert(dict(item))        else:            logging.info("items: " + item['jp_id'] + " has in jpearth2.")    except Exception as e:        logging.error("PIPLINE EXCEPTION: " + str(e))

其中,sendEmial() 方法就是Python 发送email。

    # pipeline.py    def sendEmail(self, item, heighOrLow):        subject = "INFO! INFO! 地震报告: " + item['jp_location'] + " -- 震级:" + item['jp_level'].strip()[1:] + " -- " + item[            'jp_title'].strip()        bodyhtml = '<html><body>' + \                   '<h1>日本实时地震报告: ' + \                   '地点:<a href="' + item['jp_url'] + '">' + item['jp_location'] + '</a>' + \                   '震级:<a href="' + item['jp_url'] + '">' + item['jp_level'] + '</a>' + \                   '</h1>' + \                   '<h3>位置:<img src="' + item['jp_location_image_url'] + '"/></h3>' + \                   '<h3>时间:<a href="' + item['jp_url'] + '">' + item['jp_title'] + '</a></h3>' + \                   '<h3>强度:<a href="' + item['jp_url'] + '">' + item['jp_max_level'] + '</a></h3>' + \                   '<p> 点击上面的任意链接即可跳转到『日本气象厅』网站查看详情 </p>' + \                   '</body></html>'        self.emailClient.sendEmail(self.toHighSendEmailLst, subject, bodyhtml)    # emailClient.py    def sendEmail(self, toLst, subject, body):        '''        发送邮件        :param toLst: 收件人的邮箱列表        :param subject: 邮件标题        :param body: 邮件内容        :return:        '''        logging.info("sendEmail")        message = MIMEText(body, 'html', '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服务器            # logging.info(f"登录结果:loginRes = {loginRes}")    # loginRes = (235, b'Authentication successful')            if loginRes and loginRes[0] == 235:                logging.info(f"登录成功,code = {loginRes[0]}")                smtpSSLClient.sendmail(self.sender, toLst, message.as_string())                logging.info(f"mail has been send successfully. message:{message.as_string()}")            else:                logging.info(f"登陆失败,code = {loginRes[0]}")        except Exception as e:            logging.info(f"发送失败,Exception: e={e}")

最后实际效果就是,如果一旦发生地震比较严重,我的邮箱里面就会收到一封服务器自动发送的邮件:

这部分的东西很简单,皮爷之前写过一个很详细的文章:

『【Python实战】Scrapy的高阶骚操作,带邮件功能的“种子吞噬器2.0”版本,更高更快更强!』 (https://www.jianshu.com/p/c360d12d8ddf)

接下来我们主要讲一下Spring Boot里面如何自动发邮件。

第二种情况

因为PeekpaHub是作为一个信息集合类网站展现的.

https://www.peekpa.tech/

所以,判断爬虫是否出错(比如目标网站域名变化导致爬取失败),可以写一个定时循环任务,来每天定时从数据库里面看是否有数据。如果发生异常,则向管理员发送警告邮件。

    @Scheduled(cron = "0 0 9,12,15,18 * * ? ")    public void dailyDataCheck() {        boolean hasData = databaseDao.checkHasData(TimeUtils.getInstance().getCurDayTime(), "fid7");        emailComponent.sendAlertMail("hasData: " + hasData);    }

上面的 Schedule 里面的周期是用的 cron 写的,意思是每天的9点,12点,15点和18点会自动调用函数。关于 Cron 的写法,大家可以去下面这个网站,里面可以根据大家自己的需求,自动生成相对应的局域,非常的方便。

在线Cron表达式生成器http://cron.qqe2.com/

在 Spring Boot 里面实现发送邮件,其实也很简单,只需要用 JavaMailSender 就可以。

@Componentpublic class EmailComponent {    @Value("${mail.fromMail.sender}")    private String sender;    @Value("${mail.fromMail.receiver}")    private String receiver;    @Autowired    private JavaMailSender javaMailSender;    public void sendAlertMail(String textMessage) {        SimpleMailMessage message = new SimpleMailMessage();        String curDayAndTime = TimeUtils.getInstance().getCurDayAndTime();        message.setFrom(sender);        message.setTo(receiver);        message.setSubject("DATA CHECK:: " + curDayAndTime + " PeekpaHub 数据测试结果");        message.setText(textMessage + "\nTime: " + curDayAndTime + "\nhttp://peekpa.tech/\n数据测试");        try {            javaMailSender.send(message);        } catch (Exception e) {            print(e);        }    }}

这里面需要在 application.properties 里面配置一些信息。

mail.fromMail.sender=发送邮件地址@126.commail.fromMail.receiver=接受邮件地址@126.comspring.mail.host=smtp.126.com //可以用qq,163,这里用的是126的spring.mail.username=发送邮件地址@126.comspring.mail.password=密码spring.mail.default-encoding=UTF-8spring.mail.properties.mail.smtp.auth=truespring.mail.properties.mail.smtp.starttls.enable=truespring.mail.properties.mail.smtp.starttls.required=true// 在阿里云上使用SMTP_SSL端口则是465spring.mail.properties.mail.smtp.socketFactory.port=465 spring.mail.properties.mail.smtp.socketFactory.class=javax.net.ssl.SSLSocketFactory

就这样,我们把代码部署到阿里云服务器上,然后每天都会准点调用函数,来检测数据库是否正常:


CLOSE

今天就先说到这里吧,其实有了这两个功能,我感觉程序的可用性会提高很多。你可以在手机上再安装一个接受警告邮件的客户端,打开App的推送,这样如果一旦服务器有什么问题,你就可以在第一时间在手机上接到通知。这个功能其实还可以扩展到其他应用上面,其实是个挺不错的idea。

因为文章都是涉及到服务器的,所以福利就要写在最前面
皮爷这里就有上千元的阿里云和腾讯云的优惠券给你使用(每一款优惠只要点击优惠链接,进入即可领取):

阿里云部分
【阿里云新人1888元云产品通用代金券】:
promotion.aliyun.com/ntms/yunpar…

【阿里云爆款云主机,2折优惠券】:
promotion.aliyun.com/ntms/act/qw…

【阿里云企业级服务器2折优惠券】:
promotion.aliyun.com/ntms/act/en…

腾讯云

【新客户无门槛领取总价值高达2775元代金券,每种代金券限量500张,先到先得】:
cloud.tencent.com/redirect.ph…

【腾讯云服务器、云数据库特惠,3折优惠券】:
cloud.tencent.com/redirect.ph…

如果你对文章中所写的东西有什么疑问或者不明白的地方,可以关注公众号『皮爷撸码』,加入到『皮克啪交流群』里来和这里面的大神一起讨论。