上班的日子老是3点一线,家里,公司和上班的路径,对于一个特别懒得我来讲,常常遇到上班路上下雨了,而我却没带伞,多么痛的领悟。最近对python有一种狂热的学习热情,写了4年多的C++代码,对于python我不能说简单,可是他作东西确实太快了,现有的第三方资源真的炒鸡多,用的我也是不亦乐乎。除了上班忘记带伞,天天重复性的工做还有不少,好比上下班打卡、每一个礼拜的周报,还有若是有关心的女神,也能够作定时发送内心话,或者定时提醒等各类服务。有时候想若是有一我的能按时提醒我就行了,这种想法也就停留了那么几分钟就被本身pass掉了,由于别人也可能忘记啊。。。那么这件事是否是能够交给程序来作呢!毕竟程序但是会老老实实的作重复性的工做,并且他们乐此不疲。html
上述问题的场景大多都是须要程序在指定时间、或者指定场合提醒咱们该干什么了,本篇文章就定时天气提醒服务来作开篇,讲述使用Python怎么完成这样一个任务,既然这样,那咱们就开始构思咱们的程序吧python
看过背景中的需求描述,要实现这个功能,咱们须要解决如下这么几个问题:git
一、爬取天气信息,那么接下来就产生第二个问题了github
二、动态获取指定城市天气web
三、发送天气信息给指定微信好友数据库
四、定时触发爬取动做json
五、怎么关联微信帐号小程序
下面咱们将一步一步解决上述几个问题,并实现咱们的需求windows
解决问题1:浏览器
对于使用过爬虫的同窗来讲,爬取天气信息并不难,以前也了解过一些爬取web信息的代码,简单的爬虫无非就是那么几步
一、肯定爬取的url,使用浏览器打开
二、F12查看网页布局信息
三、使用xpath或者bs4进行节点定位
四、拿到页面信息
五、本身拼接爬取到的信息
六、写文件、写数据库、发送网络等等
这里贴下我以前写的几个简单爬虫:
三、python爬虫Scrapy(一)-我爬了boss数据,这个应该还有个下篇,后面待续
下面是爬取城市天气的python方法,须要注意一点的是getWeath接口的参数city_code,这是一个全国城市编码,每一个城市都是惟一的,这个表格我已经整理成了一个txt文档,后续放源码的时候会一并提供。
1 headers = { 2 "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36", 3 } 4 5 def getWeath(city_code): 6 try: 7 url = f'http://www.weather.com.cn/weather/{city_code}.shtml' 8 resp = requests.get(url, headers = headers) 9 except BaseException as e: 10 print(e) 11 return {} 12 13 resp.encoding = 'utf-8' 14 soup = BeautifulSoup(resp.text, 'html.parser') 15 tagToday = soup.find('p', class_ = "tem") #第一个包含class="tem"的p标签即为存放今每天气数据的标签 16 try: 17 temperatureHigh = tagToday.span.string #有时候这个最高温度是不显示的,此时利用次日的最高温度代替。 18 except AttributeError: 19 temperatureHigh = tagToday.find_next('p', class_="tem").span.string #获取次日的最高温度代替 20 21 temperatureLow = tagToday.i.string #获取最低温度 22 weather = soup.find('p', class_ = "wea").string #获取天气 23 wind = soup.find('p', class_ = "win") #获取风力 24 clothes = soup.find('li', class_ = "li3 hot") #穿衣指数 25 26 return {'温度':f'{temperatureHigh}/{temperatureLow}' 27 , '天气':weather 28 , '风力':wind.i.string 29 , '穿衣':clothes.a.span.string + ',' + clothes.a.p.string}
上述方法能够获取一个城市的天气信息,并储存在一个字典中,咱们要发送给好友,还须要对其进行字符串处理,处理代码以下:
1 def strDic(dic): 2 str_weather = '' 3 for key in dic: 4 str_weather += key + ':' + dic[key] 5 str_weather += '\n' 6 return str_weather
全国城市编码以下图所示,每一个城市的编码都是一个9位的数字组成,获取天气信息时是经过指定该编码进行查询。
解决问题3:发送消息给好友
解决问题5:怎么关联微信帐号,使用wechat_sender库
咱们本身爬取到的天气信息怎么和微信能扯上关系呢,这个时候就要提到我以前写过的一篇文章微信聊天机器人-存储好友分享消息,没有看过的同窗能够快速浏览一遍,简单来讲就是登录一个web版本的微信帐号,在咱们的电脑上,作这么一个机器人使用了库wxpy,要想和这个机器人勾搭上,那咱们就须要请出咱们今天的重磅嘉宾wechat_sender,wechat_sender是基于wxpy和tornado 实现的一个能够将你的网站,爬虫,脚本等其余应用中各类消息(日志,报警,运行结果等)发送到微信的工具包,有了他咱们的消息就能够顺利的发送到咱们的饿微信帐户了。
交互流程
如上图所示,首先使用wxpy登录微信机器人,固然这个机器人使用的是咱们本身的微信帐号,这里须要特别注意一点,微信聊天机器人-存储好友分享消息这篇文章中讲述的机器人进入命令状态是使用的embed()方法,在这里咱们不能使用该接口了,咱们须要换成上述交互流程的很关键的一步,使用listen接口进行监听,这样咱们的web工具才能发送消息给机器人,建议仔细阅读一遍wechat_sender说明文档,内容很少
登录微信机器人
爬取到天气信息之后,使用wechat_sender中的Sender类直接发送消息给微信机器人,下属代码中尝试是用来多种发送消息的方式,代码中都有详细注释,可自行阅读
1 def sendWeatherMsg(receivers, msg): 2 try: 3 #receivers = [u'拉卡拉', u'证实给他看', u'李静'] 4 5 #receivers = u'李静,情绕指尖' 6 7 ''' 8 #发送给指定好友 若是好友不存在 则发送给文件夹传输助手 9 Sender(receivers = u'证实给他看').send(msg) 10 Sender(receivers = u'拉卡拉').send(msg) 11 Sender(receivers = u'李静').send(msg) 12 ''' 13 14 ''' ''' 15 #发送给指定接收的用户 16 #receivers = u'拉卡拉' 17 #接受者必须是监听对象的子集 18 sender = Sender(receivers = receivers, token = 'weather_report_123456789') 19 sender.send(msg)#若是没有指定receivers则发送给文件传输助手 20 21 22 ''' 23 receivers = u'李静,情绕指尖' 24 sender = Sender(receivers = receivers, token = 'weather_report_123456789') 25 26 #有时候好使 有时候很差使 27 sender.send_to('@wss', u'拉卡拉') #消息发送失败 会默认发送给receivers的第一个用户 Sender和Listen 28 #sender.send_to(msg, u'证实给他看') 29 ''' 30 31 #测试控制命令 32 ''' 33 receivers = u'拉卡拉' 34 sender = Sender(receivers = receivers, token = 'weather_report_123456789') 35 sender.send('@wss')#文若是没有指定receivers则发送给文件传输助手件传输助手 36 ''' 37 38 except BaseException as e: 39 print(e)
登录微信机器人微信聊天机器人-存储好友分享消息已经讲过,有不懂的同窗能够回头看下,下边代码中第12行很是关键,这一行就是用来监听外部程序发送消息的。
1 bot = Bot(cache_path = True) 2 3 receivers = [] 4 receivers.append(bot.file_helper) 5 receivers.append(bot.friends().search('拉卡拉')[0]) 6 receivers.append(ensure_one(bot.friends().search('李静', city='西安')))#有可能搜索出多个结果 7 receivers.append(bot.friends().search('证实给他看')[0]) 8 receivers.append(bot.friends().search('妈')[0]) 9 10 print(receivers) 11 12 listen(bot, receivers = receivers, token = 'weather_report_123456789') #关键一步
解决问题2,根据配置的城市名称动态获取城市编码,而后请求数据
因为没有接口能够直接获取城市编码,所以这里咱们本身封装了一个类来进行管理城市名称和城市编码,拉取城市天气时,只要输入城市名称,那么城市编码便可经过该类获取到,具体代码以下
1 import os 2 3 class City(object): 4 def __init__(self): 5 self.city = {} 6 7 def load(self, file): 8 if os.path.exists(file): 9 with open(file, 'r', encoding = 'utf-8') as f: 10 cityInfo = f.readline().strip('\n') 11 while cityInfo: 12 datas = cityInfo.split(':') 13 self.city[datas[0]] = datas[1] 14 cityInfo = f.readline().strip('\n') 15 16 def find_code(self, city_name):#根据城市名称,查找城市吧编码 17 if city_name in self.city: 18 return self.city[city_name] 19 return ''
解决问题4:定时发送任务
咱们的需求是每日定时拉取天气信息,并发送给指定好友,python有一个APScheduler库,支持定时任务,具体使用比较负责,我也没有仔细研究,这里咱们只是须要使用一个定时任务,其余不作介绍,有兴趣的同窗可自行研究。
在研究定时任务的过程当中,一直没有找到BackgroundScheduler类add_job时,回调函数怎么传递参数,所以这里我封装了一个类,让定时任务和任务回调处于一个域内,这样参数就能够放在类的成员变量未知,不须要传递了,哪位大神若是会次操做,能够评论区指出,很是感谢
1 class MyJob(object): 2 def __sendWeatherMsg(self): 3 for my_job in self.my_jobs: 4 code = city_code.find_code(my_job['city']) 5 wea = getWeath(code) 6 strWea = strDic(wea) 7 title = '{}天气预报:\n'.format(my_job['city']) 8 sendWeatherMsg(my_job['receivers'], title + strWea)#发送天气信息给文件助手 9 10 def addMyJobs(self, json_job): 11 self.my_jobs = json_job['items'] 12 scheduler = BackgroundScheduler() 13 scheduler.add_job(self.__sendWeatherMsg, trigger = 'cron', hour = json_job['hour'] 14 , minute = json_job['minute'], second = '5,10,15,20,25,30,35,40,45,50,55') 15 scheduler.start()
后期出现不一样类型任务时,咱们就须要在封装新的类。上述MyJob类有2个接口,一个是任务调度器回调接口,不须要咱们调用,另外一个是加载任务接口,这个任务参数是一个标准的json串,由任务触发时间和具体的任务列表组成,任务触发时间主要是给调度器使用,任务列表就是调度器触发时的回调函数须要执行的任务数量。
1 my_jobs = { 2 "id":"my_jobs", 3 "hour":"6, 17", 4 "minute":"30", 5 "items":[{ 6 "receivers":"文件传输助手,李静,拉卡拉", 7 "city":"昌平" 8 },{ 9 "receivers":"文件传输助手,李静,拉卡拉", 10 "city":"海淀" 11 }] 12 }
如上述任务json串来讲,咱们的任务id为my_jobs,在天天的6.30和17.30,咱们须要执行items列表所指出的任务,任务列表是一个列表,列表中存储的是具体任务,receivers表明任务执行完毕须要发送的好友,city是爬取的天气名称,测试效果以下图所示
因为任务调度器不是一个阻塞性的程序,若是咱们不在主线程进行阻塞程序,那么程序就会直接退出,若是阻塞了主线程,那么任务调度程序也将会被阻塞,所以这里在添加任务调度后,咱们开启了一个子线程,主要就是为了避免让主线程退出,这样作其实不合理,可是咱们这里仅仅是为了演示,在下篇文章中这些问题咱们在作进一步处理。
1 city_code = city_code.City() 2 city_code.load('city_code.txt') 3 4 if __name__ == "__main__": 5 try: 6 ''' ''' 7 my_job = MyJob() 8 my_job.addMyJobs(test_jobs) 9 10 f = lambda x : lambda y : x+y 11 t = Timer.Timer(f, 24 * 60 * 60)#建立线程 一天给本身发一条消息 12 t.setDaemon(True) 13 t.start() 14 t.join() #防止主主线程退出 15 16 #SendWeatherMsg(my_msg) 17 18 except ResponseError as e: 19 print(e.err_code, e.err_msg) # 查看错误号和错误消息
喜欢的同窗能够本身尝试完成下这个小程序,或者选择一个相似的场景进行处理,本篇文章中还有几个须要优化的地方,因为篇幅问题,咱们在下篇中进行讲解
一、定时任务作成windows服务,这样更优雅,随开机启动
二、发送消息给微信好友换成发送邮件给指定邮箱
须要所有代码的到csdn直接下载:Python-定时爬取指定城市天气(一)-发送给关心的微信好友
转载声明:本站文章无特别说明,皆为原创,版权全部,转载请注明:朝十晚八