Lolibot

Lolibot是一个微信消息处理框架,使用协议GPL v2

如果您在使用过程中遇见了问题,产生了疑惑,或者希望提出建议,推荐到项目地址去提交issue,或者直接向我发邮件:sanae # kochiya.me

  1. Hello World

  2. 消息处理

  3. 深入

  4. 响应

  5. 部署

Hello World

最简单的示例,会对发来的每条消息(包括事件),回复Hello World

from lolibot.loli import Shoujo
shoujo = Shoujo('yourToken')
@shoujo.add_callback()
def hello_world(message):
    return shoujo.response(message,content='Hello World')
shoujo.run()

消息处理

您可以尝试对多种微信消息的处理。

比如,或许您希望处理文本?

@shoujo.add_callback('text')
def echo(message):
    return shoujo.response(message)

或者,您希望处理图片?

@shoujo.add_callback('image')
def echoImage(message):
    return shoujo.response(message)

add_callback这个装饰器指定了期望处理的消息类型,紧接着定义的函数称为处理函数。

lolibot对目前微信所有的消息类型提供了支持,您只需要在add_callback(type)中设置希望处理的消息类型。下表列出了支持的类型:

类型名类型
text文本
image图片
voice语音
video视频
location位置
link链接
subscribe订阅
unsubscribe退订
all缺省
LOCATION用户上报地理位置
scan已订阅用户扫描二维码

小贴士

  • add_callback()—即对type进行留空,等效于add_callback('all')

  • 直接return xxx.response(message)通常是echo操作。

  • all类型是缺省的类型,如果定义了对all类型进行处理的处理函数,则即使接下来传递过来的消息处理函数并未定义,lolibot也会直接交给all类型处理函数来处理。

  • 若未定义all类型的处理函数,同时传入了一个并未定义处理函数的消息,那么,会执行lolibot中默认的all类型处理函数。

  • unsubscribe类型的定义并不会有任何收益,因为用户一旦退订了您的公众号,他就无法接收您传递的消息。

深入

所有的消息处理函数都会后跟一个参数,可以任意命名,下面用message来指代这个参数。

message是微信服务器发送过来的xml字符串,经过解析后生成的字典。根据处理消息的不同,属性(键值)也不一样,您可以任意增添以及任意修改键值。通常情况下,lolibot已经提供了足够的键值供修改,但是如果要发送news类型的消息,您需要增加大量的键值。

所有的消息均拥有以下属性(键),可以通过message[xxx]获取值:

属性名描述
msg_id消息id,64位整型
receiver接受方帐号(一个OpenID)
sender发送方帐号
type消息类型
timestamp时间戳

接下来是各种类型专有的属性。

文本消息

属性名描述
content文本内容

图片消息

属性名描述
picurl图片链接
media_id图片消息媒体id

语音消息

属性名描述
format语音格式
media_id语音消息媒体id

视频消息

属性名描述
media_id视频消息媒体id
th_media_id图片媒体id,指代缩略图

地理位置消息

属性名描述
x地理位置的纬度
y地理位置的经度
scale缩放程度
lable地理位置信息

链接消息

属性名描述
title链接标题
description链接描述
url链接地址

正确理解message中的属性,对理解response很有帮助。

响应

消息处理函数返回的,总应该是一个经过response函数处理后的字符串。

response函数负责对结果进行封装,这样会使代码书写变得稍微繁琐,但是考虑到随之而来的灵活性,大概这样的牺牲是值得的。

response函数第一个参数永远是message,根据传入的message,response函数挑选合适的模板(信函),填充后返回给微信服务器。另外,response支持若干额外的关键字。

不同类型的响应消息有不同的必要属性。比如,如果您需要返回固定的文本消息,那么,修改content就是必要的。您需要进行 message[content] = 'Hello World'这样修改message的content属性值。

以下是各类型必要的属性:

回复文本消息

属性名描述
typetext
content文本内容

回复图片消息

属性名描述
typeimage
media_id通过上传多媒体文件,得到的id

回复语音消息

属性名描述
typevoice
media_id通过上传多媒体文件,得到的id

回复视频消息

属性名描述
typevideo
media_id通过上传多媒体文件,得到的id
title视频消息的标题
description视频消息的描述

回复音乐消息

属性名描述
typemusic
media_id通过上传多媒体文件,得到的id(缩略图)
title音乐标题
description音乐描述
musurl音乐链接
hq_musurl高质量音乐链接,若没有提供则就是musurl

回复图文信息

要发送图文消息,除了指定额外关键字(下面会说)type='news',还必须指定额外关键字count=x

属性名描述
typenews
title图文消息标题
description图文消息描述
picurl图片链接
url点击图文跳转链接

注意

图文消息由于必须传入多个,所以必须对上面的属性增加数字用以区分,由0开始标注。

@shoujo.add_callback('news')
def news(m):
    m[title0] = 'test'
    m[description0] = 'kochiya sanae'
    m[picurl0] = 'http://blog.kochiya.me/avatar.png'
    m[url0] = 'http://blog.kochiya.me'
    # if you want to more ...
    # m[title1] = 'test1'
    # ...
    return shoujo.response(m,type='news',count=1)

以上方法并不优雅,如果有更好的办法,请向我提出,谢谢!

额外参数

额外参数并不是可选参数,事实上,某些额外参数甚至是必须的。

已提供的额外参数如下:

额外参数描述
type指定响应消息类型
content捷径,等效于msg[‘content’]=‘xxx’
handler可以额外传入一个以msg为参数的函数
count指定news中item的个数,当类型为news时,为必填项

回复的消息可以是任意合法的类型('text','music','image','voice','video','news')。如果该type合法,那么只需要修改type的值,并提供足够必要的参数即可。比如,我可以接收text类型(add_callback('text')),然后返回music类型的响应(reponse(message,type='music'))。

部署

lolibot提供了一份默认的example_wsgi.py,您可以修改它。

推荐使用uwsgi+nginx的方式进行部署。

这里提供一份uwsgi.ini的配置样例:

[uwsgi]
master = true
plugins = python
chdir = /path/to/you/lolibot/
socket = /tmp/loli.sock
module = wsgi:app
virtualenv = env
processes = 4
threads = 2
chmod-socket = 664
vaccum = true

nginx配置样例(记住在/etc/nginx/site-enabled/中做一个软链)

server{
    listen 80;
    charset utf-8;
    server_name example.com;
    access_log /path/to/you/access.log;
    error_log /path/to/you/error.log;
    location / {
        include uwsgi_params;
        uwsgi_pass unix:/tmp/loli.sock;
    }
}

一般直接运行uwsgi uwsig.ini是非守护进程,即,如果您关闭终端,进程会自动退出。推荐使用nohup。

ex:nohup uwsgi uwsgi.ini &

ENJOY IT!