專 欄
❈
段晓晨, 写过一点爬虫,写过几篇文章。能力虽有限,会尽量把想说的东西讲清楚。
知乎ID:段小草
知乎专栏:小段同学的杂记,
https://zhuanlan.zhihu.com/666666
❈
—
—
通过这一系列的文章,我们来介绍一下如何用Python开发微信公众号的后台。
主要工具:SAE+微信公众号+Git+Python本地环境(最好已经安装好了Git并配置好了Python IDE,比如Pycharm)
1. 工欲善其事
首先要简单介绍一下一些准备工作。
1.1 微信公众号
第一步是要注册一个个人微信公众号(个人账号不支持认证),按照
https://mp.weixin.qq.com/
给出的过程依次填写需要的信息就可以完成申请,如果已有账号的话可以直接登录。
登录以后可以看到左边栏中的自动回复功能:
在一般的使用中,我们可以通过设置关键字实现一些基本的自动回复功能,但是这样的关键字回复远远不能满足我们的实际需求,比如我们要实现一个查快递的功能,必然是要通过调用快递接口对不同用户的不同输入给出不同的输出结果,在这样的情况下关键字回复就显得很鸡肋了。于是我们选择了开发者模式。
在基本配置中,我们只需要修改URL、Token和EncodingAESKey三项配置即可,由于我们现在还没有配好自己的服务器,微信公众号这边的设置到这里暂停,等我们有了服务器获取了地址以后回来填写就可以了。
1.2 SAE
这次我们使用新浪云作为我们的服务器,注册登录
https://www.sinacloud.com
,新用户会有一定的优惠云豆,老用户充个十块也足够我们完成很多学习任务了。
选择云应用,进入控制台后创建新应用。
输入二级域名和应用名称(必填项),在下面的运行环境中选择 Python2.7 - 空应用。
成功创建应用后,会获得相应的一些配置数据和密钥,当然这些内容这次用不到,主要用到的就是登陆账号和安全密码。
SAE平台的代码版本控制分为Git和SVN,两者可以自由选择,这次我们选择使用Git进行代码的上传操作。
1.3 Git
对于Windows系统,电脑上如果安装了 Github Desktop 的话,应该就自带了 Git Bash 和 Git Shell 这样的工具,如果之前没有安装过 Git 相关的软件,可以自行搜索 Git 以后安装 Git for Windows。
Git 刚接触时可能很复杂,用起来功能很强大但繁琐,初学者可能绕来绕去就绕晕了,但是在这次的搭建过程中我们其实只需要用到四五条极为简单的命令即可,所以完全无需担心 Git ,也不要让 Git 成为你拒绝迈出第一步的障碍。(关于 SAE 的代码管理,详见
https://www.sinacloud.com/doc/sae/tutorial/code-deploy.html#git
)
下面就让我们进入到真正的开发阶段吧!
2. 捅破窗户纸
犹记得我大一的时候公众号刚刚兴起,当时我还兴致冲冲地注册了账号,设置了一大堆的关键字自动回复,坚持了数天的图文消息推送,但是当我真正开始研究开发者模式,真正想去调用一些接口时却发现,好像自己该学的也都学了,该用的也都用过,就是串不到一起去,做不出想要的东西来(当时用的好像还是 PHP ),后面一直搁置了公众号这样的东西,一下子就拖到了现在。这两天试了一下 Python 服务器的配置,发现完全就是一层窗户纸,其实一捅就破,完全没有当初的纠结和复杂了。
2.1 服务器配置和 Token 认证
由于我们之前在 SAE 平台创建的是空应用,所以我们需要做一些基础的配置工作。这次我们选择使用 web.py (Python 2.7)来进行服务器搭建,如果本地没有 web.py 库的话可以通过 pip 命令进行安装(pip install web.py)。
之后我们需要创建一个项目,并编辑如下的基本代码。
1. `config.yaml`
2. `name: wxpytest`
3. `version: 1`
4.
5. `libraries:`
6. `- name: webpy`
7. `version: "0.36"`
8.
9. `- name: lxml`
10. `version: "2.3.4"`
11. `...`
12. `index.wsgi`
1. `# coding: UTF-8`
2. `importos`
3. `importsae`
4. `import web`
5.
6. `fromweixinInterface import WeixinInterface`
7.
8. `urls = (`
9. `'/weixin','WeixinInterface'`
10. `)`
11.
12. `app_root = os.path.dirname(__file__)`
13. `templates_root = os.path.join(app_root, 'templates')`
14. `render = web.template.render(templates_root)`
15.
16. `app = web.application(urls, globals()).wsgifunc()`
17. `application = sae.create_wsgi_app(app)`
这两部分是 web.py 的基础配置文件,之后我们需要开始编写实现微信公众平台功能的代码。
新建weixinInterface.py
1. `# -*- coding: utf-8 -*-`
2. `importhashlib`
3. `import web`
4. `importlxml`
5. `import time`
6. `importos`
7.
8.
9. `classWeixinInterface:`
10.
11. `def __init__(self):`
12. `self.app_root = os.path.dirname(__file__)`
13. `self.templates_root = os.path.join(self.app_root, 'templates')`
14. `self.render = web.template.render(self.templates_root)`
15.
16. `def GET(self):`
17. `#获取输入参数`
18. `data = web.input()`
19. `signature=data.signature`
20. `timestamp=data.timestamp`
21. `nonce=data.nonce`
22. `echostr = data.echostr`
23. `#自己的token`
24. `token="token" #这里改写你在微信公众平台里输入的token`
25. `#字典序排序`
26. `list=[token,timestamp,nonce]`
27. `list.sort()`
28. `sha1=hashlib.sha1()`
29. `map(sha1.update,list)`
30. `hashcode=sha1.hexdigest()`
31. `#sha1加密算法`
32.
33. `#如果是来自微信的请求,则回复echostr`
34. `ifhashcode == signature:`
35. `returnechostr`
编写好这三部分的代码后,我们就实现了最简单的微信平台认证配置,这三部分代码中需要修改的只有 token 字段,需要和你在微信平台中输入的 token 保持一致。(之后有机会再详细写具体的认证过程吧,这次只罗列一下实现过程,需要注意的是认证 token 我们只需要用 GET 方法而之后的发消息需要用 POST 方法。)
这时我们需要把代码上传到 SAE 平台,然后在微信平台进行认证请求。
在文件根目录右键打开 Git Bash,依次输入如下命令,过程中可能会需要输入 SAE 的用户名和安全密码,按照提示操作即可。
1. `gitinit`
2. `git remote add sae https://git.sinacloud.com/yourapp`
3. `git add .`
4. `git commit -m 'your commit message'`
5. `git push sae master:1`
之后回到公众平台的开发者页面,填写 URL 为 http://xxxx.sinaapp.com/weixin 填写 Token 与代码中的 token 一致,EncodingAESKey 随机生成,然后点击提交认证,如果上面步骤没有操作错误,这一步就可以认证成功了。
2.2 最简单的消息回复机制
在微信公众号的认证完成以后,就可以针对用户的消息搞一些事情了。(消息类型开发文档详见 https://mp.weixin.qq.com/wiki?t=resource/res\_main&id=mp1421140453&token=⟨=zh\_CN )
用户与公众号之间的消息交互类型分为文本、图片、语音、视频、小视频、地理位置、链接等,本文中主要会用到文本和图片两种消息类型。
用户消息以 XML形式传至我们搭建好的服务器中,我们需要解析 XML 信息,获取出需要的信息,进行处理后对用户回复结果。
我们先来简单看一下文本消息和图片消息的 XML 结构。
文本:
1. `<xml>`
2. `<ToUserName><![CDATA[toUser]]></ToUserName>`
3. `<FromUserName><![CDATA[fromUser]]></FromUserName>`
4. `<CreateTime>1348831860</CreateTime>`
5. `<MsgType><![CDATA[text]]></MsgType>`
6. `<Content><![CDATA[this is a test]]></Content>`
7. `<MsgId>1234567890123456</MsgId>`
8. `</xml>`
9. `图片:`
10. `<xml>`
11. `<ToUserName><![CDATA[toUser]]></ToUserName>`
12. `<FromUserName><![CDATA[fromUser]]></FromUserName>`
13. `<CreateTime>1348831860</CreateTime>`
14. `<MsgType><![CDATA[image]]></MsgType>`
15. `<PicUrl><![CDATA[this is a url]]></PicUrl>`
16. `<MediaId><![CDATA[media_id]]></MediaId>`
17. `<MsgId>1234567890123456</MsgId>`
18. `</xml>`
可以看到,两者共有的字段为ToUserName、FromUserName、CreateTime、MsgType和MsgId,对于文本消息,我们可以通过Content字段直接提取出消息文本内容,但是对于图片消息,我们需要通过PicUrl或MediaId获取图片信息后进行处理。
1. `def POST(self):`
2. `str_xml = web.data() #获得post来的数据`
3. `xml = etree.fromstring(str_xml)#进行XML解析`
4. `msgType=xml.find("MsgType").text`
5. `fromUser=xml.find("FromUserName").text`
6. `toUser=xml.find("ToUserName").text`
7. `ifmsgType == 'text':`
8. `content=xml.find("Content").text`
9. `if(content == u"天气"):`
10. `pass`
11. `elifmsgType == 'image':`
12. `pass`
13. `else:`
14. `pass`
获取到用户发送的消息后,我们需要考虑如何给用户发消息,其实并不难,我们只需要给定一个消息模板,并在相应的功能最后设置返回值即可
1. `returnself
.
render
.
reply\_text
(
fromUser
,
toUser
,
int
(
time
.
time
()),
'you string here'
)`
在目录下新建
templates/reply\_text.xml
1. `$def with (toUser,fromUser,createTime,content)`
2. `<xml>`
3. `<ToUserName><![CDATA[$toUser]]></ToUserName>`
4. `<FromUserName><![CDATA[$fromUser]]></FromUserName>`
5. `<CreateTime>$createTime</CreateTime>`
6. `<MsgType><![CDATA[text]]></MsgType>`
7. `<Content><![CDATA[$content]]></Content>`
8. `</xml>`
然后编辑weixinInterface.py
1. `def POST(self):`
2. `str_xml = web.data() #获得post来的数据`
3. `xml = etree.fromstring(str_xml)#进行XML解析`
4. `msgType=xml.find("MsgType").text`
5. `fromUser=xml.find("FromUserName").text`
6. `toUser=xml.find("ToUserName").text`
7. `ifmsgType == 'text':`
8. `content=xml.find("Content").text`
9. `returnself.render.reply_text(fromUser,toUser,int(time.time()), content)`
10. `elifmsgType == 'image':`
11. `pass`
12. `else:`
13. `pass`
以上操作的功能为:判断用户消息类型,如果消息类型为文本,则获取其内容content,并原样返回 content 作为消息。
完成以上修改后,重复 git 操作将修改 push 到远程仓库即可。
1. `git add .`
2. `git commit -m 'your commit message'`
3. `git push sae master:1`
测试效果图:
在下期Python开发微信公众号后台(系列二)中,将以查快递为例讲解如何实现文本消息操作以及对图片消息的处理
我 们 终 将 改 变 潮 水 的 方 向
§
§
Python中文社区
致力于成为
国内最好的Python社区
QQ群:152745094
专栏作者申请邮箱
— Life is short,we use Python —