WeRoBot 是一个微信机器人框架,采用 MIT 协议发布。
如果你在使用 WeRoBot 的过程中有什么建议或者疑惑,欢迎去 https://github.com/whtsky/WeRoBot/issues 提 Issue 或者给我发邮件: whtsky [at] gmail.com
最简单的Hello World, 会给收到的每一条信息回复 Hello World
import werobot
robot = werobot.WeRoBot(token='tokenhere')
@robot.handler
def echo(message):
return 'Hello World!'
robot.run()
WeRoBot会将合法的请求发送给 handlers 依次执行。
如果某一个 Handler 返回了非空值, WeRoBot 就会根据这个值创建回复,后面的 handlers 将不会被执行。
你可以通过两种方式添加 handler
import werobot
robot = werobot.WeRoBot(token='tokenhere')
# 通过修饰符添加handler
@robot.handler
def echo(message):
return 'Hello World!'
# 通过`add_handler`添加handler
def echo(message):
return 'Hello World!'
robot.add_handler(echo)
在大多数情况下, 一个 Handler 并不能处理所有类型的消息。幸运的是, WeRoBot 可以帮你过滤收到的消息。
只想处理被新用户关注的消息?:
import werobot
robot = werobot.WeRoBot(token='tokenhere')
@robot.subscribe
def subscribe(message):
return 'Hello My Friend!'
robot.run()
或者,你的 handler 只能处理文本?
import werobot
robot = werobot.WeRoBot(token='tokenhere')
@robot.text
def echo(message):
return message.content
robot.run()
修饰符 | 类型 |
---|---|
robot.text | 文本 |
robot.image | 图像 |
robot.location | 位置 |
robot.link | 链接 |
robot.subscribe | 被关注 |
robot.unsubscribe | 被取消关注 |
robot.click | 自定义菜单时间 |
robot.voice | 语音 |
robot.unknown | 未知类型 |
额,这个 handler 想处理文本信息和地理位置信息?
import werobot
robot = werobot.WeRoBot(token='tokenhere')
@robot.text
@robot.location
def handler(message):
# Do what you love to do
pass
robot.run()
当然,你也可以用 add_handler 函数添加handler,就像这样:
import werobot
robot = werobot.WeRoBot(token='tokenhere')
def handler(message):
# Do what you love to do
pass
robot.add_handler(handler, types=['text', 'location'])
robot.run()
Note
通过 robot.handler 添加的 handler 将收到所有信息;只有在其他 handler 没有给出返回值的情况下, 通过 robot.handler 添加的 handler 才会被调用。
@robot.key_click 是对 @robot.click 修饰符的改进。
如果你在自定义菜单中定义了一个 Key 为 abort 的菜单,响应这个菜单的 handler 可以写成这样
@robot.key_click("abort")
def abort():
return "I'm a robot"
当然,如果你不喜欢用 @robot.key_click ,也可以写成这样
@robot.click
def abort(message):
if message.key == "abort":
return "I'm a robot"
两者是等价的。
@robot.filter 是对 @robot.text 修饰符的改进。
现在你可以写这样的代码
@robot.filter("a")
def a():
return "正文为 a "
import re
@robot.filter(re.compile(".*?bb.*?"))
def b():
return "正文中含有 b "
@robot.filter(re.compile(".*?c.*?"), "d")
def c():
return "正文中含有 c 或正文为 d"
这段代码等价于
@robot.text
def a(message):
if message.content == "a":
return "正文为 a "
import re
@robot.text
def b():
if re.compile(".*?bb.*?").match(message.content):
return "正文中含有 b "
@robot.text
def c():
if re.compile(".*?c.*?").match(message.content) or message.content == "d":
return "正文中含有 c 或正文为 d"
除了 UnknownMessage, 每一种 Message 都包括以下属性:
name | value |
---|---|
id | 消息id,64位整型 [2] |
target | 开发者账号( OpenID ) |
source | 发送方账号( OpenID ) |
time | 信息发送的时间,一个UNIX时间戳。 |
raw | 信息的原始 XML 格式 |
name | value |
---|---|
type | ‘link’ |
title | 消息标题 |
description | 消息描述 |
url | 消息链接 |
LocationMessage的属性:
name | value |
---|---|
type | ‘location’ |
location | 一个元组。(纬度, 经度) |
scale | 地图缩放大小 |
label | 地理位置信息 |
EventMessage的属性:
name | value |
---|---|
type | ‘subscribe’ ‘unsubscribe’ ‘click’ 或 ‘location’ [1] |
key | 事件 key 值。当 type = ‘click’ 时存在。 |
Latitude | 地理位置纬度。当 type = ‘location’ 时存在。 |
Longitude | 地理位置经度。当 type = ‘location’ 时存在。 |
Precision | 地理位置精度。当 type = ‘location’ 时存在。 |
VoiceMessage的属性:
name | value |
---|---|
type | ‘voice’ |
media_id | 消息媒体 ID |
format | 声音格式 |
recognition | 语音识别结果 |
VideoMessage:
UnknownMessage的属性:
name | value |
---|---|
type | ‘unknown’ |
raw | 请求的正文部分。标准的XML格式。 |
Note
如果你不为 WeRoBot 贡献代码,你完全可以无视掉 UnknownMessage 。在正常的使用中,WeRoBot应该不会收到 UnknownMessage ——除非 WeRoBot 停止开发。
[1] | 当你被用户关注时,会收到 type=’subscribe’ 的事件; 被取消关注时是 type=’unsubscribe’ 。当用户点击自定义菜单按钮时 type 为 click ,用户上报地理位置的数据包 type 为 location |
[2] | 截至目前( 2013.03.16 ),微信机器人所收到的消息中都不包含 MsgID. |
目前WeRoBot共有四种Reply: TextReply , ArticlesReply , MusicReply 和 TransferCustomerServiceReply 。他们都继承自 WeChatReply 。
TextReply 是简单的文本消息,构造函数的参数如下:
name | value |
---|---|
content | 信息正文。 |
target | 信息的目标用户。通常是机器人用户。 |
source | 信息的来源用户。通常是发送信息的用户。 |
time | 信息发送的时间,一个UNIX时间戳。默认情况下会使用当前时间。 |
flag | 如果是True, WeRoBot会对这条消息进行星标。你可以在公众平台后台看到所有的星标消息。 |
你可以在构建Reply时传入一个合法的 Message 对象来自动生成 source 和 target
reply = TextReply(message=message, content='Hello!')
Note
如果你的handler返回了一个字符串, WeRoBot会自动将其转化为一个文本消息。
ArticlesReply 是图文消息,构造函数的参数如下:
name | value |
---|---|
content | 信息正文。可为空。 |
target | 信息的目标用户。通常是机器人用户。 |
source | 信息的来源用户。通常是发送信息的用户。 |
time | 信息发送的时间,一个UNIX时间戳。默认情况下会使用当前时间。 |
flag | 如果是True, WeRoBot会对这条消息进行星标。你可以在公众平台后台看到所有的星标消息。 |
你需要给 ArticlesReply 添加 Article 来增加图文。 Article 类位于 werobot.reply.Article 。
Article 的构造函数的参数如下:
name | value |
---|---|
title | 标题 |
description | 描述 |
img | 图片链接 |
url | 点击图片后跳转链接 |
注意,微信公众平台对图片链接有特殊的要求,详情可以在 消息接口使用指南 里看到。
在构造完一个 Article 后, 你需要通过 ArticlesReply 的 add_article 参数把它添加进去。就像这样:
from werobot.reply import ArticlesReply, Article
reply = ArticlesReply(message=message)
article = Article(
title="WeRoBot",
description="WeRoBot是一个微信机器人框架",
img="https://github.com/apple-touch-icon-144.png",
url="https://github.com/whtsky/WeRoBot"
)
reply.add_article(article)
Note
每个ArticlesReply中 最多添加10个Article 。
WeRoBot 会将其自动转为 ArticlesReply 。就像这样:
import werobot
robot = werobot.WeRoBot(token='tokenhere')
@robot.text
def articles(message):
return [
[
"title",
"description",
"img",
"url"
],
[
"whtsky",
"I wrote WeRoBot",
"https://secure.gravatar.com/avatar/0024710771815ef9b74881ab21ba4173?s=420",
"http://whouz.com/"
]
]
robot.run()
MusicReply 是音乐消息,构造函数的参数如下:
name | value |
---|---|
target | 信息的目标用户。通常是机器人用户。 |
source | 信息的来源用户。通常是发送信息的用户。 |
time | 信息发送的时间,一个UNIX时间戳。默认情况下会使用当前时间。 |
title | 标题 |
description | 描述 |
url | 音乐链接 |
hq_url | 高质量音乐链接,WIFI环境优先使用该链接播放音乐。可为空 [3] |
flag | 如果是True, WeRoBot会对这条消息进行星标。你可以在公众平台后台看到所有的星标消息。 |
WeRoBot 会将其自动转为 MusicReply 。就像这样:
import werobot
robot = werobot.WeRoBot(token='tokenhere')
@robot.text
def music(message):
return [
"title",
"description",
"music_url",
"hq_music_url"
]
@robot.text
def music2(message):
return [
"微信你不懂爱",
"龚琳娜最新力作",
"http://weixin.com/budongai.mp3",
]
robot.run()
[3] | (1, 2) 如果你省略了高质量音乐链接的地址, WeRoBot 会自动将音乐链接的地址用于高质量音乐链接。 |
将消息转发到多客服
WeRoBot 0.4.0 中增加了功能强大的 Session 系统,你可以通过 Session 轻松实现用户状态的记录,享受如同 Web 开发般的便捷。
一个简单的使用 Session 的 Demo
robot = werobot.WeRoBot(token=werobot.utils.generate_token(),
enable_session=True)
@robot.text
def first(message, session):
if 'last' in session:
return
session['last'] = message.content
return message.content
robot.run()
想要开启 Session ,在实例化 WeRoBot 的时候需要传入 enable_session 和 session_storage 两个参数:
没有打开 Session 的时候,一个标准的 WeRoBot Handler 应该是这样的
@robot.text
def hello(message):
return "Hello!"
而在打开 Session 之后, 这个 Handler 需要修改为接受第二个参数: session
@robot.text
def hello(message, session):
count = session.get("count", 0) + 1
session["count"] = count
return "Hello! You have sent %s messages to me" % count
传入的 session 参数是一个标准的 Python 字典。
在修改完 Handler 之后, 你的微信机器人就拥有 Session 系统了 :)
FileStorage 会把你的 Session 数据以 dbm 形式储存在文件中。
Parameters: | filename – 文件名, 默认为 werobot_session |
---|
MongoDBStorage 会把你的 Session 数据储存在一个 MongoDB Collection 中
import pymongo
import werobot
from werobot.session.mongodbstorage import MongoDBStorage
collection = pymongo.MongoClient()["wechat"]["session"]
session_storage = MongoDBStorage(collection)
robot = werobot.WeRoBot(token="token", enable_session=True,
session_storage=session_storage)
你需要安装 pymongo 才能使用 MongoDBStorage 。
Parameters: | collection – 一个 MongoDB Collection。 |
---|
RedisStorage 会把你的 Session 数据储存在 Redis 中
import redis
import werobot
from werobot.session.redisstorage import RedisStorage
db = redis.Redis()
session_storage = RedisStorage(db, prefix="my_prefix_")
robot = werobot.WeRoBot(token="token", enable_session=True,
session_storage=session_storage)
你需要安装 redis 才能使用 RedisStorage 。
Parameters: |
|
---|
SaeKVDBStorage 使用SAE 的 KVDB 来保存你的session
import werobot
from werobot.session.saekvstorage import SaeKVDBStorage
session_storage = SaeKVDBStorage()
robot = werobot.WeRoBot(token="token", enable_session=True,
session_storage=session_storage)
需要先在后台开启 KVDB 支持
Parameters: | prefix – KVDB 中 Session 数据 key 的 prefix 。默认为 ws_ |
---|
微信 API 操作类 通过这个类可以方便的通过微信 API 进行一系列操作,比如主动发送消息、创建自定义菜单等
创建分组 详情请参考 http://mp.weixin.qq.com/wiki/index.php?title=分组管理接口
Parameters: | name – 分组名字(30个字符以内) |
---|---|
Returns: | 返回的 JSON 数据包 |
创建自定义菜单
client = Client("id", "secret")
client.create_menu({
"button":[
{
"type":"click",
"name":"今日歌曲",
"key":"V1001_TODAY_MUSIC"
},
{
"type":"click",
"name":"歌手简介",
"key":"V1001_TODAY_SINGER"
},
{
"name":"菜单",
"sub_button":[
{
"type":"view",
"name":"搜索",
"url":"http://www.soso.com/"
},
{
"type":"view",
"name":"视频",
"url":"http://v.qq.com/"
},
{
"type":"click",
"name":"赞一下我们",
"key":"V1001_GOOD"
}
]
}
]})
详情请参考 http://mp.weixin.qq.com/wiki/index.php?title=自定义菜单创建接口
Parameters: | menu_data – Python 字典 |
---|---|
Returns: | 返回的 JSON 数据包 |
创建二维码 详情请参考 http://mp.weixin.qq.com/wiki/index.php?title=生成带参数的二维码
Parameters: | data – 你要发送的参数 dict |
---|---|
Returns: | 返回的 JSON 数据包 |
删除自定义菜单。 详情请参考 http://mp.weixin.qq.com/wiki/index.php?title=自定义菜单删除接口
Returns: | 返回的 JSON 数据包 |
---|
下载多媒体文件。 详情请参考 http://mp.weixin.qq.com/wiki/index.php?title=上传下载多媒体文件
Parameters: | media_id – 媒体文件 ID |
---|---|
Returns: | requests 的 Response 实例 |
获取关注者列表 详情请参考 http://mp.weixin.qq.com/wiki/index.php?title=获取关注者列表
Parameters: | first_user_id – 可选。第一个拉取的OPENID,不填默认从头开始拉取 |
---|---|
Returns: | 返回的 JSON 数据包 |
查询用户所在分组 详情请参考 http://mp.weixin.qq.com/wiki/index.php?title=分组管理接口
Parameters: | openid – 用户的OpenID |
---|---|
Returns: | 返回的 JSON 数据包 |
查询所有分组 详情请参考 http://mp.weixin.qq.com/wiki/index.php?title=分组管理接口
Returns: | 返回的 JSON 数据包 |
---|
查询自定义菜单。 详情请参考 http://mp.weixin.qq.com/wiki/index.php?title=自定义菜单查询接口
Returns: | 返回的 JSON 数据包 |
---|
获取用户基本信息 详情请参考 http://mp.weixin.qq.com/wiki/index.php?title=获取用户基本信息
Parameters: |
|
---|---|
Returns: | 返回的 JSON 数据包 |
获取 Access Token 。 详情请参考 http://mp.weixin.qq.com/wiki/index.php?title=通用接口文档
Returns: | 返回的 JSON 数据包 |
---|
移动用户分组 详情请参考 http://mp.weixin.qq.com/wiki/index.php?title=分组管理接口
Parameters: |
|
---|---|
Returns: | 返回的 JSON 数据包 |
发送图文消息 详情请参考 http://mp.weixin.qq.com/wiki/index.php?title=发送客服消息
Parameters: |
|
---|---|
Returns: | 返回的 JSON 数据包 |
发送图片消息 详情请参考 http://mp.weixin.qq.com/wiki/index.php?title=发送客服消息
Parameters: |
|
---|---|
Returns: | 返回的 JSON 数据包 |
发送音乐消息 详情请参考 http://mp.weixin.qq.com/wiki/index.php?title=发送客服消息
Parameters: |
|
---|---|
Returns: | 返回的 JSON 数据包 |
发送文本消息 详情请参考 http://mp.weixin.qq.com/wiki/index.php?title=发送客服消息
Parameters: |
|
---|---|
Returns: | 返回的 JSON 数据包 |
发送视频消息 详情请参考 http://mp.weixin.qq.com/wiki/index.php?title=发送客服消息
Parameters: |
|
---|---|
Returns: | 返回的 JSON 数据包 |
发送语音消息 详情请参考 http://mp.weixin.qq.com/wiki/index.php?title=发送客服消息
Parameters: |
|
---|---|
Returns: | 返回的 JSON 数据包 |
通过ticket换取二维码 详情请参考 http://mp.weixin.qq.com/wiki/index.php?title=生成带参数的二维码
Parameters: | ticket – 二维码 ticket 。可以通过 create_qrcode() 获取到 |
---|---|
Returns: | 返回的 Request 对象 |
修改分组名 详情请参考 http://mp.weixin.qq.com/wiki/index.php?title=分组管理接口
Parameters: |
|
---|---|
Returns: | 返回的 JSON 数据包 |
上传多媒体文件。 详情请参考 http://mp.weixin.qq.com/wiki/index.php?title=上传下载多媒体文件
Parameters: | media_type – 媒体文件类型,分别有图片(image)、语音(voice)、视频(video)和缩略图(thumb) |
---|
:param media_file:要上传的文件,一个 File-object
Returns: | 返回的 JSON 数据包 |
---|
简化微信支付API操作
alpha 暂时不建议使用 这个接口使用起来十分不友好 而且会引起巨大的误解
url 需要带上 code 和 state (url?code=xxx&state=1) code 和state 是 oauth 时候回来的
token 要传用户的 token
这尼玛 你能相信这些支付接口都是腾讯出的?
签名 pay package 需要的参数 详情请参考 支付开发文档
Parameters: | package – 需要签名的的参数 |
---|---|
Returns: | 可以使用的packagestr |
签名 js 需要的参数 详情请参考 支付开发文档
wxclient.create_js_pay_params(
body=标题, out_trade_no=本地订单号, total_fee=价格单位分,
notify_url=通知url,
spbill_create_ip=建议为支付人ip,
)
Parameters: | package – 需要签名的的参数 |
---|---|
Returns: | 支付需要的对象 |
创建 native pay url 详情请参考 支付开发文档
Parameters: | productid – 本地商品ID |
---|---|
Returns: | 返回URL |
通知 腾讯发货
)
:param 需要签名的的参数 :return: 支付需要的对象
查询订单状态 一般用于无法确定 订单状态时候补偿
Parameters: | out_trade_no – 本地订单号 |
---|---|
Returns: | 订单信息dict |
当你运行 werobot.run 的时候,你可以通过传递 server 参数来手动指定使用的服务器
import werobot
robot = werobot.WeRoBot(token='tokenhere')
@robot.handler
def echo(message):
return 'Hello World!'
robot.run(server='gevent', port=12233)
server 支持以下几种:
当 server 为 auto 时, WeRoBot 会自动依次尝试以下几种服务器:
所以,只要你安装了相应的服务器软件,就可以使用 werobot.run 直接跑在生产环境下。
Note
server 的默认值为 auto
请注意, werobot.run 是跑在 非守护进程模式下 的——也就是说,一旦你关闭终端,进程就会自动退出。
我们建议您使用 Supervisor 来管理 WeRoBot 的进程。
配置文件样例:
[program:wechat_robot]
command = python /home/whtsky/robot.py
user = whtsky
redirect_stderr = true
stdout_logfile = /home/whtsky/logs/robot.log
微信服务器只支持80端口的机器人——显然,你的服务器上不会只跑着一个微信机器人。对于这种情况,我们建议您使用 Nginx 来进行反向代理。
配置文件样例:
server {
server_name example.com;
listen 80;
location / {
proxy_pass_header Server;
proxy_redirect off;
proxy_pass http://127.0.0.1:12233;
}
}
Note
在这个例子中, WeRoBot 的端口号为 12233。你应该在微信管理后台中将服务器地址设为 http://example.com 。