文章目录
- 写在前面
- 做的什么
- 一些tips
- 1.爬虫部分
- 2.微信机器人转发消息
- 2.1机器人需求以及实现过程
- 2.2向好友发送推送
- 2.2.1得到一个好友列表
- 2.2.2遍历好友列表推送消息
- 3.微信机器人代码
- 3.1结构
- 3.2主程序
- 3.3get_school()函数内部
- 3.4小补充,关于@bot.register()
- 2019/11/19补充
- 写在后面
写在前面
做的什么
1.爬取学院和教务处公告
- 使用requests库发起get请求获得目标HTML。
- 使用bs4用来解析HTML获取公告标题和链接。
2.开发微信机器人向好友和自己推送标题和链接
- 好友微信内自主订阅通知,以此获取到一个好友列表
- 遍历列表,向好友推消息
一些tips
微信机器人和QQ机器人开发类似,有对应的py库,但是今年早些时候腾讯停止了WebQQ服务。所以正规的QQ机器人就没法开发了,但是听说也有一些其它的渠道可以开发QQ机器人,不过既然官方都停止维护了,就没有再去深入了解。
所以就转向了微信机器人,有几点很头疼:
- 想搞个小号开发,但微信申请新的账号不像QQ那么容易
- 我申请完了发现小号登不上Web微信!查了一下好像说新申请的号一年内不让登陆
- 问了好多渣男有没有不用的微信小号而且能登陆网页微信的,没结果。我一想:有也不会给啊,人吃饭的工具啊。
折腾了一阵子最后还是用自己的号做开发,有点小烦。
建议先快速浏览一下wepy官方中文文档,对于这个库能做什么、该怎么做应该会有一个大概的认识。
大概了解后,后面开发的时候根据自己的需求对应地去找相应的API就好了。
下面是一个最简单地示例,向你昵称为“XX小舟”的好友发送’Hello WeChat!’。
from wxpy import *
# 初始化机器人,扫码登陆
bot = Bot()
my_friend = bot.friends().search('XX小舟', sex=MALE)[0]#返回的是一个列表,所以加上[0]
my_friend.send('Hello WeChat!')
1.爬虫部分
分出去写了,一是因为内容比较独立,二是加进来总体篇幅太长。
链接:py爬虫爬取学校通知公告
2.微信机器人转发消息
上面部分说到了如何判断通知是最新的。
用的方法是: 实时获取当天的年月日,与网站内通告的日期比对,相等则一定是最新消息,爬到一条后就把它的链接添加到一个“已抓取”列表中,再次抓取的时候先判断通知的链接是否在列表内,在则是当日已抓取信息;不在内则是当日新信息,到了第二天则清空“已抓取”列表。
2.1机器人需求以及实现过程
我的微信机器人要达到的目标很简单:就是给指定好友发送消息。所以其实很多功能都没用到,比如说对群聊的监控、自动拉人入群以及图灵机器人在线陪聊等等。
所以我的开发路线也很明确,根据对应想要的功能在前面给的官方文档中直接去找API。开发其它功能也是同样的思路,虽然说网上关于微信机器人开发的博客还挺多的,也包括我这篇。但是别人的博客也可能是对应实现某个功能,可能不是你自己想要的,这样去找、去看博客其实效率很低。遇到不确定的地方还是得去查官方文档。
2.2向好友发送推送
2.2.1得到一个好友列表
如果每次都是通过如下的方式去寻找好友再发消息出去,就很傻。
my_friend = bot.friends().search('XX小舟', sex=MALE)[0]
所以我搞了一个“订阅”:好友主动订阅通知,由此将好友分别加入两个通知的两个列表。大致效果如下
代码如下,其实可以简单的理解成一个自动回复的例子:
@bot.register(Friend, TEXT)# 规定响应好友发来的“TEXT”类型的msg
def service(msg):
print(msg.text)
if '通知' in msg.text:
msg.reply_msg("你想订阅哪些网站通知?\n 请回复标题,如:1,2或12\n1.机自学院通告\n2.教务处通告\n注:订阅成功后可回复TD取消订阅")
if '1' in msg.text:
if msg.sender in friends_school:
msg.reply_msg("您已经成功订阅机自学院通告,无需再次操作")
else:
friends_school.append(msg.sender)
msg.reply_msg("成功订阅机自学院通告")
if '2' in msg.text:
if msg.sender in friends_teaching:
msg.reply_msg("您已经成功订阅教务处通告,无需再次操作")
else:
friends_teaching.append(msg.sender)
msg.reply_msg("成功订阅教务处通告")
if "TD" in msg.text:
if msg.sender in friends_school and msg.sender in friends_teaching:
friends_school.remove(msg.sender)
friends_teaching.remove(msg.sender)
msg.reply_msg("成功退订学院、教务处通告")
elif msg.sender in friends_school:
friends_school.remove(msg.sender)
msg.reply_msg("成功退订学院通告")
elif msg.sender in friends_teaching:
friends_teaching.remove(msg.sender)
msg.reply_msg("成功退订教务处通告")
else:
msg.reply_msg("您还未订阅")
2.2.2遍历好友列表推送消息
如此就得到了两个列表friends_school和friends_teaching,分别存放了订阅两个网站通知的好友。发送消息时,遍历列表,向好友推送消息。
for eachFriend in friends_school:
eachFriend.send("学院有新通知,标题:“" + each_text + "”")
eachFriend.send("链接:" + real_href)
如果爬到新消息,就推送出去,效果如下
3.微信机器人代码
3.1结构
前面一些全局变量没有截图进来,占位置。
3.2主程序
因为涉及到爬虫,所以写了个while一直重复执行,每次循环最后sleep 5秒。
while 1:
# 获取当天时间,格式与网页内相同,Y-M-D
timeGet = time.strftime('%Y-%m-%d', time.localtime())
if timeGet == today:
pass
else:
# 如果到达明天,today重新赋值,并且清空“已爬取网页列表”
today = timeGet
exception = []
# print(today)
# 学院通告
get_school()# 爬取学院公告并发给好友
# 教务处通告
get_teaching()# 爬取教务处公告并发给好友
print("##########################")
print("已爬取名单:")
print(exception)# 已爬取的通知列表
print("学院名单:")
print(friends_school)
print("教务处名单:")
print(friends_teaching)
time.sleep(5)
3.3get_school()函数内部
get_teaching就不放了,两者几乎一样。
def get_school():
url = 'http://www.auto.shu.edu.cn/synr/tzgg.htm'
# 模拟浏览器发送HTTP请求
header = {'User-Agent': 'Mozilla/5.0'}
try:
response = requests.get(url, headers=header)
response.raise_for_status()
response.encoding = response.apparent_encoding
html = response.text
soup = BeautifulSoup(html, "html.parser")
except:
print("爬取失败了,朋友")
mail("报错", "爬虫失败了")#这个mail函数文中没讲,是给我自己发送邮件,参数为主题+正文
return
target = soup.find_all("span", string=today)
for eachOne in target:
# 得到链接和标题
each_text = eachOne.parent.parent.td.a.text
each_href = eachOne.parent.parent.td.a.get("href")
if each_href in exception:
pass
else:
# 没在“已爬取列表”内的话,发送链接、消息给好友
real_href = "http://www.auto.shu.edu.cn/" + each_href[3:]# 处理一下链接
print(real_href)
print(each_text)
# 给我自己发邮件通知
mail("学院有新通知", "标题:" + each_text + "\n链接:" + real_href)
for eachFriend in friends_school:
eachFriend.send("学院有新通知,标题:“" + each_text + "”")
eachFriend.send("链接:" + real_href)
# 加入“已爬取列表”
exception.append(each_href)
3.4小补充,关于@bot.register()
为了保持登陆,官方文档这么说的(截图):
因为我程序里写了while,所以就不需要堵塞线程,程序不会结束。但是突然一想,我的两个@bot.register()注册的函数都在while外面,能被执行到吗?
调试证明,这两个@bot.register()注册的函数都能被执行,所以我推断它的本质是回调函数。