首页 > 编程语言 >Python网络编程之微信机器人

Python网络编程之微信机器人

时间:2023-01-21 14:23:10浏览次数:41  
标签:__ xml get Python text 编程 之微信 content 微信

系统设计

  • 用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',
    # 'cookie': 'z_pro_city=s_provice%3Dyunnan%26s_city%3Dkunming; userProvinceId=18; userCityId=420; userCountyId=0; userLocationId=1; ip_ck=5cKD5vj+j7QuMjUyMTI5LjE2NzQyMjg2MjI%3D; lv=1674228622; vn=1; Hm_lvt_ae5edc2bc4fc71370807f6187f0a2dd0=1674228622; _ga=GA1.3.1721602942.1674228623; _gid=GA1.3.490169458.1674228623; z_day=icnmo11564%3D1%26ixgo20%3D1; __bid_n=185cfd18f882e1701c4207; FPTOKEN=0HtavafnHo0SIXRSy/DEdWb5O9Z+no8ky+cOa4MR6ualW82sP0pHxADx5qOHsWc5YXcJbSnpnQt47kujwpzZu9brvCGjxpdG21dqoSDGC1Kae+r/GvRtErzbImy7meMlQzasw7QUbthwz4Ko1sBesZO3L1nHjXbtShxuUrlW7/A4ZavwMQBbTaV8hrUDPAKT4T0gzZCaxyIYPbMgoNbePFvEEQLgPgKyv/JhdhsuhV9B83aYYz0y7Xkg/8cbeW491juoF0ZKsdM6rv1jdLg/GZS4v8stw7D6WpR0n1VXEy0Fp3MBQyT4RfW2TrLbOl/THQtQ+JlO+6AOK0fTJ59Wnk0BbiGNk1s1roSu8dxFNQakYeTM7RnqNby4kypuXSllCBLkR2/Kx1PY0nFFqULeaJKFXBKhVtRtecv7fI6rcbMJk5WcPebsB//JyGcHkuoz|F8U9pDZiF1E+TgsgRohOOOf5U6XfDfGgqqdV4oCzlNw=|10|7c56052848fd4a7df09d57f618355576; _gat=1; questionnaire_pv=1674172822; Hm_lpvt_ae5edc2bc4fc71370807f6187f0a2dd0=1674229624',
    '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__)  # 实例化一个Flask app

@app.route('/message', methods=['GET', 'POST'])  # 路由
def chatme():  # 定义控制器函数gf
    if request.method == 'GET':  # GET请求
        data = request.args  # 获取GET请求的参数
        token = TOKEN  # 微信接口调用的token
        signature = data.get('signature', '')  # 微信接口调用的签名
        timestamp = data.get('timestamp', '')  # 微信接口相关时间戳参数
        nonce = data.get('nonce', '')  # 微信接口相关nonce参数
        echostr = data.get('echostr', '')  # 微信接口相关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]

        # 返回xml文件
        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>
            '''

运行效果

  • 关注测试公众号
  • 发送消息并收到回复

标签:__,xml,get,Python,text,编程,之微信,content,微信
From: https://www.cnblogs.com/z5onk0/p/17063762.html

相关文章

  • python赋值和拷贝
    赋值,值相同,内存地址相同–函数参数传递。浅拷贝,值相同,内存地址不同。拷贝第一层内存地址的引用。第一层元素为可变元素。拷贝过的引用会跟着发生变化。否则不发生变化import......
  • 读函数式编程思维笔记02_转变思维
    1. 命令式编程1.1. 按照“程序是一系列改变状态的命令”来建模的一种编程风格1.2. 传统的for循环1.2.1. 确立初始状态1.2.2. 每次迭代都执行循环体中的一系列命......
  • 【python】Matplotlib库学习笔记
    Matplotlib是python的绘图库。以下内容主要介绍Matplotlib的子库pyplot。pyplot是常用的2D绘图模块,包含一系列绘图相关函数。plot()函数plot()函数可以用来绘制......
  • 【ABAQUS 二次开发笔记】使用keyword 、python和matlab一起处理Odb数据
    用conversionshellelement(S4R单元)建模层合板,有6层ply,每个lamina(ply)有3个integrationpoint,共计18个integrationpoint。我想得到集合SET-Middle-elem中所有integrati......
  • 安装 python in Linux: Ubuntu at WSL on windows
      安装ubuntu20.04appstore安装ubuntu安装异常:https://thegeekpage.com/wslregisterdistribution-failed-with-error-0x8007019e/    安装python3.8.1......
  • CUDA C++编程
    核函数作用调用核函数的时候,代码会被N个CUDA线程执行N次。 修饰符__global__返回值函数名(){  ...执行代码} 调用函数名<<<BlockNumber,ThreadNumber>>>()......
  • Python入门之数据类型转换
    """数据类型转换运算符算数运算符增强运算符"""#1.数据类型转换#intfloatstrstr_usb=input("请输入美元:")#类型转换str-->intin......
  • Python入门之数据类型
    """核心数据类型"""#1.Nonea01="张无忌"#接触变量与数据的绑定关系a01=None#使用None占位sex=None流程图:   #2.整形int#十进制nu......
  • Python 永久换源
    Python永久换源pipconfigsetglobal.index-urlhttps://pypi.douban.com/simple源地址:#腾讯http://mirrors.tencentyun.com/pypi/simple#阿里https://mirrors......
  • 利用艾宾浩斯曲线生成单词背诵规划表——python
    利用艾宾浩斯遗忘曲线生成单词背诵计划表#以下代码根据需背诵list总数(listcount)、复习间隔天数(days)#来自动生成单词背诵规划表,包括背诵周期、某天应学习复习list。#......