创作灵感
昨天在朋友圈看到这样一则分享:
多少会有些迷信的嘛,也是跟风,我就也识别了二维码,结果还要获取我的个人用户信息。。。
这样一波操作过后,我又可以分享出去,让我的朋友圈好友去扫,他们又分享,这样一传十、一传百,不知不觉又被隔了一波韭菜:
创作笔法
微信公众号的两种开发模式
你可能会有一个疑惑?我为什么要用小号做测试呢?其实微信公众号开发分两种模式:
编辑模式:主要针对非编程人员及信息发布类公众帐号使用。开启该模式后,可以方便地通过界面配置“自定义菜单”和“自动回复的消息”。
开发模式:主要针对具备开发能力的人使用。开启该模式后,能够使用微信公众平台开放的接口,通过编程方式实现自定义菜单的创建、用户消息的接收/处理/响应。这种模式更加灵活,建议有开发能力的公司或个人都采用该模式。
简单来说,就是不用写代码直接在微信公众号网页上配置自定义菜单或者自动回复,这叫编辑模式;需要写代码实现自动回复或者更高级的逻辑,这叫开发模式;并且这两种模式是互斥的,就是说,一旦开启了开发模式,编辑模式就失效了,之前配置的自定义菜单和自动回复全部失效,这对我现在这个公众号是不可接受的,因为在编辑模式里配置太多了,迁移到开发者模式一来多耗了时间成本,二来还不稳定,所以我想起了我尘封已久的小号。
创作原料
在正式开发前,你需要有以下“纸”或者“笔”:
服务器接入微信公众号
然后呢,其实在微信公众号开发过程中,微信公众号后台就像是一台代理服务器,微信公众号消息先由微信公众号后台处理,再转发给我们自己的服务器处理,这过程就必须要遵循微信公众号的开发规范了;那么,怎么让微信公众号和我们自己的服务器对接呢?接入微信公众平台开发,开发者需要按照如下步骤完成:
填写服务器配置:填写 URL(只支持 80(http) 和 443(https) 端口,开发者文档说是服务器域名,准确来说不是你的服务器域名,而是你服务器上处理微信公众号转发消息的根路由)、Token(可随便填) 和 EncodingAESKey(可自动生成),这两个参数只在接入时可能有用,是为了安全性起见而采用 sha1 加密的几个参数之二,无需过多关心,这一步主要是注意 URL 的正确性。
验证服务器地址的有效性:点一下验证按钮即可,网页上会出现 Token 验证成功或者失败的提示。
依据接口文档实现业务逻辑:这个就是我们大展身手写代码的部分了。
应用逻辑
有个坑需要填一下,个人微信公众号不能够获取用户的基本信息:昵称和头像等等
需要认证才能获得这个权限,但是认证需要 take money,但是我满脸都写着穷。。。
回到我们的创作初衷,涉及个性化预测海报,个性化部分我就简单处理,直接随机字符串,如果深挖的话需要个性化推荐,但是没有用户信息,难道要写几个逻辑让用户自己输兴趣爱好并返回?这已经脱离本次创作的初衷了,下次补上。
至于制作海报,我用的的 PIL 库中的 ImageDraw 对象,直接在预设的海报上填充字符串即可。
PIL 库的安装姿势是 pip install pillow 而不是 pip install PIL
然后应用服务器采用的是 Flask 框架(Flask 是应用框架,nginx 是 web 服务器,他们都属于软件,Flask 自带的生产环境服务器不足以支持实际应用,需要 uwsgi 应用服务器,nginx 直接处理静态资源请求,逻辑请求转发给 uwsgi ;阿里云服务器是虚拟化的 PC,包括软件和硬件;有关服务器具体知识可以参考我之前发过的一篇文章:扫码考勤小程序正式上线)
回到主题,假设我们的根路由是
https://doamin/wechat/
我们可以给这个路由绑定一个视图函数,my_view(),并同时开启处理 post 请求开关(默认只处理 get),我们所有的逻辑都可以由这一个视图函数实现,接入公众号开发时 Token 验证公众号是通过 get 方式请求到我们的服务器的,验证通过后的转发消息都是通过 post 方式,那么,我们就可以通过请求方式区分是验证还是转发了。
if request.method == 'GET': signature = request.args['signature'] timestamp = request.args['timestamp'] echostr = request.args['echostr'] nonce = request.args['nonce'] token = '好想爱这个世界' tempList = [token, timestamp, nonce] # 字典序排序 tempList.sort() # 转成字符串 tempStr = ''.join(tempList) # sha1 加密 tempStr = hashlib.sha1(tempStr.encode('utf-8')).hexdigest() if tempStr == signature: print('token verify succes') return echostr else: #可以发现,前面的验证代码其实无关紧要,只要返回了 echostr ,就算验证成功 return echostr elif request.method == 'POST': print('在这里写业务逻辑')
我们还需要在自己的服务器上调用微信的接口,比如海报制作完成后,通过微信转发给用户,不能直接返回图片的二进制数据,事实上这是微信公众号做的,我们需要上传该海报至微信公众号素材库,获得这个海报的 id,然后封装成 xml 数据返回给微信公众号(吐槽一下还没有升级到 json 交换数据),这样用户就收到我们的海报了。
那么问题来了,上传该海报至微信公众号素材库,在公众号文章编辑界面呆久了,我还以为要手动上传,还好找到了接口 1,我们可以在服务器上调用这个接口 1,为了防止滥用这个接口 1, 必须提供 access_token , 但是 access_token 哪里来呢?需要通过调用另一个接口 2,接口 2 需要提供 AppId 和 AppSecret 参数,如果不自己修改,这两个是长期有效的,可以直接获取。
接口 1:POST https://api.weixin.qq.com/cgi-bin/media/upload?access_token=ACCESS_TOKEN&type=TYPE
接口 2:GET https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
还有一个坑就是,这个 access_token 有效期只有 2 个小时,所以我们需要不断更新它,所以需要给我们的 Flask 引入循环任务配置
# 定时任务配置 class Config(object): # 创建配置 # 任务列表 JOBS = [ { 'id': '1', 'func': '__main__:refreshToken', # 定时执行的方法名 'trigger': 'interval', # interval表示循环任务 'hours': 2, # 每两个小时的执行一次 } ] app.config.from_object(Config()) # 为实例化的flask引入配置