当前位置:   article > 正文

python实现微信公众号自动定时推送天气、以及公众号聊天机器人(给心爱的人一点惊喜)_python向微信公众号推送消息

python向微信公众号推送消息

前言

一、项目展示

二、使用步骤

1.安装库

2.源代码

3.部署到服务器

总结



前言

配置需求:

1.一台服务器

2.一个域名(用于聊天机器人)

3.一个微信测试公众号

4.python环境(这里用到的版本是3.6.4)

5.爬虫所需的库:bs4、requests


一、项目展示

二、使用步骤

1.安装库

1.bs4、requests的安装

pip install -i http://pypi.douban.com/simple/ --trusted-host=pypi.douban.com/simple包名

2.注册微信公众测试号

微信公众平台 (qq.com)

3.获取测试号appid、appsecret、userid、templateId

2.源代码

1.config.json

  1. {
  2. "appId": "你自己的",
  3. "appsecret": "你自己的",
  4. "userId": [
  5. "你自己的","xxxx"
  6. ],
  7. "templateId": "你自己的"
  8. }

我这里使用的模板是:

{{date.DATA}} 现在位于:{{city.DATA}} 天气{{today_weather.DATA}},{{today_weather_str.DATA}} 今天的最低温度为{{today_min.DATA}},最高温度为{{today_max.DATA}},风力为{{today_wind.DATA}} tips: {{today_str.DATA}} 顺便给小琳播报一下{{tomorrow.DATA}}的天气:{{tomorrow_weather.DATA}},最低温度{{tomorrow_min.DATA}},最高温度{{tomorrow_max.DATA}},风力{{tomorrow_wind.DATA}} 每日一句情话:{{daily_love.DATA}} 每日一句英语 :{{note_ch.DATA}}{{note_en.DATA}} 每天都要元气满满哦~

2.wechat_sendmsg.py

参考文章:

(97条消息) python实现微信公众号给你的重要用户推送消息_python向微信公众号推送消息_DreamAtDawn的博客-CSDN博客

(这里采用的是白天的天气   晚上获取会出现问题)

