WeRoBot¶
WeRoBot 是一个微信公众号开发框架。
如果你在使用 WeRoBot 的过程中有什么建议或者疑惑,欢迎去 https://github.com/whtsky/WeRoBot/issues 提 Issue 或者给我发邮件: whtsky [at] gmail.com
入门¶
Hello World¶
最简单的Hello World, 会给收到的每一条信息回复 Hello World
import werobot
robot = werobot.WeRoBot(token='tokenhere')
@robot.handler
def echo(message):
return 'Hello World!'
robot.run()
消息加密¶
WeRoBot 支持对消息的加密,即微信公众号的安全模式。
为 WeRoBot 开启消息加密功能,首先需要安装 cryptography
pip install cryptography
之后需要在微信公众平台的基本配置中将消息加解密方式选择为安全模式,随机生成 EncodingAESKey,并且把它传给 WeRoBot 或者 WeRoBot 实例的 config 或者创建相对应的 Config 类
from werobot import WeRoBot
robot = WeRoBot(token='2333',
encoding_aes_key='your_encoding_aes_key',
app_id='your_app_id')
Handlers¶
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()
在 WeRobot 中我们把请求分成了 Message 和 Event 两种类型,针对两种类型的请求分别有不同的 Handler。
修饰符 | 类型 |
---|---|
robot.text | 文本 (Message) |
robot.image | 图像 (Message) |
robot.location | 位置 (Message) |
robot.link | 链接 (Message) |
robot.voice | 语音 (Message) |
robot.unknown | 未知类型 (Message) |
robot.subscribe | 被关注 (Event) |
robot.unsubscribe | 被取消关注 (Event) |
robot.click | 自定义菜单事件 (Event) |
robot.view | 链接 (Event) |
robot.scan | 扫码 (Event) |
robot.location_event | 上报位置 (Event) |
robot.unknown_event | 未知类型 (Event) |
额,这个 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()
注解
通过 robot.handler
添加的 handler 将收到所有信息;只有在其他 handler 没有给出返回值的情况下, 通过 robot.handler
添加的 handler 才会被调用。
robot.key_click —— 回应自定义菜单¶
@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.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 |
---|---|
message_id | 消息id,64位整型 |
target | 开发者账号( OpenID ) |
source | 发送方账号( OpenID ) |
time | 信息发送的时间,一个UNIX时间戳。 |
raw | 信息的原始 XML 格式 |
LinkMessage¶
name | value |
---|---|
type | ‘link’ |
title | 消息标题 |
description | 消息描述 |
url | 消息链接 |
LocationMessage¶
LocationMessage 的属性:
name | value |
---|---|
type | ‘location’ |
location | 一个元组。(纬度, 经度) |
scale | 地图缩放大小 |
label | 地理位置信息 |
VoiceMessage¶
VoiceMessage 的属性:
name | value |
---|---|
type | ‘voice’ |
media_id | 消息媒体 ID |
format | 声音格式 |
recognition | 语音识别结果 |
UnknownMessage¶
UnknownMessage 的属性:
name | value |
---|---|
type | ‘unknown’ |
raw | 请求的正文部分。标准的XML格式。 |
注解
如果你不为 WeRoBot 贡献代码,你完全可以无视掉 UnknownMessage 。在正常的使用中,WeRoBot应该不会收到 UnknownMessage ——除非 WeRoBot 停止开发。
事件¶
公共属性¶
除了 UnknownEvent, 每一种 Event 都包括以下属性:
name | value |
---|---|
message_id | 消息id |
target | 开发者账号( OpenID ) |
source | 发送方账号( OpenID ) |
time | 信息发送的时间,一个UNIX时间戳。 |
raw | 信息的原始 XML 格式 |
SubscribeEvent¶
SubscribeEvent 的属性:
name | value |
---|---|
type | ‘subscribe’ |
key | 事件 key 值。 当且仅当未关注公众号扫描二维码时存在。 |
ticket | 二维码的 ticket。 当且仅当未关注公众号扫描二维码时存在。 |
LocationEvent¶
LocationEvent 的属性:
name | value |
---|---|
type | ‘location’ |
latitude | 地理位置纬度 |
longitude | 地理位置经度 |
precision | 地理位置精度 |
TemplateSendJobFinishEvent¶
模版消息发送任务完成后的 Event 通知。 属性: =========== =================================== name value =========== =================================== status 发送是否成功。为 ‘success’ 或失败原因 =========== ===================================
UnknownEvent¶
UnknownEvent 的属性:
name | value |
---|---|
type | ‘unknown’ |
raw | 请求的正文部分。标准的XML格式。 |
注解
如果你不为 WeRoBot 贡献代码,你完全可以无视掉 UnknownEvent 。在正常的使用中,WeRoBot应该不会收到 UnknownEvent ——除非 WeRoBot 停止开发。
回复¶
你可以在构建Reply时传入一个合法的 Message 对象来自动生成 source 和 target
reply = TextReply(message=message, content='Hello!')
TextReply¶
TextReply 是简单的文本消息,构造函数的参数如下:
name | value |
---|---|
content | 信息正文。 |
target | 信息的目标用户。通常是机器人用户。 |
source | 信息的来源用户。通常是发送信息的用户。 |
time | 信息发送的时间,一个UNIX时间戳。默认情况下会使用当前时间。 |
注解
如果你的handler返回了一个字符串, WeRoBot会自动将其转化为一个文本消息。
ImageReply¶
ImageReply 为回复图片消息,构造函数的参数如下:
name | value |
---|---|
media_id | 通过素材管理接口上传多媒体文件,得到的id。 |
target | 信息的目标用户。通常是机器人用户。 |
source | 信息的来源用户。通常是发送信息的用户。 |
time | 信息发送的时间,一个UNIX时间戳。默认情况下会使用当前时间。 |
VoiceReply¶
VoiceReply 为回复语音消息,构造函数的参数如下:
name | value |
---|---|
media_id | 通过素材管理接口上传多媒体文件,得到的id。 |
target | 信息的目标用户。通常是机器人用户。 |
source | 信息的来源用户。通常是发送信息的用户。 |
time | 信息发送的时间,一个UNIX时间戳。默认情况下会使用当前时间。 |
VideoReply¶
VideoReply 为回复视频消息,构造函数的参数如下:
name | value |
---|---|
media_id | 通过素材管理接口上传多媒体文件,得到的id。 |
title | 视频消息的标题。可为空。 |
description | 视频消息的描述。可为空。 |
target | 信息的目标用户。通常是机器人用户。 |
source | 信息的来源用户。通常是发送信息的用户。 |
time | 信息发送的时间,一个UNIX时间戳。默认情况下会使用当前时间。 |
ArticlesReply¶
ArticlesReply 是图文消息,构造函数的参数如下:
name | value |
---|---|
content | 信息正文。可为空。 |
target | 信息的目标用户。通常是机器人用户。 |
source | 信息的来源用户。通常是发送信息的用户。 |
time | 信息发送的时间,一个UNIX时间戳。默认情况下会使用当前时间。 |
你需要给 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)
注解
每个ArticlesReply中 最多添加10个Article 。
- 你也可以让你的 handler 返回一个列表, 里面每一个元素都是一个长度为四的列表,
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¶
MusicReply 是音乐消息,构造函数的参数如下:
name | value |
---|---|
target | 信息的目标用户。通常是机器人用户。 |
source | 信息的来源用户。通常是发送信息的用户。 |
time | 信息发送的时间,一个UNIX时间戳。默认情况下会使用当前时间。 |
title | 标题 |
description | 描述 |
url | 音乐链接 |
hq_url | 高质量音乐链接,WIFI环境优先使用该链接播放音乐。可为空 [3] |
- 你也可以让你的 handler 返回一个长度为三或四的列表, [3]
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 会自动将音乐链接的地址用于高质量音乐链接。 |
TransferCustomerServiceReply¶
将消息转发到多客服
SuccessReply¶
给微信服务器回复 “success”。 假如服务器无法保证在五秒内处理并回复,需要回复 SuccessReply ,这样微信服务器才不会对此作任何处理,并且不会发起重试。
Session¶
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¶
想要开启 Session ,在实例化 WeRoBot
的时候需要传入 enable_session
和 session_storage
两个参数:
enable_session
: 必须为 True (打开 Session )session_storage
: 可选,一个 Session Storage 实例。默认是werobot.session.filestorage.FileStorage
。
修改 Handler 以使用 Session¶
没有打开 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 系统了 :)
可用的 Session Storage¶
-
class
werobot.session.filestorage.
FileStorage
(filename='werobot_session')¶ FileStorage 会把你的 Session 数据以 dbm 形式储存在文件中。
参数: filename – 文件名, 默认为 werobot_session
-
class
werobot.session.mongodbstorage.
MongoDBStorage
(collection)¶ 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 。参数: collection – 一个 MongoDB Collection。
-
class
werobot.session.redisstorage.
RedisStorage
(redis, prefix='ws_')¶ 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 。参数: - redis – 一个 Redis Client。
- prefix – Reids 中 Session 数据 key 的 prefix 。默认为
ws_
-
class
werobot.session.saekvstorage.
SaeKVDBStorage
(prefix='ws_')¶ 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 支持
参数: prefix – KVDB 中 Session 数据 key 的 prefix 。默认为 ws_
-
class
werobot.session.sqlitestorage.
SQLiteStorage
(filename='werobot_session.sqlite3')¶ SQLiteStorge 会把 Session 数据储存在一个 SQLite 数据库文件中
import werobot from werobot.session.sqlitestorage import SQLiteStorage session_storage = SQLiteStorage robot = werobot.WeRoBot(token="token", enable_session=True, session_storage=session_storage)
参数: filename – SQLite数据库的文件名, 默认是 werobot_session.sqlite3
。
WeRoBot.Config
¶
WeRoBot 使用 WeRoBot.Config
类来存储配置信息。 WeRoBot
类实例的 config
属性是一个 WeRobot.config.Config
实例。
WeRobot.config.Config
继承自 dict 。因此, 你可以像使用普通 dict 一样使用它
from werobot import WeRoBot
robot = WeRoBot(token='2333')
robot.config.update(
HOST='0.0.0.0',
PORT=80
)
与普通 dict 不同的是, 你可以先把配置文件保存在一个对象或是文件中, 然后在 WeRoBot.config.Config
中导入配置
from werobot import WeRoBot
robot = WeRoBot(token='2333')
class MyConfig(object):
HOST = '0.0.0.0'
PORT = 80
robot.config.from_object(MyConfig)
robot.config.from_pyfile("config.py")
默认配置¶
dict(
TOKEN=None,
SERVER="auto",
HOST="127.0.0.1",
PORT="8888",
SESSION_STORAGE=None,
APP_ID=None,
APP_SECRET=None,
ENCODING_AES_KEY=None
)
与其他 Web 框架集成¶
WeRoBot 可以作为独立服务运行,也可以集成在其他 Web 框架中一同运行。
Django¶
WeRoBot 支持 Django 1.6+。
首先,在一个文件中写好你的微信机器人
# Filename: robot.py
from werobot import WeRoBot
robot = WeRoBot(token='token')
@robot.handler
def hello(message):
return 'Hello World!'
然后,在你 Django 项目中的 urls.py
中调用 werobot.contrib.django.make_view()
,将 WeRoBot 集成进 Django
from django.conf.urls import patterns, include, url
from werobot.contrib.django import make_view
from robot import robot
urlpatterns = patterns('',
url(r'^robot/', make_view(robot)),
)
Flask¶
首先, 同样在文件中写好你的微信机器人
# Filename: robot.py
from werobot import WeRoBot
robot = WeRoBot(token='token')
@robot.handler
def hello(message):
return 'Hello World!'
然后, 在 Flask 项目中为 Flask 实例集成 WeRoBot
from flask import Flask
from robot import robot
from werobot.contrib.flask import make_view
app = Flask(__name__)
app.add_url_rule(rule='/robot/', # WeRoBot 挂载地址
endpoint='werobot', # Flask 的 endpoint
view_func=make_view(robot),
methods=['GET', 'POST'])
Bottle¶
在你的 Bottle App 中集成 WeRoBot
from werobot import WeRoBot
robot = WeRoBot(token='token')
@robot.handler
def hello(message):
return 'Hello World!'
from bottle import Bottle
from werobot.contrib.bottle import make_view
app = Bottle()
app.route('/robot', # WeRoBot 挂载地址
['GET', 'POST'],
make_view(robot))
Tornado¶
最简单的 Hello World
import tornado.ioloop
import tornado.web
from werobot import WeRoBot
from werobot.contrib.tornado import make_handler
robot = WeRoBot(token='token')
@robot.handler
def hello(message):
return 'Hello World!'
application = tornado.web.Application([
(r"/robot/", make_handler(robot)),
])
if __name__ == "__main__":
application.listen(8888)
tornado.ioloop.IOLoop.instance().start()
API¶
-
werobot.contrib.django.
make_view
(robot)¶ 为一个 BaseRoBot 生成 Django view。
参数: robot – 一个 BaseRoBot 实例。 返回: 一个标准的 Django view
-
werobot.contrib.flask.
make_view
(robot)¶ 为一个 BaseRoBot 生成 Flask view。
Usage
from werobot import WeRoBot robot = WeRoBot(token='token') @robot.handler def hello(message): return 'Hello World!' from flask import Flask from werobot.contrib.flask import make_view app = Flask(__name__) app.add_url_rule(rule='/robot/', # WeRoBot 的绑定地址 endpoint='werobot', # Flask 的 endpoint view_func=make_view(robot), methods=['GET', 'POST'])
参数: robot – 一个 BaseRoBot 实例 返回: 一个标准的 Flask view
-
werobot.contrib.bottle.
make_view
(robot)¶ 为一个 BaseRoBot 生成 Bottle view。
Usage
from werobot import WeRoBot robot = WeRoBot(token='token') @robot.handler def hello(message): return 'Hello World!' from bottle import Bottle from werobot.contrib.bottle import make_view app = Bottle() app.route( '/robot', # WeRoBot 挂载地址 ['GET', 'POST'], make_view(robot) )
参数: robot – 一个 BaseRoBot 实例 返回: 一个标准的 Bottle view
-
werobot.contrib.tornado.
make_handler
(robot)¶ 为一个 BaseRoBot 生成 Tornado Handler。
Usage
import tornado.ioloop import tornado.web from werobot import WeRoBot from tornado_werobot import make_handler robot = WeRoBot(token='token') @robot.handler def hello(message): return 'Hello World!' application = tornado.web.Application([ (r"/", make_handler(robot)), ])
参数: robot – 一个 BaseRoBot 实例。 返回: 一个标准的 Tornado Handler
错误页面¶
WeRoBot
自带了一个错误页面,它将会在 Signature 验证不通过的时候返回错误页面。
定制错误页面¶
如果你想为 WeRoBot
指定 Signature 验证不通过时显示的错误页面,可以这么做:
@robot.error_page
def make_error_page(url):
return "<h1>喵喵喵 %s 不是给麻瓜访问的快走开</h1>" % url
WeRoBot.Client
—— 微信 API 操作类¶
-
class
werobot.client.
Client
(config)¶ 微信 API 操作类 通过这个类可以方便的通过微信 API 进行一系列操作,比如主动发送消息、创建自定义菜单等
-
create_group
(name)¶ 创建分组 详情请参考 http://mp.weixin.qq.com/wiki/index.php?title=分组管理接口
参数: name – 分组名字(30个字符以内) 返回: 返回的 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=自定义菜单创建接口
参数: menu_data – Python 字典 返回: 返回的 JSON 数据包
-
create_qrcode
(**data)¶ 创建二维码 详情请参考 http://mp.weixin.qq.com/wiki/index.php?title=生成带参数的二维码
参数: data – 你要发送的参数 dict 返回: 返回的 JSON 数据包
删除自定义菜单。 详情请参考 http://mp.weixin.qq.com/wiki/index.php?title=自定义菜单删除接口
返回: 返回的 JSON 数据包
-
download_media
(media_id)¶ 下载多媒体文件。 详情请参考 http://mp.weixin.qq.com/wiki/index.php?title=上传下载多媒体文件
参数: media_id – 媒体文件 ID 返回: requests 的 Response 实例
-
get_access_token
()¶ 判断现有的token是否过期。 用户需要多进程或者多机部署可以手动重写这个函数 来自定义token的存储,刷新策略。
:return:返回token
-
get_followers
(first_user_id=None)¶ 获取关注者列表 详情请参考 http://mp.weixin.qq.com/wiki/index.php?title=获取关注者列表
参数: first_user_id – 可选。第一个拉取的OPENID,不填默认从头开始拉取 返回: 返回的 JSON 数据包
-
get_group_by_id
(openid)¶ 查询用户所在分组 详情请参考 http://mp.weixin.qq.com/wiki/index.php?title=分组管理接口
参数: openid – 用户的OpenID 返回: 返回的 JSON 数据包
-
get_groups
()¶ 查询所有分组 详情请参考 http://mp.weixin.qq.com/wiki/index.php?title=分组管理接口
返回: 返回的 JSON 数据包
查询自定义菜单。 详情请参考 http://mp.weixin.qq.com/wiki/index.php?title=自定义菜单查询接口
返回: 返回的 JSON 数据包
-
get_user_info
(user_id, lang='zh_CN')¶ 获取用户基本信息 详情请参考 http://mp.weixin.qq.com/wiki/index.php?title=获取用户基本信息
参数: - user_id – 用户 ID 。 就是你收到的 Message 的 source
- lang – 返回国家地区语言版本,zh_CN 简体,zh_TW 繁体,en 英语
返回: 返回的 JSON 数据包
-
grant_token
()¶ 获取 Access Token 。 详情请参考 http://mp.weixin.qq.com/wiki/index.php?title=通用接口文档
返回: 返回的 JSON 数据包
-
move_user
(user_id, group_id)¶ 移动用户分组 详情请参考 http://mp.weixin.qq.com/wiki/index.php?title=分组管理接口
参数: - user_id – 用户 ID 。 就是你收到的 Message 的 source
- group_id – 分组 ID
返回: 返回的 JSON 数据包
-
send_article_message
(user_id, articles)¶ 发送图文消息 详情请参考 http://mp.weixin.qq.com/wiki/index.php?title=发送客服消息
参数: - user_id – 用户 ID 。 就是你收到的 Message 的 source
- articles – 一个包含至多10个
Article
实例的数组
返回: 返回的 JSON 数据包
-
send_image_message
(user_id, media_id)¶ 发送图片消息 详情请参考 http://mp.weixin.qq.com/wiki/index.php?title=发送客服消息
参数: - user_id – 用户 ID 。 就是你收到的 Message 的 source
- media_id – 图片的媒体ID。 可以通过
upload_media()
上传。
返回: 返回的 JSON 数据包
-
send_music_message
(user_id, url, hq_url, thumb_media_id, title=None, description=None)¶ 发送音乐消息 详情请参考 http://mp.weixin.qq.com/wiki/index.php?title=发送客服消息
参数: - user_id – 用户 ID 。 就是你收到的 Message 的 source
- url – 音乐链接
- hq_url – 高品质音乐链接,wifi环境优先使用该链接播放音乐
- thumb_media_id – 缩略图的媒体ID。 可以通过
upload_media()
上传。 - title – 音乐标题
- description – 音乐描述
返回: 返回的 JSON 数据包
-
send_template_message
(user_id, template_id, data, url='')¶ 发送模板消息 详情请参考 http://mp.weixin.qq.com/wiki/17/304c1885ea66dbedf7dc170d84999a9d.html
参数: - user_id – 用户 ID 。 就是你收到的 Message 的 source
- template_id – 模板 ID。
- data – 用于渲染模板的数据。
- url – 模板消息的可选链接。
返回: 返回的 JSON 数据包
-
send_text_message
(user_id, content)¶ 发送文本消息 详情请参考 http://mp.weixin.qq.com/wiki/index.php?title=发送客服消息
参数: - user_id – 用户 ID 。 就是你收到的 Message 的 source
- content – 消息正文
返回: 返回的 JSON 数据包
-
send_video_message
(user_id, media_id, title=None, description=None)¶ 发送视频消息 详情请参考 http://mp.weixin.qq.com/wiki/index.php?title=发送客服消息
参数: - user_id – 用户 ID 。 就是你收到的 Message 的 source
- media_id – 发送的视频的媒体ID。 可以通过
upload_media()
上传。 - title – 视频消息的标题
- description – 视频消息的描述
返回: 返回的 JSON 数据包
-
send_voice_message
(user_id, media_id)¶ 发送语音消息 详情请参考 http://mp.weixin.qq.com/wiki/index.php?title=发送客服消息
参数: - user_id – 用户 ID 。 就是你收到的 Message 的 source
- media_id – 发送的语音的媒体ID。 可以通过
upload_media()
上传。
返回: 返回的 JSON 数据包
-
show_qrcode
(ticket)¶ 通过ticket换取二维码 详情请参考 http://mp.weixin.qq.com/wiki/index.php?title=生成带参数的二维码
参数: ticket – 二维码 ticket 。可以通过 create_qrcode()
获取到返回: 返回的 Request 对象
-
update_group
(group_id, name)¶ 修改分组名 详情请参考 http://mp.weixin.qq.com/wiki/index.php?title=分组管理接口
参数: - group_id – 分组id,由微信分配
- name – 分组名字(30个字符以内)
返回: 返回的 JSON 数据包
-
upload_media
(media_type, media_file)¶ 上传多媒体文件。 详情请参考 http://mp.weixin.qq.com/wiki/index.php?title=上传下载多媒体文件
参数: - media_type – 媒体文件类型,分别有图片(image)、语音(voice)、视频(video)和缩略图(thumb)
- media_file – 要上传的文件,一个 File-object
返回: 返回的 JSON 数据包
-
部署¶
在独立服务器上部署¶
当你运行 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 支持以下几种:
- cgi
- flup
- wsgiref
- waitress
- cherrypy
- paste
- fapws3
- tornado
- gae
- twisted
- diesel
- meinheld
- gunicorn
- eventlet
- gevent
- rocket
- bjoern
- auto
当 server 为 auto 时, WeRoBot 会自动依次尝试以下几种服务器:
- Waitress
- Paste
- Twisted
- CherryPy
- WSGIRef
所以,只要你安装了相应的服务器软件,就可以使用 werobot.run
直接跑在生产环境下。
注解
server 的默认值为 auto
使用 Supervisor 管理守护进程¶
请注意, 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
使用 Nginx 进行反向代理¶
微信服务器只支持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;
}
}
注解
在这个例子中, WeRoBot 的端口号为 12233。你应该在微信管理后台中将服务器地址设为 http://example.com
。
贡献指南¶
欢迎所有人为 WeRoBot
贡献。如果你打算为 WeRoBot
项目贡献代码, 请仔细阅读这份贡献指南。
贡献代码¶
若要贡献代码, 请注意使用 GitHub
的 workflow 。
标准的做法应该先 Fork 这个项目到自己的 Repo, 然后从 develop
分支创建一个新的分支。
当一切开发完成之后, 可以发 Pull Request 到 develop
分支, 我们会为你的代码做 Review。同时 CI 也会为合并之后的分支运行测试。
如果一切没有问题, 我们将合并你的代码到 develop
分支, 并最终发布在 master
分支的稳定版本。
注解
以下的内容是为 Linux / macOS 操作系统而写的。 如果你使用 Windows 进行开发,可能会遇到一些问题。
环境搭建¶
建议使用 virtualenv
创建虚拟环境进行开发, 然后安装开发环境需要的 packages。
关于 Python 版本, 推荐使用 Python 3.5 进行开发。
如果使用的是 3.5 版本
# Python 3.5
python -m venv venv
如果是其他版本
# virtualenv is highly recommended.
virtualenv venv
# Activate virtualenv.
source venv/bin/activate
# Install dev packages.
pip install -r dev-requirements.txt
代码风格¶
请遵循 PEP8
标准进行代码书写。
https://www.python.org/dev/peps/pep-0008/
为了统一代码风格我们推荐使用 flake8
进行代码风格检查, 并为代码提交添加钩子。
# Install git hook for flake8.
flake8 --install-hook
# flake8 will automatically run before commit.
添加钩子之后会在每次代码提交时运行 flake8
进行检查。
若要单独运行 flake8
。
# Run flake8 immediately.
flake8 werobot
测试¶
在代码提交之前, 请先运行本地的测试。每次提交之后会有在线的 CI 运行更多版本兼容性的测试, 请密切关注测试结果。
# Run tests locally.
python setup.py test
当然也可以使用 tox 在本地运行多版本的兼容性测试。
# Run multi-version tests locally.
tox
另外请为自己新添加的模块或者功能编写测试代码, 所有的测试文件都在 tests 文件夹下。
Changelog¶
Version 1.0.0¶
- 增加对消息加解密的支持
- 重写 werobot.messages, 完善对 Event 的支持
- 将微信消息的 id 属性重命名为 message_id
- 增加
werobot.reply.SuccessReply
- 增加
werobot.reply.ImageReply
- 增加
werobot.reply.VoiceReply
- 增加
werobot.reply.VideoReply
- 删除
werobot.reply.create_reply()
- 为
werobot.reply.WeChatReply
增加process_args
方法 - 为
werobot.robot.BaseRoBot
增加parse_message
方法 - 为
werobot.robot.BaseRoBot
增加get_encrypted_reply
方法 - 删去了 Reply 中过时的 flag
- 修复
werobot.session.filestorage.FileStorage
在 PyPy 下的兼容性问题 - 增加
werobot.session.sqlitestorage.SQLiteStorage
- 将默认的 SessionBackend 切换为
werobot.session.sqlitestorage.SQLiteStorage
- 将图文消息单个消息的渲染函数放到
werobot.replies.Article
内 - 取消对 Python2.6, Python3.3 的支持
- 增加与 Django 1.6+, Flask, Bottle, Tornado 集成的支持
- 替换 inspect.getargspec()
Version 0.6.1¶
- Fix wrong URL in
upload_media
- Add VideoMessage
Version 0.6.0¶
- Add
@werobot.filter
- Add
werobot.session.saekvstorage
- Add support for Weixin Pay (
werobot.pay.WeixinPayClient
) - Add
werobot.reply.TransferCustomerServiceReply
- Fix FileStorage’s bug
Version 0.5.3¶
- Fix: can’t handle request for root path
Version 0.5.2¶
- Fix Python 3 support
Version 0.5.1¶
- Fix typo
Version 0.5.0¶
- Add
werobot.client
- Add
werobot.config
- Add
werobot.logger
- Add
@werobot.key_click
(Thanks @tg123) - Support Location Event
- Use smart args
- Friendly 403 page
- Improved server support
- Enable session by default.
- Drop
werobot.testing.make_text_message
- Drop
werobot.testing.make_image_message
- Drop
werobot.testing.make_location_message
- Drop
werobot.testing.make_voice_message
- Drop
werobot.testing.WeTest.send
- Rewrite
werobot.message
- Rewrite testing case
Version 0.4.1¶
- Add VoiceMessage
- Add
message.raw
: Raw XML of message - Rename
UnknownMessage.content
toUnknownMessage.raw
- Fix a bug when signature is invalid.
- Ignore session when receive UnknownMessage
Version 0.4.0¶
- Add session support
- Add logging support
- Rename
werobot.test
towerobot.testing
- Handlers added by
@robot.handler
will have the lowest priority.
Version 0.3.5¶
- Bug fix: Make
BaseRoBot
importable
Version 0.3.4¶
- Rename
WeRoBot.app
toWeRoBot.wsgi
- Add
BaseRoBot
class. It’s useful for creating extensions. - Reorganized documents.
Version 0.3.3¶
- Add
host
param in werobot.run - Update EventMessage
- Add LinkMessage
Version 0.3.1¶
- Add
server
param in werobot.run
Version 0.3.0¶
- Add new messages and replies support for WeChat 4.5