Python-定时爬取指定城市天气(二)-邮件提醒

目录

  • 一、概述
  • 二、模块重新划分
  • 三、优化定时任务
  • 四、发送邮件
  • 五、源代码

一、概述

上一篇文章python-定时爬取指定城市天气(一)-发送给关心的微信好友中我们讲述了怎么定时爬取城市天气,并发送给指定微信好友,文末遗留两个问题

  • 定时任务做成windows服务,这样更优雅,随开机启动
  • 发送消息给微信好友换成发送邮件给指定邮箱

本篇文章我们在原来代码的基础上进行了一定的模块拆分,并处理以上两个问题

二、模块重新划分

1、 新增my_job.py文件,把任务模块单独划分出来

之前的定时任务使用的是apscheduler库做的,并且任务类在main函数所在py文件中,这样导致主py文件很难进行修改

2、 新增util.py文件

包含公用的方法,比如目前的字典转字符串

3.、新增weather_service.py文件

主要负责构造windows服务,也是一个主py文件,不同于第一篇文章的主py文件weath_report.py,这是我们实现的两种定时任务,可分别运行,如果想把天气信息通知微信好友则启动weath_report.py,可参考文章ython-定时爬取指定城市天气(一)-发送给关心的微信好友,如果是通过发送邮件的方式则直接把weather_service.py安装成windows服务,并启动即可,记住需要配置运行的任务列表,下边会讲述怎么配置任务

4、 新增timing_task.py文件

包含任务方法executeJob(),主要是在服务中循环跑,然后在合适的时间爬取天气并发送到指定邮箱,任务的参数是通过配置json串来实现

三、优化定时任务

本篇文章的定时任务是运行在windows服务中的,因此我们首先需要安装pywin32模块

1.、安装pywin32

pip install pywin32

2.、服务操作相关命令

1.安装服务 python PythonService.py install
2.让服务自动启动 python PythonService.py --startup auto install
3.启动服务 python PythonService.py start
4.重启服务 python PythonService.py restart
5.停止服务 python PythonService.py stop
6.删除/卸载服务 python PythonService.py remove

3.、启动服务时被拒绝

Installing service timingTaskDaemon
Error installing service: 拒绝访问。 (5)

a.大多数原因是由于python环境配置的问题,python默认安装时配置的pah是用户环境变量,这里我们需要改成系统环境变量,具体可以参考Python 写windows service 及 start service 出现错误 1053:服务没有及时响应启动或控制请求
b.考虑命令行是否有权限,我自己的win8系统默认权限就不够,需要右键管理员启动才可以

4、 实现windows服务功能,我们需要继承win32serviceutil.ServiceFramework这个类,把需要执行的业务逻辑放入SvcDoRun函数中,如下代码中executeJob()函数即为我们定时执行的任务

class WeatherPythonService(win32serviceutil.ServiceFramework):
    _svc_name_ = "weather_service_test4"
    _svc_display_name_ = "weather_service_test4"
    _svc_description_ = "i am a test weather_service_test"
    def __init__(self, args):
        win32serviceutil.ServiceFramework.__init__(self, args)
        # Create an event which we will use to wait on.
        # The "service stop" request will set this event.
        self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
        self.run = True
    def SvcStop(self):
        # Before we do anything, tell the SCM we are starting the stop process.
        self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
        # And set my event.
        win32event.SetEvent(self.hWaitStop)
        self.run = False
    def SvcDoRun(self):
        #what to do#
        while self.run:
            executeJob()
            time.sleep(5)
        #win32event.WaitForSingleObject(self.hWaitStop, win32event.INFINITE)
if __name__ == '__main__':
    #executeJob()
    win32serviceutil.HandleCommandLine(WeatherPythonService)

5.、任务执行函数

def executeJob():
    now_time = time.localtime(time.time())
    now_hour = now_time.tm_hour
    now_minute = now_time.tm_min
    for job in my_jobs:
        ts = job['time']
        for t in ts.split(','):
            jobtime = t.split('.')
            h = jobtime[0]
            m = jobtime[1]
            if (now_hour != h and now_minute != m):
                code = city_code.find_code(job['city'])
                wea = getWeath(code)
                strWea = strDic(wea)
                title = '{}天气预报'.format(job['city'])
                send_email(job['receivers'], 'title', title + ":\n" + strWea)