代码如下(示例): 

  1. from datetime import datetime
  2. from requests import get, post
  3. from time import localtime
  4. import json
  5. import os
  6. import random
  7. import sys
  8. import bs4
  9. import requests
  10. def get_weather():
  11. city_name = '张家界'
  12. headers = {
  13. 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
  14. 'Accept-Encoding': 'gzip, deflate',
  15. 'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
  16. 'Cache-Control': 'max-age=0',
  17. 'Connection': 'keep-alive',
  18. 'Cookie': 'HttpOnly; userNewsPort0=1; Hm_lvt_080dabacb001ad3dc8b9b9049b36d43b=1660634957; f_city=%E9%87%91%E5%8D%8E%7C101210901%7C; defaultCty=101210901; defaultCtyName=%u91D1%u534E; Hm_lpvt_080dabacb001ad3dc8b9b9049b36d43b=1660639816',
  19. 'Host': 'www.weather.com.cn',
  20. 'Referer': 'http://www.weather.com.cn/weather1d/101251101.shtml',
  21. 'Upgrade-Insecure-Requests': '1',
  22. 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.81 Safari/537.36 Edg/104.0.1293.54'
  23. }
  24. url = "http://www.weather.com.cn/weather/101251101.shtml"
  25. response = get(url=url, headers=headers)
  26. text = response.content.decode('utf-8')
  27. soup = bs4.BeautifulSoup(text, 'html.parser')
  28. # 存放日期
  29. list_day = []
  30. i = 0
  31. day_list = soup.find_all('h1')
  32. for each in day_list:
  33. if i <= 1: # 今明两天的数据
  34. list_day.append(each.text.strip())
  35. i += 1
  36. # 天气情况
  37. list_weather = []
  38. weather_list = soup.find_all('p', class_='wea') # 之前报错是因为写了class 改为class_就好了
  39. for i in weather_list:
  40. list_weather.append(i.text)
  41. list_weather = list_weather[0:2] # 只取今明两天
  42. # 存放当前温度,和明天的最高温度和最低温度
  43. tem_list = soup.find_all('p', class_='tem')
  44. i = 0
  45. list_tem = []
  46. for each in tem_list:
  47. if i >= 0 and i < 2:
  48. list_tem.append([each.span.text, each.i.text]) # 记录明天的最高温度和最低温度
  49. i += 1
  50. # 风力
  51. list_wind = []
  52. wind_list = soup.find_all('p', class_='win')
  53. for each in wind_list:
  54. list_wind.append(each.i.text.strip())
  55. list_wind = list_wind[0:2] # 同只取今明两天
  56. today_date = list_day[0]
  57. today_weather = list_weather[0]
  58. today_max = list_tem[0][0] + '℃'
  59. today_min = list_tem[0][1]
  60. today_wind = list_wind[0]
  61. tomorrow = list_day[1]
  62. tomorrow_weather = list_weather[1]
  63. tomorrow_max = list_tem[1][0] + '℃'
  64. tomorrow_min = list_tem[1][1]
  65. tomorrow_wind = list_wind[1]
  66. return city_name, today_date, today_weather, today_min, today_max, today_wind, tomorrow, tomorrow_weather, tomorrow_min, tomorrow_max, tomorrow_wind
  67. def get_daily_love():
  68. # 每日一句情话
  69. url = "https://api.lovelive.tools/api/SweetNothings/Serialization/Json"
  70. r = requests.get(url)
  71. all_dict = json.loads(r.text)
  72. sentence = all_dict['returnObj'][0]
  73. daily_love = sentence
  74. return daily_love
  75. def get_ciba():
  76. # 每日一句英语(来自爱词霸)
  77. url = "http://open.iciba.com/dsapi/"
  78. r = get(url)
  79. note_en = r.json()["content"]
  80. note_ch = r.json()["note"]
  81. return note_ch, note_en
  82. def get_color():
  83. # 往list中填喜欢的颜色即可
  84. color_list = ['#6495ED', '#3CB371']
  85. return random.choice(color_list)
  86. def get_config():
  87. with open("config.json", "r") as f:
  88. config = json.load(f)
  89. return config
  90. def get_token(config):
  91. url = "https://api.weixin.qq.com/cgi-bin/token"
  92. param = {
  93. "grant_type": "client_credential",
  94. "appid": config['appId'],
  95. "secret": config['appsecret']
  96. }
  97. response = requests.get(url=url, params=param)
  98. result = response.json().get("access_token")
  99. return result
  100. def send_message(to_user, access_token, city_name, today_date, today_weather, today_max, today_min, today_wind,
  101. tomorrow, tomorrow_weather, tomorrow_max, tomorrow_min, tomorrow_wind, daily_love, note_ch, note_en,
  102. today_weather_str, today_str):
  103. url = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token={}".format(access_token)
  104. week_list = ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"]
  105. year = localtime().tm_year
  106. month = localtime().tm_mon
  107. day = localtime().tm_mday
  108. today = datetime.date(datetime(year=year, month=month, day=day))
  109. week = week_list[today.isoweekday() % 7]
  110. print(today_max, today_min)
  111. for i in to_user:
  112. data = {
  113. "touser": i,
  114. "template_id": config["templateId"],
  115. "url": "http://www.baidu.com",
  116. "topcolor": "#FF0000",
  117. "data": {
  118. "date": {
  119. "value": "{} {}".format(today, week),
  120. "color": get_color()
  121. },
  122. "city": {
  123. "value": city_name,
  124. "color": get_color()
  125. },
  126. "today": {
  127. "value": today_date,
  128. "color": get_color()
  129. },
  130. "today_weather": {
  131. "value": today_weather,
  132. "color": get_color()
  133. },
  134. "today_max": {
  135. "value": today_max,
  136. "color": get_color()
  137. },
  138. "today_min": {
  139. "value": today_min,
  140. "color": get_color()
  141. },
  142. "today_wind": {
  143. "value": today_wind,
  144. "color": get_color()
  145. },
  146. "tomorrow": {
  147. "value": tomorrow,
  148. "color": get_color()
  149. },
  150. "tomorrow_weather": {
  151. "value": tomorrow_weather,
  152. "color": get_color()
  153. },
  154. "tomorrow_max": {
  155. "value": tomorrow_max,
  156. "color": get_color()
  157. },
  158. "tomorrow_min": {
  159. "value": tomorrow_min,
  160. "color": get_color()
  161. },
  162. "tomorrow_wind": {
  163. "value": tomorrow_wind,
  164. "color": get_color()
  165. },
  166. "daily_love": {
  167. "value": daily_love,
  168. "color": get_color()
  169. },
  170. "note_en": {
  171. "value": note_en,
  172. "color": get_color()
  173. },
  174. "note_ch": {
  175. "value": note_ch,
  176. "color": get_color()
  177. },
  178. "today_weather_str": {
  179. "value": today_weather_str,
  180. "color": get_color()
  181. },
  182. "today_str": {
  183. "value": today_str,
  184. "color": get_color()
  185. }
  186. }
  187. }
  188. headers = {
  189. 'Content-Type': 'application/json',
  190. 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) '
  191. 'AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36'
  192. }
  193. response = post(url, headers=headers, json=data).json()
  194. if response["errcode"] == 40037:
  195. print("推送消息失败,请检查模板id是否正确")
  196. elif response["errcode"] == 40036:
  197. print("推送消息失败,请检查模板id是否为空")
  198. elif response["errcode"] == 40003:
  199. print("推送消息失败,请检查微信号是否正确")
  200. elif response["errcode"] == 0:
  201. print("推送消息成功")
  202. else:
  203. print(response)
  204. if __name__ == "__main__":
  205. try:
  206. config = get_config()
  207. except FileNotFoundError:
  208. print("推送消息失败,请检查config.txt文件是否与程序位于同一路径")
  209. os.system("pause")
  210. sys.exit(1)
  211. except SyntaxError:
  212. print("推送消息失败,请检查配置文件格式是否正确")
  213. os.system("pause")
  214. sys.exit(1)
  215. # 获取accessToken
  216. accessToken = get_token(config)
  217. # 接收的用户
  218. users = config["userId"]
  219. # 传入省份和市获取天气信息
  220. city_name, today_date, today_weather, today_min, today_max, today_wind, tomorrow, tomorrow_weather, tomorrow_min, tomorrow_max, tomorrow_wind = get_weather()
  221. # 判断今天天气并返回对应响应
  222. # print(today_weather)
  223. today_weather_str = ""
  224. str_weather = ['雨', '云', '晴', '阴']
  225. # 提示可以多想几条 放入列表 random.choice([])
  226. today_weather_str_rain = ['今日可能有雨 记得带伞哦', '下雨天和巧克力更配哦~', '天街小雨润如酥 草色遥看近却无']
  227. today_weather_str_cloud = ['等风起,漫随天外云卷云舒', '今日有云 气候宜人', '应是天仙狂醉,乱把白云揉碎']
  228. today_weather_str_sun = ['快醒醒 太阳已经晒屁gu啦~', '今日天气晴 不止天气', '今天天气不错 多出门走走']
  229. today_weather_str_overcast = ['今日天气较阴 适宜懒人瘫在家里~', '阴天雨天暴雨天 爱你爱到发晒癫']
  230. for i in str_weather:
  231. if i in today_weather and i == '雨':
  232. today_weather_str = random.choice(today_weather_str_rain)
  233. break
  234. elif i in today_weather and i == '云':
  235. today_weather_str = random.choice(today_weather_str_cloud)
  236. break
  237. elif i in today_weather and i == '晴':
  238. today_weather_str = random.choice(today_weather_str_sun)
  239. break
  240. elif i in today_weather and i == '阴':
  241. today_weather_str = random.choice(today_weather_str_overcast)
  242. break
  243. else:
  244. today_weather_str = '啊哦 今天公众号有点不太聪明~ '
  245. # print(today_weather_str)
  246. # 判断今日温度并返回对应响应
  247. today_min_judge = today_min.split('℃')
  248. today_max_judge = today_max.split('℃')
  249. today_min_str = ''
  250. today_max_str = ''
  251. weather_min_str = ['今日温度较低 天冷记得加衣哦', '今日温度较低 要注意保暖哦']
  252. weather_max_str = ['今日温度较高 奖励自己一个冰淇淋降降温吧~', '今天好像比较热 记得防晒和消暑降温哦']
  253. weather_center_str = ['今日温度适宜 适合运动跳芭蕾~(doge)', '今日温度适宜 适合出去happy~']
  254. if int(today_min_judge[0]) < 10:
  255. today_str = random.choice(weather_min_str)
  256. elif int(today_max[0]) > 30:
  257. today_str = random.choice(weather_max_str)
  258. else:
  259. today_str = random.choice(weather_center_str)
  260. # print(today_str)
  261. # 获取每日情话
  262. daily_love = get_daily_love()
  263. # 获取每日一句英语
  264. note_ch, note_en = get_ciba()
  265. # 公众号推送消息
  266. # 传入提醒信息
  267. send_message(users, accessToken, city_name, today_date, today_weather, today_max, today_min, today_wind,
  268. tomorrow, tomorrow_weather, tomorrow_max, tomorrow_min, tomorrow_wind, daily_love, note_ch,
  269. note_en, today_weather_str, today_str)
  270. # 这里系统暂停乱码 需要将pycharm设置成与cmd相同的GBK编码 在setting file encode中
  271. os.system("pause")

