一、概述

上一篇文章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":['1134024095@qq.com'],
"city":"昌平",
"time":"6.30,17.30"
},{
"receivers":['1134024095@qq.com'],
"city":"海淀",
"time":"6.30,17.30"
}]

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

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

![查询系统日志](https://www.cnblogs.com/images/cnblogs_com/swarmbees/1351403/t_look_log.png)

四、发送邮件

这里我们使用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.、邮件发送成功

![邮件发送成功](https://www.cnblogs.com/images/cnblogs_com/swarmbees/1351403/t_success.png)

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(['1134024095@qq.com','1024068757@qq.com'], "昌平", "6.30")

五、源代码

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

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

如果您觉得文章不错,不妨给个打赏,写作不易,感谢各位的支持。您的支持是我最大的动力,谢谢!!!

很重要--转载声明

  1. 本站文章无特别说明,皆为原创,版权所有,转载时请用链接的方式,给出原文出处。同时写上原作者:朝十晚八 or Twowords

  2. 如要转载,请原文转载,如在转载时修改本文,请事先告知,谢绝在转载时通过修改本文达到有利于转载者的目的。


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

  1. Python-定时爬取指定城市天气(一)-发送给关心的微信好友

    一.背景 上班的日子总是3点一线,家里,公司和上班的路径,对于一个特别懒得我来说,经常遇到上班路上下雨了,而我却没带伞,多么痛的领悟.最近对python有一种狂热的学习热情,写了4年多的C++代码,对 ...

  2. 爬虫-通过本地IP地址从中国天气网爬取当前城市天气情况

    1.问题描述 ​ 最近在做一个pyqt登录校园网的小项目,想在窗口的状态栏加上当天的天气情况,用爬虫可以很好的解决我的问题. 2.解决思路 ​ 考虑到所处位置的不同,需要先获取本地城市地址,然后作为中 ...

  3. [Python] 快速爬取当前城市所有租房网站房源及配置,一目了然

    Python爬取当前城市房源信息,以徐州为例代码效果图请看下方,其他部分请查看附件,一起学习,谢谢 # -*- coding: utf-8 -*- """ @Time : ...

  4. 利用Python爬虫爬取指定天猫店铺全店商品信息

    本编博客是关于爬取天猫店铺中指定店铺的所有商品基础信息的爬虫,爬虫运行只需要输入相应店铺的域名名称即可,信息将以csv表格的形式保存,可以单店爬取也可以增加一个循环进行同时爬取. 源码展示 首先还是完 ...

  5. python 定时爬取内容并发送报告到指定邮箱

    import requests import smtplib import schedule import time from bs4 import BeautifulSoup from email. ...

  6. 用Python定时爬取网站最新资源

    记录一下. 写做个网站,爬了另一个网站的内容来做自己网站的内容. 把脚本挂到服务器,每隔一个小时去爬一次资源,然后保存到一个HTML文件里. 用flask做web对接,当有请求的时候就返回那个HTML ...

  7. 一个简单的定向python爬虫爬取指定页面的jpg图片

    import requests as r import re resul=r.get("http://www.imooc.com/course/list") urlinfo=re. ...

  8. 使用Python爬虫爬取网络美女图片

    代码地址如下:http://www.demodashi.com/demo/13500.html 准备工作 安装python3.6 略 安装requests库(用于请求静态页面) pip install ...

  9. Python爬虫|爬取喜马拉雅音频

    "GOOD Python爬虫|爬取喜马拉雅音频 喜马拉雅是知名的专业的音频分享平台,用户规模突破4.8亿,汇集了有声小说,有声读物,儿童睡前故事,相声小品等数亿条音频,成为国内发展最快.规模 ...

随机推荐

  1. SQL基本语句的优化10个原则

    原则一:尽量避免在列上进行运算,这样会导致索引失效. 例如: ; 优化: SELECT * FROM table WHERE d >= '2011-01-01'; 原则二:使用JOIN时,应该用 ...

  2. 算法竞赛之递归——输出1-n的所有排列

    本文是博主原创文章,未经允许不得转载.我的csdn博客也同步发布了此文, 链接 https://blog.csdn.net/umbrellalalalala/article/details/79792 ...

  3. Java开源生鲜电商平台-用户表的设计(源码可下载)

    Java开源生鲜电商平台-用户表的设计(源码可下载) 说明:由于该系统属于B2B平台,不设计到B2C的架构. 角色分析:买家与卖家. 由于买家与卖家所填写的资料都不一样,需要建立两站表进行维护,比如: ...

  4. 利用分支限界法求解单源最短路(Dijkstra)问题

    分支限界法定义:采用Best fist search算法,并使用剪枝函数的算法称为分支界限法. 分支限界法解释:按Best first的原则,有选择的在其child中进行扩展,从而舍弃不含有最优解的分 ...

  5. Python_跟随目标主机IP变换

    ''' 为了防止黑客攻击或者负载均衡,会经常变换主机,这样同一个域名在不同时间可能会对应不同的IP地址,在这种情况下可以通过 socket模块的gethostbyname()函数来实时获取目标主机的I ...

  6. Java基础系列--桶排序

    原创作品,可以转载,但是请标注出处地址:http://www.cnblogs.com/V1haoge/p/9045967.html 1.算法简介 桶排序可以算是最简单快速的排序算法了,只是限定条件要多 ...

  7. Reflection的getCallerClass静态方法

    Reflection的getCallerClass的使用 博客分类: java基础   Reflection的getCallerClass的使用:可以得到调用者的类.这个方法是很好用的. 0 和小于0 ...

  8. BigDecimal.setScale 处理java小数点

    BigDecimal.setScale()方法用于格式化小数点setScale(1)表示保留一位小数,默认用四舍五入方式 setScale(1,BigDecimal.ROUND_DOWN)直接删除多余 ...

  9. java中判断文件及所在文件夹是否存在

    File file=new File(filePath);if (file.exists()) {}else { File fileParent =new File(file.getParent()) ...

  10. js判断浏览器是否支持flash的方法

    传统浏览器可以使用window.ActiveXObject检查浏览器是否启用相关的控件.检查浏览器是否启用flash控件,需要先检查浏览器是否支持ActiveXObject,可以使用typeof检查w ...