任务执行时,需要配置任务执行列表,即上述代码中my_jobs对象,该对象是一个标准的json串,不同于上一篇文章的json格式,本篇文章的任务参数如下,任务整体是一个数组,数组中包含了任务对象,每一个对象由3个字段组成,分别是邮件接收者邮箱receivers、爬取城市city和爬取时间time

my_jobs = [{
    "receivers":['[email protected]'],
    "city":"昌平",
    "time":"6.30,17.30"
    },{
    "receivers":['[email protected]'],
    "city":"海淀",
    "time":"6.30,17.30"
    }]

6.、安装服务,成功启动后,但是任务没有正常执行,可以通过查看系统任务事件来确定错误的原因,如下图所示,这是我在排查错误的时候截图

查询系统日志:win+r 回车输入 eventvwr.exe 在回车

四、发送邮件

这里我们使用QQ邮箱作为示例进行演示,发送邮件使用smtplib库

1.、QQ邮箱发送需要申请口令,申请方式

2、 选择邮箱发送服务器smtp.qq.com和端口号465

3.、构造发件人、收件人和邮件内容

message = MIMEText(text, 'plain', 'utf-8')
message['From'] = formataddr(["就差一点儿", sender])  # 括号里的对应发件人邮箱昵称、发件人邮箱账号
message['To'] = Header(','.join(receivers), 'utf-8')#接受者
message['Subject'] = Header(title, 'utf-8')

text为邮件内容,通过From构造发件人信息,To构造收件人信息,这个构造的只是显示的文本串,如本小节底部截图所示的收件人和发件人等,真正的接受邮件的账号在发送邮件时指定。

4.、连接邮箱服务器、登陆

smtpObj = smtplib.SMTP_SSL()
smtpObj.connect(mail_host, mail_port)    # mail_port 为 SMTP 端口号
smtpObj.login(mail_user, mail_pass)  

5、 发送邮件

smtpObj.sendmail(sender, receivers, message.as_string())

6.、邮件发送成功

7、 完整发送邮件代码

