Flask+SAE快速打造微信公众帐号(有码)

微信公众平台是个很牛逼的东西。大大节约了我们这些玩客的开发成本。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)


在微信平台输入你的url和token(要与上面代码里填的一致),点赞,不,点确定,即可完成验证。有问题的时候,记得加上末尾的 ‘/’ 试试 ( 如果你用Django,有ending slash 的问题 )。


四、完成初版- 将用户所发送的内容原样返回 (做完这个你就可以不用继续看了,去发挥你的想象力做出更有趣的东西来吧~)

首先要明白,微信平台提供给开发者的接口,其实是一堆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

解析出这些内容之后,我们要按照微信接口的格式构造一个xml发回去, 这里只需把 收者 和 发者 互换位置,加上时间戳和内容, 即可达到效果。


  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

你可能感兴趣的:(python,django,sae,flask)