微信公众平台是个很牛逼的东西。大大节约了我们这些玩客的开发成本。Django也不错,但是开发这种东西,太笨重了,大材小用。还是推荐Flask。
本文以我自己的作品为例,介绍一种简单方法,可以快速地从零开始开发一个微信公众帐号,提供简单的搜索歌词的功能,输入“歌曲名 歌手名”,返回歌词。
作品已开源,欢迎围观。
使用技术:Python, Flask框架, SAE
成本:两罐汽水,一个下午一个晚上(或更快)
产出:一个微信公众账号,信息如下
账号名:查理歌词
微信号: chaligeci
项目地址: https://github.com/handalin/CharlieLrc
环境:linux系统
需要先安装的东西: svn ( ubuntu里 apt-get install subversion ) 这是新浪用来管理代码的工具
Flask (文档在此 https://flask-cn.readthedocs.org/en/latest/ ) 这是一个Python写的Web开发框架,轻巧灵活,很适合开发这种小应用。
一、去微信那里申请公号 ( http://mp.weixin.qq.com/ )
注册完,想好账号的名字(不可更改),填完资料来到一个页面,要求你填入你自己服务器的 url , 还有 token。
token就是令牌,微信平台通过token来验证彼此的身份(就别吐槽这个了。。。)
那么url,填入你的服务器地址。
服务器就采用新浪的Sina App Engine了。
二、到SAE新建一个项目
由于本文的主角是 微信平台, 新浪这边的事儿, 看这里吧 http://sae.sina.com.cn/?m=devcenter&catId=289 ,简洁明了。
三、微信公号和SAE应用的对接-验证
做法就是, 在SAE应用(下面简称应用)里写一个函数来处理Http请求, 微信平台这边会给我们的应用发送一个GET请求,带上4个参数。
我们要做的就是在应用里面处理这个请求,验证(其实可以不用)之后返回echostr参数即可。
上代码:
# -*- coding:utf8 -*- import time from flask import Flask,request, make_response import hashlib @app.route('/', methods = ['GET', 'POST'] ) def wechat_auth(): if request.method == 'GET': token = 'xxxxxxxxxxx' # your token query = request.args # GET 方法附上的参数 signature = query.get('signature', '') timestamp = query.get('timestamp', '') nonce = query.get('nonce', '') echostr = query.get('echostr', '') s = [timestamp, nonce, token] s.sort() s = ''.join(s) if ( hashlib.sha1(s).hexdigest() == signature ): return make_response(echostr)
四、完成初版- 将用户所发送的内容原样返回 (做完这个你就可以不用继续看了,去发挥你的想象力做出更有趣的东西来吧~)
首先要明白,微信平台提供给开发者的接口,其实是一堆xml格式的数据, 假设用户发了一个消息给公号,那么这个消息会以xml的格式被组织然后发送,那么我们在应用里收到此xml , 理所应当要解析出内容, 这里使用 xml.etree.ElementTree 来解析。 http://mp.weixin.qq.com/wiki/index.php?title=%E6%B6%88%E6%81%AF%E6%8E%A5%E5%8F%A3%E6%8C%87%E5%8D%97 这里可以看到它xml的格式,我们其实只需要解析出 发者,收者,还有内容即可。 ElementTree 可以很轻松地做到这点,代码如下:
# Get the infomations from the recv_xml. xml_recv = ET.fromstring(request.data) ToUserName = xml_recv.find("ToUserName").text FromUserName = xml_recv.find("FromUserName").text Content = xml_recv.find("Content").text
reply = "<xml><ToUserName><![CDATA[%s]]></ToUserName><FromUserName><![CDATA[%s]]></FromUserName><CreateTime>%s</CreateTime><MsgType><![CDATA[text]]></MsgType><Content><![CDATA[%s]]></Content><FuncFlag>0</FuncFlag></xml>"
response = make_response( reply % (FromUserName, ToUserName, str(int(time.time())), Content ) )
response.content_type = 'application/xml' return response
svn commit -m 之后, 更新代码完成。
这里注意,要先去微信公众平台 mp.weixin.qq.com 的高级设置 那里面, 关闭编辑模式,打开开发者模式....
拿起你的手机去试试吧, 发什么回复什么。 你可以试试看骂它傻x,看会发生什么事。
五、查理歌词--一个查歌词的小爬虫
很明显,我们只需要对收到的Content作处理, 得到结果(歌词),返回去即可。
编写 shark.py 文件, shark是虾米的一个产品叫 虾歌, 我很喜欢虾米, 推荐一下吧。 不过虾米的搜索和排名真心是奇葩, 我表示受不了,但暂时先这样吧。
我把它写成了一个类 SharkSearcher, 实现了 feed 函数, 该函数接受关键词参数, 返回歌词结果。
# -*- coding:utf8 -*- import urllib2, urllib import sys import re class SharkSearcher(): def __init__(self): self.error_msg = "查理没用...查不到...\nbtw,您听歌的品味真独特.\n您确认格式正确?(歌名 歌手名)" def process_lrc(self, lrc): return ''.join( lrc.split('<br />') ) def feed(self, song, artist=None): if not artist: artist = '' else: artist = '+' + artist myurl = 'http://www.xiami.com/search?key=' + song + artist # pretent to be IE. ^O^ user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)' values = {'name':'67', 'location':'Northampton', 'language':'Python'} headers = { 'User-Agent':user_agent} data = urllib.urlencode(values) req = urllib2.Request(myurl, data, headers) try: html = urllib2.urlopen(req).read() except BaseException: return self.error_msg pattern = r'<td class="song_name"><a target="_blank" href="(.+?)" title="' try: song_url = re.findall(pattern, html)[0] except BaseException: return self.error_msg pattern = r'<div class="lrc_main">([\s\S]+?)</div>' req = urllib2.Request('http://www.xiami.com'+song_url, data, headers) try: html = urllib2.urlopen(req).read() except BaseException: return self.error_msg lrc = re.findall(pattern, html)[0] return self.process_lrc(lrc)
我的做法很dirty,就是将用户给我的参数拆开,附到 HTTP 的GET请求里发给虾米。
去虾米 (xiami.com) 搜一下, 会发现 它的搜索结果 url 是这样的 http://www.xiami.com/search?key=xxx+yyy(xxx,yyy是搜索的关键词) , 那么直接用python的urllib2包可以读到整个搜索结果, 然后看它源码, 这里用正则表达式直接抠出了我想要的部分( 第一个链接), 当然你可以用更碉堡的办法,但正则表达式无疑是最好写的。
接着拿到歌曲详情页,依然,用正则表达式抠出歌词,返回即可。
注意,虾米会判断你的身份,限制机器人的访问。 中间那段 # pretent to be IE 就是用来伪装的, 装成是浏览器, 然后虾米就乖乖地交出数据了。
所有代码已放上github。
https://github.com/handalin/CharlieLrc