# 三个参数:第一个为文本内容,第二个 plain 设置文本格式,第三个 utf-8 设置编码
def send_email(receivers, title, text):
    message = MIMEText(text, 'plain', 'utf-8')
    message['From'] = formataddr(["就差一点儿", sender])  # 括号里的对应发件人邮箱昵称、发件人邮箱账号
    message['To'] = Header(','.join(receivers), 'utf-8')#接受者

    message['Subject'] = Header(title, 'utf-8')

    ret = True
    try:
        smtpObj = smtplib.SMTP_SSL()
        smtpObj.connect(mail_host, mail_port)    # mail_port 为 SMTP 端口号
        smtpObj.login(mail_user, mail_pass)
        smtpObj.sendmail(sender, receivers, message.as_string())
    except smtplib.SMTPException:
        ret = False

    f = open('./sendemail_weather.log', 'a', encoding = 'utf-8')
    if ret:
        f.write(datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') + ':邮件发送成功\n')
    else:
        f.write(datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') +':无法发送邮件\n')
    f.close()

8、测试发送邮件

send_email(['[email protected]','[email protected]'], "昌平", "6.30")

五、源代码

以前写博客测试程序都是放在csdn,最近几次发现csdn审核流程太慢了,导致和博客发布时间不统一,因此后续测试程序代码我都尽量放在git上,本篇文章的测试程序有需要的朋友可以去weather_report_service下载

本篇文章是使用markdown语法写的,排版实在不怎么样,大家凑合看吧,博客园的markdown解释器没有简书好,简书地址Python-定时爬取指定城市天气(二) - 邮件提醒



转载声明:本站文章无特别说明,皆为原创,版权所有,转载请注明:朝十晚八 or Twowords



Python-定时爬取指定城市天气(二)-邮件提醒

原文地址:https://www.cnblogs.com/swarmbees/p/10035127.html

时间: 11-28

Python-定时爬取指定城市天气(二)-邮件提醒的相关文章

Python爬取全国历史天气数据

1.通过爬取历史首页,来获取城市地址和历史时间,构建链接: ''' 获取全国的城市名称和链接 ''' import requests from lxml import etree import random import pymongo from time_list import get_time client = pymongo.MongoClient('localhost',27017) tianqi_data = client['tianqi_data'] time_url_table =

python爬虫爬取csdn博客专家所有博客内容

python爬虫爬取csdn博客专家所有博客内容: 全部过程采取自动识别与抓取,抓取结果是将一个博主的所有 文章存放在以其名字命名的文件内,代码如下 结果如下: 版权声明:本文为博主原创文章,未经博主允许不得转载.

【Python】爬取IMDBTOP250

在网上看到有人利用python+beautifulsoup爬取豆瓣Top250 试着自己模仿这个做了个爬取IMDB的, 可惜只能爬取到11个. 后来检查了超久, 才发现, soup=BeautifulSoup(contents)这里,内容不完整,只能到11个电影为止. 代码如下: import urllib2 from bs4 import BeautifulSoup mylist=[] def crawl(url): headers={'User-Agent':'Mozilla/5.0(Win

Python爬虫爬取知乎小结

博客首发至Marcovaldo's blog (http://marcovaldong.github.io/) 最近学习了一点网络爬虫,并实现了使用python来爬取知乎的一些功能,这里做一个小的总结.网络爬虫是指通过一定的规则自动的从网上抓取一些信息的程序或脚本.我们知道机器学习和数据挖掘等都是从大量的数据出发,找到一些有价值有规律的东西,而爬虫则可以帮助我们解决获取数据难的问题,因此网络爬虫是我们应该掌握的一个技巧. python有很多开源工具包供我们使用,我这里使用了requests.Be

python实现爬取千万淘宝商品的方法_python_脚本之家

分享到 一键分享 QQ空间 新浪微博 百度云收藏 人人网 腾讯微博 百度相册 开心网 腾讯朋友 百度贴吧 豆瓣网 搜狐微博 百度新首页 QQ好友 和讯微博 更多... 百度分享 python实现爬取千万淘宝商品的方法 作者:mingaixin 字体:[增加 减小] 类型:转载 这篇文章主要介绍了python实现爬取千万淘宝商品的方法,涉及Python页面抓取的相关技巧,需要的朋友可以参考下 本文实例讲述了python实现爬取千万淘宝商品的方法.分享给大家供大家参考.具体实现方法如下: ? 1 2

python爬虫爬取美女图片

python 爬虫爬取美女图片 #coding=utf-8 import urllib import re import os import time import threading def getHtml(url): page = urllib.urlopen(url) html = page.read() return html def getImgUrl(html,src): srcre = re.compile(src) srclist = re.findall(srcre,html)

python爬虫爬取页面源码在本页面展示

python爬虫在爬取网页内容时,需要将内容连同内容格式一同爬取过来,然后在自己的web页面中显示,自己的web页面为django框架 首先定义一个变量html,变量值为一段HTML代码 >>> print(html) <div id=1>   my <br>   name <br> is   JAY <br> </div> ,我们现在要取div里面的内容,在自己的web页面中显示,空格和换行符等都以HTML代码的形式抓取.最终

Python+requests 爬取网站遇到中文乱码怎么办?

分类: Python/Ruby 最近刚开始使用python来做爬虫爬取相关数据,使用了python自带的urllib和第三方库requests,解析html使用了beautifulsoup以及lxml     这里说下lxml,lxml是python的一个html.xml解析库,lxml使用XPath能快速,简单的定位元素并获取信息.下面进入正题 1. 遇到的中文乱码问题 1.1 简单的开始     使用requests来拔取网站内容十分方便,一个最简单的代码段只需要2-3行代码就行. 点击(此

python&amp;MongoDB爬取图书馆借阅记录(没有验证码)

题外话:这个爬虫本来是想用java完成然后发布在博客园里的,但是一直用java都失败了,最后看到别人用了python,然后自己就找别人问了问关键的知识点,发现连接那部分,python只用了19行!!!!!好了,其他的就不多说,直接上需求和代码 首先是需要爬取的链接和网页:http://211.81.31.34/uhtbin/cgisirsi/x/0/0/57/49?user_id=LIBSCI_ENGI&password=LIBSC 登陆进去之后进入我的账号——借阅.预约及申请记录——借阅历史就

python爬虫——爬取NUS-WIDE数据库图片

实验室需要NUS-WIDE数据库中的原图,数据集的地址为http://lms.comp.nus.edu.sg/research/NUS-WIDE.htm   由于这个数据只给了每个图片的URL,所以需要一个小爬虫程序来爬取这些图片.在图片的下载过程中建议使用VPN.由于一些URL已经失效,所以会下载一些无效的图片. 1 # PYTHON 2.7 Ubuntu 14.04 2 nuswide = "$NUS-WIDE-urls_ROOT" #the location of your nu