文章目录

  • 写在前面
  • 做的什么
  • 一些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.爬取学院和教务处公告

  1. 使用requests库发起get请求获得目标HTML。
  2. 使用bs4用来解析HTML获取公告标题和链接。

2.开发微信机器人向好友和自己推送标题和链接

  1. 好友微信内自主订阅通知,以此获取到一个好友列表
  2. 遍历列表,向好友推消息

一些tips

微信机器人和QQ机器人开发类似,有对应的py库,但是今年早些时候腾讯停止了WebQQ服务。所以正规的QQ机器人就没法开发了,但是听说也有一些其它的渠道可以开发QQ机器人,不过既然官方都停止维护了,就没有再去深入了解。
所以就转向了微信机器人,有几点很头疼:

  1. 想搞个小号开发,但微信申请新的账号不像QQ那么容易
  2. 我申请完了发现小号登不上Web微信!查了一下好像说新申请的号一年内不让登陆
  3. 问了好多渣男有没有不用的微信小号而且能登陆网页微信的,没结果。我一想:有也不会给啊,人吃饭的工具啊。

折腾了一阵子最后还是用自己的号做开发,有点小烦。
建议先快速浏览一下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]

所以我搞了一个“订阅”:好友主动订阅通知,由此将好友分别加入两个通知的两个列表。大致效果如下

java微信机器人通知_微信


代码如下,其实可以简单的理解成一个自动回复的例子:

@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)

如果爬到新消息,就推送出去,效果如下

java微信机器人通知_微信机器人_02

3.微信机器人代码

3.1结构

前面一些全局变量没有截图进来,占位置。

java微信机器人通知_wepy_03

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()

为了保持登陆,官方文档这么说的(截图):

java微信机器人通知_java微信机器人通知_04


因为我程序里写了while,所以就不需要堵塞线程,程序不会结束。但是突然一想,我的两个@bot.register()注册的函数都在while外面,能被执行到吗?

调试证明,这两个@bot.register()注册的函数都能被执行,所以我推断它的本质是回调函数。