【2022.1.21】用Python搭建了一个机器人服务器,可以同微信服务器进行通信,效果是在微信公众号内发送消息,可以根据消息内容进行自动回复
系统设计
- 用Python实现了一个微信机器人,在微信公众号内发送消息,可以根据消息内容进行自动回复
- 搭建Flask服务器,接收微信服务器发送的消息,并做出回复
- 根据微信服务器发送过来的消息,调用爬虫随机爬取笑话大全网站上的任一则笑话,以及根据请求的城市爬取天气预报网站上的该城市的天气情况
- 在本地部署机器人服务器,使用小米球ngrok进行内网穿透,将其暴露在公网上,同微信服务器进行通信
小米球ngrok内网穿透

申请微信公众号
- 由于个人申请的微信公众号需要等待一周才能审核完,速度太慢,转而使用一个公开的测试用公众号,填写机器人服务器的url和token

笑话大全网站爬虫joke.py
import requests
from random import randint
from pyquery import PyQuery as pq
headers = {
'authority': 'xiaohua.zol.com.cn',
'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
'accept-language': 'zh-CN,zh;q=0.9',
'referer': 'https://xiaohua.zol.com.cn/lengxiaohua/80.html',
'sec-ch-ua': '"Not_A Brand";v="99", "Google Chrome";v="109", "Chromium";v="109"',
'sec-ch-ua-mobile': '?0',
'sec-ch-ua-platform': '"Windows"',
'sec-fetch-dest': 'document',
'sec-fetch-mode': 'navigate',
'sec-fetch-site': 'same-origin',
'sec-fetch-user': '?1',
'upgrade-insecure-requests': '1',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36',
}
def get_joke():
url = "https://xiaohua.zol.com.cn/lengxiaohua/%s.html" % str((randint(1, 80)))
print (url)
r = requests.get(url, headers=headers)
doc = pq(r.text)
joke_list = doc('div.main > ul')
jokes = []
for item in joke_list.children().items():
joke = item.find('.summary-text').text()
jokes.append(joke)
joke = jokes[randint(1, len(jokes))].strip()
return joke
if __name__ == "__main__":
get_joke()
天气预报网站爬虫weather.py
import requests
from lxml import etree
def get_weather(keyword):
url = 'https://www.tianqi.com/tianqi/search?keyword=' + keyword
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36'
}
response = requests.get(url,headers=headers)
tree = etree.HTML(response.text)
try:
city_name = tree.xpath('//dd[@class="name"]/h1/text()')[0]
except:
content = '没有该城市天气信息,请确认查询格式'
return content
week = tree.xpath('//dd[@class="week"]/text()')[0]
now = tree.xpath('//p[@class="now"]')[0].xpath('string(.)')
temp = tree.xpath('//dd[@class="weather"]/span')[0].xpath('string(.)')
shidu = tree.xpath('//dd[@class="shidu"]/b/text()')
kongqi = tree.xpath('//dd[@class="kongqi"]/h5/text()')[0]
pm = tree.xpath('//dd[@class="kongqi"]/h6/text()')[0]
content = "【{0}】{1}天气\n当前温度:{2}\n今日天气:{3}\n{4}\n{5}\n{6}".format(city_name, week.split('\u3000')[0], now, temp, '\n'.join(shidu),kongqi,pm)
return content
if __name__ == "__main__":
keyword = '昆明'
content = get_weather(keyword)
print(content)
flask服务器wechat_robot.py
- 需要写一个get方法进行校验,验证请求是否来自于微信服务器
- post方法中写业务逻辑,注意收到请求和回复请求都需要转换为特定的xml格式,并携带相应的用户信息以及消息
from config import TOKEN,XML_STR
from flask import Flask, request, make_response
import hashlib
import xml.etree.ElementTree as ET
from weather import get_weather
from joke import get_joke
app = Flask(__name__)
@app.route('/message', methods=['GET', 'POST'])
def chatme():
if request.method == 'GET':
data = request.args
token = TOKEN
signature = data.get('signature', '')
timestamp = data.get('timestamp', '')
nonce = data.get('nonce', '')
echostr = data.get('echostr', '')
s = [timestamp, nonce, token]
s = ''.join(s).encode("utf-8")
if hashlib.sha1(s).hexdigest() == signature:
return make_response(echostr)
else:
return make_response("signature validation error")
if request.method == 'POST':
xml_str = request.stream.read()
xml = ET.fromstring(xml_str)
toUserName = xml.find('ToUserName').text
fromUserName = xml.find('FromUserName').text
createTime = xml.find('CreateTime').text
msgType = xml.find('MsgType').text
if msgType != 'text':
reply = XML_STR % (
fromUserName,
toUserName,
createTime,
'text',
'Unknow Format, Please check out'
)
return reply
content = xml.find('Content').text
msgId = xml.find('MsgId').text
if u'笑话' in content:
content = get_joke()
elif content[-2:] == "天气":
keyword = content[:-2]
if len(keyword) < 2:
content = '请输入正确的城市名称'
return XML_STR % (fromUserName, toUserName, createTime, msgType, content)
content = get_weather(keyword)
else:
if type(content).__name__ == "unicode":
content = content[::-1]
content = content.encode('UTF-8')
elif type(content).__name__ == "str":
print(type(content).__name__)
content = content
content = content[::-1]
reply = XML_STR % (fromUserName, toUserName, createTime, msgType, content)
print (fromUserName, " | ", toUserName, " | ", createTime, " | ", msgType)
return reply
if __name__ == "__main__":
app.run(host='0.0.0.0', port=8080,debug=True)
配置文件config.py
- 包含微信公众号的token以及回复请求的xml格式
TOKEN = 'weixin'
XML_STR = '''
<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[%s]]></MsgType>
<Content><![CDATA[%s]]></Content>
</xml>
'''
运行效果
- 关注测试公众号

- 发送消息并收到回复

【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库