3.部署到服务器

本地测试无误后相同的操作部署到服务器

1.服务器这里用到系统是centos7 依据自己的情况

安装python 安装所需库 然后将代码上传到服务器(finalshell直接复制粘贴)

2.服务器运行代码测试  python /x/x.py

3.linux定时任务 配置/etc/crontab

 这里是每天早上九点定时推送 根据个人情况修改

到这里公众号推送就已经完成了 

配置对话机器人

这里就会稍微有些麻烦  我就言简意赅一点

1.进入微信测试号 绑定接口配置url

        a.这里我使用的是django来处理微信回复消息

        b.服务器安装django  django-admin startproject xx 生成django项目

        c.绑定服务器必须是域名形式 不能是公网ip地址 (绑定时微信会通过get请求发送四个参数)参考文章:接入概述 | 微信开放文档 (qq.com)

      我这里是http://www.xxx.xxx/wechat_test/(你的django url地址)

    

        d.django中view.py的代码def wechat_test():(这里获取四个参数并指定加密方式来绑定微信url)

import hashlib
import json
import requests
import time
from django.shortcuts import render,HttpResponse
from xml.etree import ElementTree
  1. def wechat_test(request):
  2. if request.method == 'GET':
  3. token = 'misimnya'
  4. timestamp = request.GET.get('timestamp')
  5. nonce = request.GET.get('nonce')
  6. echostr = request.GET.get('echostr')
  7. signature = request.GET.get('signature')
  8. # 进行字典排序
  9. sort_list = [token, timestamp, nonce]
  10. sort_list.sort()
  11. result = hashlib.sha1((sort_list[0] + sort_list[1] + sort_list[2]).encode('utf-8')).hexdigest()
  12. # 判断参数是否相同
  13. if result == signature:
  14. return HttpResponse(echostr)
  15. else:
  16. return HttpResponse('error!')
  17. elif request.method == 'POST':
  18. return HttpResponse('no get')

       

e.启动服务 python manage.py runserver 去微信测试号绑定提交

token自定义 和代码参数一致就行

 f.绑定成功后你已经完成一大半了 接下来就是对收到的消息进行处理(收到的是xml格式的消息) 采用什么机器人回复(这里是用的是免费的思知机器人)

      进去官网注册:思知机器人 | 对话机器人 | 聊天机器人 | 知识图谱 - OwnThink

      你也可以用官方的  我这里用的是自己的机器人

      机器人管理登陆后创建自己的机器人  然后拿到机器人的appid

views源代码:

  1. import hashlib
  2. import json
  3. import requests
  4. import time
  5. from django.shortcuts import render,HttpResponse
  6. from xml.etree import ElementTree
  7. # Create your views here.
  8. class ParseXmlMsg(object):
  9. def __init__(self, xmlData):
  10. self.ToUserName = xmlData.find('ToUserName').text
  11. self.FromUserName = xmlData.find('FromUserName').text
  12. self.CreateTime = xmlData.find('CreateTime').text
  13. self.MsgType = xmlData.find('MsgType').text
  14. self.MsgId = xmlData.find('MsgId').text
  15. if self.MsgType == 'text':
  16. self.Content = xmlData.find('Content').text.encode('utf-8')
  17. elif self.MsgType == 'image':
  18. self.PicUrl = xmlData.find('PicUrl').text
  19. self.MediaId = xmlData.find('MediaId').text
  20. class TextMsg(object):
  21. def __init__(self, toUserName, fromUserName, content):
  22. # 私有对象,禁止外部访问
  23. self.__dict = dict()
  24. self.__dict['ToUserName'] = toUserName
  25. self.__dict['FromUserName'] = fromUserName
  26. self.__dict['CreateTime'] = int(time.time())
  27. self.__dict['Content'] = content
  28. def send(self):
  29. XmlForm = """
  30. <xml>
  31. <ToUserName><![CDATA[{ToUserName}]]></ToUserName>
  32. <FromUserName><![CDATA[{FromUserName}]]></FromUserName>
  33. <CreateTime>{CreateTime}</CreateTime>
  34. <MsgType><![CDATA[text]]></MsgType>
  35. <Content><![CDATA[{Content}]]></Content>
  36. </xml>
  37. """
  38. return XmlForm.format(**self.__dict)
  39. class ImageMsg(object):
  40. def __init__(self, toUserName, fromUserName, mediaId):
  41. self.__dict = dict()
  42. self.__dict['ToUserName'] = toUserName
  43. self.__dict['FromUserName'] = fromUserName
  44. self.__dict['CreateTime'] = int(time.time())
  45. self.__dict['MediaId'] = mediaId
  46. def send(self):
  47. XmlForm = """
  48. <xml>
  49. <ToUserName><![CDATA[{ToUserName}]]></ToUserName>
  50. <FromUserName><![CDATA[{FromUserName}]]></FromUserName>
  51. <CreateTime>{CreateTime}</CreateTime>
  52. <MsgType><![CDATA[image]]></MsgType>
  53. <Image>
  54. <MediaId><![CDATA[{MediaId}]]></MediaId>
  55. </Image>
  56. </xml>
  57. """
  58. return XmlForm.format(**self.__dict)
  59. def wechat_test(request):
  60. if request.method == 'GET':
  61. token = 'misimnya'
  62. timestamp = request.GET.get('timestamp')
  63. nonce = request.GET.get('nonce')
  64. echostr = request.GET.get('echostr')
  65. signature = request.GET.get('signature')
  66. # 进行字典排序
  67. sort_list = [token, timestamp, nonce]
  68. sort_list.sort()
  69. result = hashlib.sha1((sort_list[0] + sort_list[1] + sort_list[2]).encode('utf-8')).hexdigest()
  70. # 判断参数是否相同
  71. if result == signature:
  72. return HttpResponse(echostr)
  73. else:
  74. return HttpResponse('error!')
  75. elif request.method == 'POST':
  76. # 解析发送过来的body
  77. webData = request.body
  78. xmlData = ElementTree.fromstring(webData)
  79. recMsg = ParseXmlMsg(xmlData)
  80. if recMsg.MsgType == 'text':
  81. toUser = recMsg.FromUserName
  82. fromUser = recMsg.ToUserName
  83. # 获取用户发送过来的消息文本
  84. usercontent = recMsg.Content
  85. # 一定要传解码的消息文本 这里获取到的是 /x84形式的
  86. # print(usercontent.decode('utf-8'))
  87. # ownthink 返回json格式数据的对象
  88. # 自己的机器人id userid
  89. ownthink_reply = requests.get('https://api.ownthink.com/bot?appid=自己的机器人id&userid=自己的userid&spoken={}'.format(usercontent.decode('utf-8')))
  90. # text方法获取返回json数据
  91. content_json = ownthink_reply.text
  92. answer = json.loads(content_json)
  93. # print(answer)
  94. content = answer['data']['info']['text']
  95. # content = 'test'
  96. replyMsg = TextMsg(toUser, fromUser, content)
  97. return HttpResponse(content=replyMsg.send())
  98. elif recMsg.MsgType == 'image':
  99. print('暂时不做处理')
  100. return HttpResponse(content='success')
  101. def index(request):
  102. return render(request, "love_story.html")

         g.更改setting.py将app加入  将csrf这里注释(post请求会拦截报错)用户发送的信息就是post请求过来  

        h.总的一句话  就是配置url 指向views里面的处理函数 也可以不加入app  

        不懂的话可以搜索看看django教程

        最后就是关于django在服务器的后台挂起

参考文章:(97条消息) Centos下django项目的启动和停止(后台运行)_停止django项目_noob_python的博客-CSDN博客


 

总结

由于微信对公众号的整改   5.4日起微信公众号的颜色无了  不过问题不大哈哈

如果这篇文章对你有帮助的话 就点个赞 谢谢大家~

大佬轻喷~

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/70719
推荐阅读
相关标签
  

闽ICP备14008679号