微信公众平台 Python 开发包文档

文档已经转移到新地址: http://wechat-python-sdk.com/

非官方微信公众平台 Python 开发包,包括官方接口和非官方接口。

  • 官方接口依据公众平台开发者文档编写,可以实现公众平台开发者文档中的所有内容,具体不列举,请查看 WechatBasic 文档;

  • 非官方接口采用模拟登陆的方式,可以实现更多高级功能,但也存在相应风险。

    目前提供的非官方接口功能有:

    • 主动对指定用户发送文本消息
    • 主动对指定用户发送图片消息
    • 主动对指定用户发送语音消息
    • 主动对指定用户发送视频消息
    • 获取指定用户的个人信息
    • 获取用户列表
    • 获取分组列表
    • 获取图文信息列表
    • 获取与指定用户的对话内容
    • 向指定用户发送图文消息(必须从图文库里选取消息ID传入)
    • 在素材库中创建图文消息
    • 上传素材至素材库 (图片/语音/视频)
    • 向特定用户发送媒体文件 (图片/语音/视频)
    • 获取素材库文件列表
    • 获取用户头像
    • 获取新消息的数目
    • 获取最新一条消息
    • 获取消息列表
    • 根据消息ID获取图片消息内容
    • 根据消息ID获取语音消息内容
    • 根据消息ID获取视频消息内容
    • 获取图文分析信息

请注意:本开发包并不打算提供一个独立的完整微信解决方案,我们更希望这个开发包可以非常融洽的在各个框架中进行集成并使用,对于HTTP请求及响应方面并不涉及,该开发包仅仅接受必要参数,提供各种微信操作的方法,并返回相应的可以响应微信服务器的数据(Response)或操作执行结果。

项目地址:https://github.com/wechat-python-sdk/wechat-python-sdk

目录:

安装

文档已经转移到新地址: http://wechat-python-sdk.com/

自动安装

可以通过 pip 进行安装:

pip install wechat-sdk

也可以通过 easy_install 进行安装:

easy_install wechat-sdk

手动安装

在终端下输入下列命令:

wget https://github.com/wechat-python-sdk/wechat-python-sdk/archive/master.tar.gz
tar zvxf master.tar.gz
cd wechat-python-sdk-master
python setup.py build
python setup.py install

快速上手

文档已经转移到新地址: http://wechat-python-sdk.com/

本页内容提供了一些可以快速上手的短小示例代码,并假设你已经安装了 wechat-sdk 。如果还没有,请返回安装一节进行安装。

注意事项

因为本开发包并不打算接管 HTTP 请求及响应阶段,包括微信服务器 Request 参数的提取、Request Body 的提取、返回 Response 这些操作请自行完成,本页示例中假设开发包所需要的各个参数都已经提取完毕并且最后得到的响应内容会被返回。

关于字符串中的中文问题,请保证所有在代码中出现的包含汉字的字符串均为 unicode 类型,微信服务器发送过来的 Request Body 不受此限制,请注意下面的代码中关于字符串类型的地方。

官方接口 - 基本回复使用方法

第一个例子(examples/tutorial_official_1.py),根据用户发送的内容返回用户发送内容的类型文字说明,比如用户发送了一张图片,则返回“图片”,发送了一段文字,则返回“文字”。

这里附加一个操作,当用户发送的是文字并且内容为“wechat”时返回“^_^”笑脸符号。

# -*- coding: utf-8 -*-

from wechat_sdk import WechatBasic


# 下面这些变量均假设已由 Request 中提取完毕
token = 'WECHAT_TOKEN'  # 你的微信 Token
signature = 'f24649c76c3f3d81b23c033da95a7a30cb7629cc'  # Request 中 GET 参数 signature
timestamp = '1406799650'  # Request 中 GET 参数 timestamp
nonce = '1505845280'  # Request 中 GET 参数 nonce
# 用户的请求内容 (Request 中的 Body)
# 请更改 body_text 的内容来测试下面代码的执行情况
body_text = """
<xml>
<ToUserName><![CDATA[touser]]></ToUserName>
<FromUserName><![CDATA[fromuser]]></FromUserName>
<CreateTime>1405994593</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[wechat]]></Content>
<MsgId>6038700799783131222</MsgId>
</xml>
"""

# 实例化 wechat
wechat = WechatBasic(token=token)
# 对签名进行校验
if wechat.check_signature(signature=signature, timestamp=timestamp, nonce=nonce):
    # 对 XML 数据进行解析 (必要, 否则不可执行 response_text, response_image 等操作)
    wechat.parse_data(body_text)
    # 获得解析结果, message 为 WechatMessage 对象 (wechat_sdk.messages中定义)
    message = wechat.get_message()

    response = None
    if message.type == 'text':
        if message.content == 'wechat':
            response = wechat.response_text(u'^_^')
        else:
            response = wechat.response_text(u'文字')
    elif message.type == 'image':
        response = wechat.response_text(u'图片')
    else:
        response = wechat.response_text(u'未知')

    # 现在直接将 response 变量内容直接作为 HTTP Response 响应微信服务器即可,此处为了演示返回内容,直接将响应进行输出
    print response

第二个例子(examples/tutorial_official_2.py),假如用户输入“新闻”,则服务器响应一段预设的多图文

# -*- coding: utf-8 -*-

from wechat_sdk import WechatBasic


# 下面这些变量均假设已由 Request 中提取完毕
token = 'WECHAT_TOKEN'  # 你的微信 Token
signature = 'f24649c76c3f3d81b23c033da95a7a30cb7629cc'  # Request 中 GET 参数 signature
timestamp = '1406799650'  # Request 中 GET 参数 timestamp
nonce = '1505845280'  # Request 中 GET 参数 nonce
# 用户的请求内容 (Request 中的 Body)
# 请更改 body_text 的内容来测试下面代码的执行情况
body_text = """
<xml>
<ToUserName><![CDATA[touser]]></ToUserName>
<FromUserName><![CDATA[fromuser]]></FromUserName>
<CreateTime>1405994593</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[新闻]]></Content>
<MsgId>6038700799783131222</MsgId>
</xml>
"""

# 实例化 wechat
wechat = WechatBasic(token=token)
# 对签名进行校验
if wechat.check_signature(signature=signature, timestamp=timestamp, nonce=nonce):
    # 对 XML 数据进行解析 (必要, 否则不可执行 response_text, response_image 等操作)
    wechat.parse_data(body_text)
    # 获得解析结果, message 为 WechatMessage 对象 (wechat_sdk.messages中定义)
    message = wechat.get_message()

    response = None
    if message.type == 'text' and message.content == u'新闻':
        response = wechat.response_news([
            {
                'title': u'第一条新闻标题',
                'description': u'第一条新闻描述,这条新闻没有预览图',
                'url': u'http://www.google.com.hk/',
            }, {
                'title': u'第二条新闻标题, 这条新闻无描述',
                'picurl': u'http://doraemonext.oss-cn-hangzhou.aliyuncs.com/test/wechat-test.jpg',
                'url': u'http://www.github.com/',
            }, {
                'title': u'第三条新闻标题',
                'description': u'第三条新闻描述',
                'picurl': u'http://doraemonext.oss-cn-hangzhou.aliyuncs.com/test/wechat-test.jpg',
                'url': u'http://www.v2ex.com/',
            }
        ])

    # 现在直接将 response 变量内容直接作为 HTTP Response 响应微信服务器即可,此处为了演示返回内容,直接将响应进行输出
    print response

官方接口 - 如何判断消息的类型

微信服务器发来的POST请求可能会有文字/语音/图片/视频/链接/地理位置/事件,对于如何判定自己通过 get_message() 获得到的 WechatMessage 对象类型,这里提供一个示例代码(为了简洁起见,代码中出现的 token signature timestamp nonce body_text 均已从 HTTP Request 中提取完毕,具体形式可参照上面的代码,这里不再重复):

# -*- coding: utf-8 -*-

from wechat_sdk import WechatBasic
from wechat_sdk.messages import (
    TextMessage, VoiceMessage, ImageMessage, VideoMessage, LinkMessage, LocationMessage, EventMessage
)


# 下面这些变量均假设已由 Request 中提取完毕
# token, signature, timestamp, nonce, body_text

# 实例化 wechat
wechat = WechatBasic(token=token)
# 对签名进行校验
if wechat.check_signature(signature=signature, timestamp=timestamp, nonce=nonce):
    # 对 XML 数据进行解析 (必要, 否则不可执行 response_text, response_image 等操作)
    wechat.parse_data(body_text)
    # 获得解析结果, message 为 WechatMessage 对象 (wechat_sdk.messages中定义)
    message = wechat.get_message()

    response = None
    if isinstance(message, TextMessage):
        response = wechat.response_text(content=u'文字信息')
    elif isinstance(message, VoiceMessage):
        response = wechat.response_text(content=u'语音信息')
    elif isinstance(message, ImageMessage):
        response = wechat.response_text(content=u'图片信息')
    elif isinstance(message, VideoMessage):
        response = wechat.response_text(content=u'视频信息')
    elif isinstance(message, LinkMessage):
        response = wechat.response_text(content=u'链接信息')
    elif isinstance(message, LocationMessage):
        response = wechat.response_text(content=u'地理位置信息')
    elif isinstance(message, EventMessage):  # 事件信息
        if message.type == 'subscribe':  # 关注事件(包括普通关注事件和扫描二维码造成的关注事件)
            if message.key and message.ticket:  # 如果 key 和 ticket 均不为空,则是扫描二维码造成的关注事件
                response = wechat.response_text(content=u'用户尚未关注时的二维码扫描关注事件')
            else:
                response = wechat.response_text(content=u'普通关注事件')
        elif message.type == 'unsubscribe':
            response = wechat.response_text(content=u'取消关注事件')
        elif message.type == 'scan':
            response = wechat.response_text(content=u'用户已关注时的二维码扫描事件')
        elif message.type == 'location':
            response = wechat.response_text(content=u'上报地理位置事件')
        elif message.type == 'click':
            response = wechat.response_text(content=u'自定义菜单点击事件')
        elif message.type == 'view':
            response = wechat.response_text(content=u'自定义菜单跳转链接事件')
        elif message.type == 'templatesendjobfinish':
            response = wechat.response_text(content=u'模板消息事件')

    # 现在直接将 response 变量内容直接作为 HTTP Response 响应微信服务器即可,此处为了演示返回内容,直接将响应进行输出
    print response

非官方接口 - 基本用法

第一个例子(examples/tutorial_unofficial_1.py),展示了几个直接获取信息的函数的用法,至于具体的返回值所包含的内容,请查看 WechatExt 文档

# -*- coding: utf-8

import json

from wechat_sdk import WechatExt


wechat = WechatExt(username='username', password='password')

# 获取未分组中所有的用户成员
user_list = wechat.get_user_list()
print user_list
print '==================================='

# 获取分组列表
group_list = wechat.get_group_list()
print group_list
print '==================================='

# 获取图文信息列表
news_list = wechat.get_news_list(page=0, pagesize=15)
print news_list
print '==================================='

# 获取与最新一条消息用户的对话内容
user_info_json = wechat.get_top_message()
user_info = json.loads(user_info_json)
print wechat.get_dialog_message(fakeid=user_info['msg_item'][0]['fakeid'])

微信官方接口操作 WechatBasic

文档已经转移到新地址: http://wechat-python-sdk.com/

class wechat_sdk.basic.WechatBasic(token=None, appid=None, appsecret=None, partnerid=None, partnerkey=None, paysignkey=None, access_token=None, access_token_expires_at=None, jsapi_ticket=None, jsapi_ticket_expires_at=None, checkssl=False)

微信基本功能类

参数:
  • token (str) – 微信 Token
  • appid (str) – App ID
  • appsecret (str) – App Secret
  • partnerid (str) – 财付通商户身份标识, 支付权限专用
  • partnerkey (str) – 财付通商户权限密钥 Key, 支付权限专用
  • paysignkey (str) – 商户签名密钥 Key, 支付权限专用
  • access_token (str) – 直接导入的 access_token 值, 该值需要在上一次该类实例化之后手动进行缓存并在此处传入, 如果不传入, 将会在需要时自动重新获取
  • access_token_expires_at (str) – 直接导入的 access_token 的过期日期,该值需要在上一次该类实例化之后手动进行缓存并在此处传入, 如果不传入, 将会在需要时自动重新获取
  • jsapi_ticket (str) – 直接导入的 jsapi_ticket 值, 该值需要在上一次该类实例化之后手动进行缓存并在此处传入, 如果不传入, 将会在需要时自动重新获取
  • jsapi_ticket_expires_at (str) – 直接导入的 jsapi_ticket 的过期日期,该值需要在上一次该类实例化之后手动进行缓存并在此处传入, 如果不传入, 将会在需要时自动重新获取
  • checkssl (boolean) – 是否检查 SSL, 默认为 False, 可避免 urllib3 的 InsecurePlatformWarning 警告

实例化说明:

  1. 当实例化 WechatBasic 时,你可以传递上述参数说明中任意多个参数进去,但是传递参数不足将会在使用部分功能时引发对应的异常。
虽然认证订阅号、未认证服务号拥有 appid 及 appsecret,但不代表其能调用高级接口 ,这两种类型的账号仅能进行自定义菜单及JS相关操作,进行其他权限外操作仍然会抛出异常 OfficialAPIError
  1. 详细说明一下 access_token, access_token_expires_at, jsapi_ticket, jsapi_ticket_expires_at 参数的传入问题:

因为此开发包并不打算以服务器的方式常驻,所以,每次请求均会重新实例化 WechatBasic ,而微信的 access_tokenjsapi_ticket 的有效期为 7200 秒,不可能每次实例化的时候去重新获取,所以需要你以你自己的方式去保存上一次请求中实例化后的 WechatBasicaccess_token, access_token_expires_at, jsapi_ticket, jsapi_ticket_expires_at 参数,并在下一次的实例化的过程中传入,以此来保证 access_tokenjsapi_ticket 的持久性。

获取 access_tokenaccess_token_expires_at 的方式为调用 get_access_token() 方法

获取 jsapi_ticketjsapi_ticket_expires_at 的方式为调用 get_jsapi_ticket() 方法

下一版本将会考虑更为简单通用的方法,在新版本发布之前,请用你自己的方式把得到的 access_token, access_token_expires_at, jsapi_ticket, jsapi_ticket_expires_at 保存起来,不管是文件,缓存还是数据库都可以,获取它们的时间可以非常自由,不管是刚刚实例化完成还是得到响应结果之后都没有问题,在调用对应函数时如果没有 access_tokenjsapi_ticket 的话会自动获取的 :)

check_signature(signature, timestamp, nonce)

验证微信消息真实性

运行时检查:token

可用公众号类型:认证/未认证订阅号, 认证/未认证服务号

参数:
  • signature (str) – 微信加密签名
  • timestamp (str) – 时间戳
  • nonce (str) – 随机数
返回:

通过验证返回 True, 未通过验证返回 False

generate_jsapi_signature(timestamp, noncestr, url, jsapi_ticket=None)

使用 jsapi_ticket 对 url 进行签名

当未提供 jsapi_ticket 参数时检查:appid, appsecret

可用公众号类型:认证/未认证订阅号,认证/未认证服务号

参数:
  • timestamp (str) – 时间戳
  • noncestr (str) – 随机数
  • url (str) – 要签名的 url,不包含 # 及其后面部分
  • jsapi_ticket (str) – (可选参数) jsapi_ticket 值 (如不提供将自动通过 appid 和 appsecret 获取)
返回:

返回 sha1 签名的 hexdigest 值

parse_data(data)

解析微信服务器发送过来的数据并保存类中

运行时检查:无

可用公众号类型:认证/未认证订阅号, 认证/未认证服务号

参数:data (str) – HTTP Request 的 Body 数据
Raises:ParseError 解析微信服务器数据错误, 数据不合法
get_message()

获取解析好的 WechatMessage 对象

运行时检查:是否已调用 parse_data() 进行解析

可用公众号类型:认证/未认证订阅号, 认证/未认证服务号

返回:解析好的 WechatMessage 对象
message

功能同 get_message()

get_access_token()

获取 Access Token 及 Access Token 过期日期, 仅供缓存使用, 如果希望得到原生的 Access Token 请求数据请使用 grant_token()

运行时检查:appid, appsecret

可用公众号类型:认证订阅号, 认证/未认证服务号

返回:dict 对象, key 包括 access_tokenaccess_token_expires_at
get_jsapi_ticket()

获取 Jsapi Ticket 及 Jsapi Ticket 过期日期, 仅供缓存使用, 如果希望得到原生的 Jsapi Ticket 请求数据请使用 grant_jsapi_ticket()

运行时检查:appid, appsecret

可用公众号类型:认证/未认证订阅号, 认证/未认证服务号

返回:dict 对象, key 包括 jsapi_ticketjsapi_ticket_expires_at
response_text(content, escape=False)

将文字信息 content 组装为符合微信服务器要求的响应数据

运行时检查:是否已调用 parse_data() 进行解析

可用公众号类型:认证/未认证订阅号, 认证/未认证服务号

参数:
  • content (str) – 回复文字
  • escape (boolean) – 是否转义该文本内容 (默认不转义)
返回:

符合微信服务器要求的 XML 响应数据

response_image(media_id)

将 media_id 所代表的图片组装为符合微信服务器要求的响应数据

运行时检查:是否已调用 parse_data() 进行解析

可用公众号类型:认证/未认证订阅号, 认证/未认证服务号

参数:media_id (str) – 图片的 MediaID
返回:符合微信服务器要求的 XML 响应数据
response_voice(media_id)

将 media_id 所代表的语音组装为符合微信服务器要求的响应数据

运行时检查:是否已调用 parse_data() 进行解析

可用公众号类型:认证/未认证订阅号, 认证/未认证服务号

参数:media_id (str) – 语音的 MediaID
返回:符合微信服务器要求的 XML 响应数据
response_video(media_id[, title=None, description=None])

将 media_id 所代表的视频组装为符合微信服务器要求的响应数据

运行时检查:是否已调用 parse_data() 进行解析

可用公众号类型:认证/未认证订阅号, 认证/未认证服务号

参数:
  • media_id (str) – 视频的 MediaID
  • title (str) – 视频消息的标题
  • description (str) – 视频消息的描述
返回:

符合微信服务器要求的 XML 响应数据

response_music(music_url[, title=None, description=None, hq_music_url=None, thumb_media_id=None])

将音乐信息组装为符合微信服务器要求的响应数据

运行时检查:是否已调用 parse_data() 进行解析

可用公众号类型:认证/未认证订阅号, 认证/未认证服务号

参数:
  • music_url (str) – 音乐链接
  • title (str) – 音乐标题
  • description (str) – 音乐描述
  • hq_music_url (str) – 高质量音乐链接, WIFI环境优先使用该链接播放音乐
  • thumb_media_id (str) – 缩略图的 MediaID
返回:

符合微信服务器要求的 XML 响应数据

response_news(articles)

将新闻信息组装为符合微信服务器要求的响应数据

运行时检查:是否已调用 parse_data() 进行解析

可用公众号类型:认证/未认证订阅号, 认证/未认证服务号

参数:articles (list) – list 对象, 每个元素为一个 dict 对象, key 包含 title, description, picurl, url
返回:符合微信服务器要求的 XML 响应数据
grant_token(override=True)

获取 Access Token

运行时检查:appid, appsecret

可用公众号类型:认证订阅号, 认证/未认证服务号

详情请参考 http://mp.weixin.qq.com/wiki/11/0e4b294685f817b95cbed85ba5e82b8f.html

参数:override (boolean) – 是否在获取的同时覆盖已有 access_token (默认为True)
返回:返回的 JSON 数据包
grant_jsapi_ticket(override=True)

获取 Jsapi Ticket

运行时检查:appid, appsecret

可用公众号类型:认证/未认证订阅号, 认证/未认证服务号

详情请参考 http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html#.E9.99.84.E5.BD.951-JS-SDK.E4.BD.BF.E7.94.A8.E6.9D.83.E9.99.90.E7.AD.BE.E5.90.8D.E7.AE.97.E6.B3.95

参数:override (boolean) – 是否在获取的同时覆盖已有 jsapi_ticket (默认为True)
返回:返回的 JSON 数据包
create_menu(menu_data)

创建自定义菜单

# -*- coding: utf-8 -*-
wechat = WechatBasic(appid='appid', appsecret='appsecret')
wechat.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/13/43de8269be54a0a6f64413e4dfa94f39.html

请注意中文请使用 unicode 形式, 如上面的示例

运行时检查:appid, appsecret

可用公众号类型:认证订阅号, 认证/未认证服务号

参数:menu_data (dict) – Python 字典
返回:返回的 JSON 数据包
get_menu()

查询自定义菜单

详情请参考 http://mp.weixin.qq.com/wiki/16/ff9b7b85220e1396ffa16794a9d95adc.html

运行时检查:appid, appsecret

可用公众号类型:认证订阅号, 认证/未认证服务号

返回:返回的 JSON 数据包
delete_menu()

删除自定义菜单

详情请参考 http://mp.weixin.qq.com/wiki/16/8ed41ba931e4845844ad6d1eeb8060c8.html

运行时检查:appid, appsecret

可用公众号类型:认证订阅号, 认证/未认证服务号

返回:返回的 JSON 数据包
upload_media(media_type, media_file, extension='')

上传多媒体文件

详情请参考 http://mp.weixin.qq.com/wiki/10/78b15308b053286e2a66b33f0f0f5fb6.html

运行时检查:appid, appsecret

可用公众号类型:认证服务号

参数:
  • media_type (str) – 媒体文件类型,分别有图片(image)、语音(voice)、视频(video)和缩略图(thumb)
  • media_file (object) – 要上传的文件,一个 File object 或 StringIO object
  • extension (str) – 如果 media_file 传入的为 StringIO object,那么必须传入 extension 显示指明该媒体文件扩展名,如 mp3, amr;如果 media_file 传入的为 File object,那么该参数请留空
返回:

返回的 JSON 数据包

download_media(media_id)

下载多媒体文件

如果希望将返回的多媒体文件以文件的形式进行保存,提供一个代码示例:

wechat = WechatBasic(appid='appid', appsecret='appsecret')
response = wechat.download_media('your media id')
with open('yourfilename', 'wb') as fd:
    for chunk in response.iter_content(1024):
        fd.write(chunk)

详情请参考 http://mp.weixin.qq.com/wiki/10/78b15308b053286e2a66b33f0f0f5fb6.html

运行时检查:appid, appsecret

可用公众号类型:认证服务号

参数:media_id (str) – 媒体文件 ID
返回:requests 的 Response 实例 (具体请参考 http://docs.python-requests.org/en/latest/)
create_group(name)

创建分组

详情请参考 http://mp.weixin.qq.com/wiki/13/be5272dc4930300ba561d927aead2569.html

运行时检查:appid, appsecret

可用公众号类型:认证服务号

参数:name (str) – 分组名字(30个字符以内)
返回:返回的 JSON 数据包
get_groups()

查询所有分组

详情请参考 http://mp.weixin.qq.com/wiki/13/be5272dc4930300ba561d927aead2569.html

运行时检查:appid, appsecret

可用公众号类型:认证服务号

返回:返回的 JSON 数据包
get_group_by_id(openid)

查询用户所在分组

详情请参考 http://mp.weixin.qq.com/wiki/13/be5272dc4930300ba561d927aead2569.html

运行时检查:appid, appsecret

可用公众号类型:认证服务号

参数:openid (str) – 用户的OpenID
返回:返回的 JSON 数据包
update_group(group_id, name)

修改分组名

详情请参考 http://mp.weixin.qq.com/wiki/13/be5272dc4930300ba561d927aead2569.html

运行时检查:appid, appsecret

可用公众号类型:认证服务号

参数:
  • group_id (integer) – 分组id,由微信分配
  • name (str) – 分组名字(30个字符以内)
返回:

返回的 JSON 数据包

move_user(user_id, group_id)

移动用户分组

详情请参考 http://mp.weixin.qq.com/wiki/13/be5272dc4930300ba561d927aead2569.html

运行时检查:appid, appsecret

可用公众号类型:认证服务号

参数:
  • user_id (str) – 用户 ID, 就是你收到的 WechatMessage 的 source
  • group_id (str) – 分组 ID
返回:

返回的 JSON 数据包

get_user_info(user_id[, lang='zh_CN'])

获取用户基本信息

详情请参考 http://mp.weixin.qq.com/wiki/14/bb5031008f1494a59c6f71fa0f319c66.html

运行时检查:appid, appsecret

可用公众号类型:认证服务号

参数:
  • user_id (str) – 用户 ID, 就是你收到的 WechatMessage 的 source
  • lang (str) – 返回国家地区语言版本,zh_CN 简体,zh_TW 繁体,en 英语
返回:

返回的 JSON 数据包

get_followers(first_user_id=None)

获取关注者列表

详情请参考 http://mp.weixin.qq.com/wiki/3/17e6919a39c1c53555185907acf70093.html

运行时检查:appid, appsecret

可用公众号类型:认证服务号

参数:first_user_id (str) – 可选。第一个拉取的OPENID,不填默认从头开始拉取
返回:返回的 JSON 数据包
send_text_message(user_id, content)

发送文本消息

详情请参考 http://mp.weixin.qq.com/wiki/7/12a5a320ae96fecdf0e15cb06123de9f.html

运行时检查:appid, appsecret

可用公众号类型:认证服务号

参数:
  • user_id (str) – 用户 ID, 就是你收到的 WechatMessage 的 source
  • content (str) – 消息正文
返回:

返回的 JSON 数据包

send_image_message(user_id, media_id)

发送图片消息

详情请参考 http://mp.weixin.qq.com/wiki/7/12a5a320ae96fecdf0e15cb06123de9f.html

运行时检查:appid, appsecret

可用公众号类型:认证服务号

参数:
  • user_id (str) – 用户 ID, 就是你收到的 WechatMessage 的 source
  • media_id (str) – 图片的媒体ID。 可以通过 upload_media() 上传。
返回:

返回的 JSON 数据包

send_voice_message(user_id, media_id)

发送语音消息

详情请参考 http://mp.weixin.qq.com/wiki/7/12a5a320ae96fecdf0e15cb06123de9f.html

运行时检查:appid, appsecret

可用公众号类型:认证服务号

参数:
  • user_id (str) – 用户 ID, 就是你收到的 WechatMessage 的 source
  • media_id (str) – 发送的语音的媒体ID。 可以通过 upload_media() 上传。
返回:

返回的 JSON 数据包

send_video_message(user_id, media_id [, title=None, description=None)

发送视频消息

详情请参考 http://mp.weixin.qq.com/wiki/7/12a5a320ae96fecdf0e15cb06123de9f.html

运行时检查:appid, appsecret

可用公众号类型:认证服务号

参数:
  • user_id (str) – 用户 ID, 就是你收到的 WechatMessage 的 source
  • media_id (str) – 发送的视频的媒体ID。 可以通过 upload_media() 上传。
  • title (str) – 视频消息的标题
  • description (str) – 视频消息的描述
返回:

返回的 JSON 数据包

send_music_message(user_id, url, hq_url, thumb_media_id[, title=None, description=None])

发送音乐消息

详情请参考 http://mp.weixin.qq.com/wiki/7/12a5a320ae96fecdf0e15cb06123de9f.html

运行时检查:appid, appsecret

可用公众号类型:认证服务号

参数:
  • user_id (str) – 用户 ID, 就是你收到的 WechatMessage 的 source
  • url (str) – 音乐链接
  • hq_url (str) – 高品质音乐链接,wifi环境优先使用该链接播放音乐
  • thumb_media_id (str) – 缩略图的媒体ID。 可以通过 upload_media() 上传。
  • title (str) – 音乐标题
  • description (str) – 音乐描述
返回:

返回的 JSON 数据包

send_article_message(user_id, articles)

发送图文消息

详情请参考 http://mp.weixin.qq.com/wiki/7/12a5a320ae96fecdf0e15cb06123de9f.html

运行时检查:appid, appsecret

可用公众号类型:认证服务号

参数:
  • user_id (str) – 用户 ID, 就是你收到的 WechatMessage 的 source
  • articles (list) – list 对象, 每个元素为一个 dict 对象, key 包含 title, description, picurl, url
返回:

返回的 JSON 数据包

create_qrcode(**data)

创建二维码

详情请参考 http://mp.weixin.qq.com/wiki/18/28fc21e7ed87bec960651f0ce873ef8a.html

运行时检查:appid, appsecret

可用公众号类型:认证服务号

参数:data (dict) – 你要发送的参数 dict
返回:返回的 JSON 数据包
show_qrcode(ticket)

通过ticket换取二维码

详情请参考 http://mp.weixin.qq.com/wiki/18/28fc21e7ed87bec960651f0ce873ef8a.html

运行时检查:appid, appsecret

可用公众号类型:认证服务号

参数:ticket (str) – 二维码 ticket 。可以通过 create_qrcode() 获取到
返回:返回的 Request 对象
set_template_industry(industry_id1, industry_id2)

设置所属行业

详情请参考 http://mp.weixin.qq.com/wiki/17/304c1885ea66dbedf7dc170d84999a9d.html

运行时检查:appid, appsecret

可用公众号类型:认证服务号

参数:
  • industry_id1 (str) – 主营行业代码
  • industry_id2 (str) – 副营行业代码
返回:

返回的 JSON 数据包

get_template_id(template_id_short):

获得模板ID

详情请参考 http://mp.weixin.qq.com/wiki/17/304c1885ea66dbedf7dc170d84999a9d.html

运行时检查:appid, appsecret

可用公众号类型:认证服务号

参数:template_id_short (str) – 模板库中模板的编号,有“TM**”和“OPENTMTM**”等形式
返回:返回的 JSON 数据包
send_template_message(user_id, template_id, data, url='', topcolor='#FF0000')

发送模版消息

详情请参考 http://mp.weixin.qq.com/wiki/17/304c1885ea66dbedf7dc170d84999a9d.html

运行时检查:appid, appsecret

可用公众号类型:认证服务号

注意参数中的 data 示例如下(请提供dict形式而不是字符串形式)::

{
    "first": {
       "value": "恭喜你购买成功!",
       "color": "#173177"
    },
    "keynote1":{
       "value": "巧克力",
       "color": "#173177"
    },
    "keynote2": {
       "value": "39.8元",
       "color": "#173177"
    },
    "keynote3": {
       "value": "2014年9月16日",
       "color": "#173177"
    },
    "remark":{
       "value": "欢迎再次购买!",
       "color": "#173177"
    }
}
参数:
  • user_id (str) – 用户 ID, 就是你收到的 WechatMessage 的 source (OpenID)
  • template_id (str) – 模板ID
  • data (dict) – 模板消息数据,示例如上
  • url (str) – 跳转地址 (默认为空)
  • topcolor (str) – 顶部颜色RGB值 (默认 #FF0000 )
返回:

返回的 JSON 数据包

微信非官方接口操作 WechatExt

文档已经转移到新地址: http://wechat-python-sdk.com/

class wechat_sdk.ext.WechatExt(username, password[, token=None, cookies=None, appid=None, plugin_token=None, ifencodepwd=False, login=True, checkssl=False])

微信扩展功能类

参数:
  • username (str) – 你的微信公众平台账户用户名
  • password (str) – 你的微信公众平台账户密码
  • token (str) – 直接导入的 token 值, 该值需要在上一次该类实例化之后手动进行缓存并在此传入, 如果不传入, 将会在实例化的时候自动获取
  • cookies (str) – 直接导入的 cookies 值, 该值需要在上一次该类实例化之后手动进行缓存并在此传入, 如果不传入, 将会在实例化的时候自动获取
  • appid (str) – 直接导入的 appid 值, 该值需要在上一次该类实例化之后手动进行缓存并在此传入, 如果不传入, 将会在调用 stat_ 开头的方法(统计分析类)时自动获取
  • plugin_token (str) – 直接导入的 plugin_token 值, 该值需要在上一次该类实例化之后手动进行缓存并在此传入, 如果不传入, 将会在调用 stat_ 开头的方法(统计分析类)时自动获取
  • ifencodepwd (boolean) – 密码是否已经经过编码, 如果密码已经经过加密, 此处为 True , 如果传入的密码为明文, 此处为 False
  • login (boolean) – 是否在实例化过程中尝试登录 (推荐此处设置为 False, 然后手动执行登录以方便进行识别验证码等操作, 此处默认值为 True 为兼容历史版本
  • checkssl (boolean) – 是否检查 SSL, 默认为 False, 可避免 urllib3 的 InsecurePlatformWarning 警告

实例化说明:

  1. 请注意实例化时的 login 参数,它的默认值为 True ,但这仅仅是为了兼容历史版本(v0.4.2及以前),在新版本中,强烈推荐将该参数设置为 False ,然后手动执行 login() 以有效应对可能出现的验证码问题。

  2. 当实例化 WechatExt 时,你必须传入 usernamepassword ,对于 tokencookies 参数,如果传入了它们,将会自动省略登录过程(无论 login 参数被设置为了 True 还是 False )。

  3. 请保证你的代码中会捕获 NeedLoginError 异常,一旦发生此异常,你需要重新调用 login() 方法登录来获取新的 tokencookies

  4. 详细说明一下 token 及 cookies 参数的传入问题:

    因为此开发包并不打算以服务器的方式常驻,所以,每次请求均会重新实例化 WechatExt ,所以需要你以你自己的方式去保存上一次请求中实例化后的 WechatExttokencookies 参数,并在下一次的实例化的过程中传入,以此来保证不会频繁登录。

    获取 tokencookies 的方式为调用 get_token_cookies() 方法

    下一版本将会考虑更为简单通用的方法,在新版本发布之前,请用你自己的方式把得到的 tokencookies 保存起来,不管是文件,缓存还是数据库都可以,只要在实例化后,你可以在任何时间调用 get_token_cookies() 方法。

  5. appidplugin_token 参数是用于统计分析类的方法的(以 stat_ 开头),如果不需要调用这些方法,可以无需理会这两个参数。

    它们和 tokencookies 一样,可由开发者自行缓存,获取它们的方式为调用 get_plugin_token_appid() 方法。唯一需要注意的是,如果传入了 appidplugin_token 参数,那么也必须要传入 tokencookies 参数,否则无效。

login(verify_code='')

登录微信公众平台

当你刚刚实例化 WechatExt 完或者捕获到 NeedLoginError 异常时,需要调用此方法进行登录或登录重试。

如何应对登录时的验证码:

默认情况下,如果微信服务器认为你的账号正常,那么直接调用一次 login() 就可以完成登录操作,但如果不幸出现了验证码,本方法会抛出 LoginVerifyCodeError 异常,这时你需要通过下面的 get_verify_code() 方法来获取验证码图片,然后通过你自己的方式识别这张图片并得出结果,并将验证码识别结果作为本方法的 verify_code 参数值来重新调用本方法,可多次尝试。

如何识别验证码:

鉴于腾讯的验证码基本无法通过机器进行识别,所以推荐网络上的人工识别验证码服务。因为 tokencookies 都有一定时间的有效期,所以一次验证码识别可以使用不短的时间,响应时间和价格完全可以承受。

参数:verify_code (str) – 验证码, 不传入则为无验证码
Raises:LoginVerifyCodeError 需要验证码或验证码出错,该异常为 LoginError 的子类
Raises:LoginError 登录出错,异常内容为微信服务器响应的内容,可作为日志记录下来
get_verify_code(file_path)

获取登录验证码并存储到本地路径

参数:file_path (str) – 将验证码图片保存的文件路径
get_token_cookies()

获取当前 token 及 cookies, 供手动缓存使用

返回 dict 示例:

{
    'cookies': 'bizuin=3086177907;data_bizuin=3086177907;data_ticket=AgWTXTpLL+FV+bnc9yLbb3V8;slave_sid=TERlMEJ1bWFCbTlmVnRLX0lLdUpRV0pyN2k1eVkzbWhiY0NfTHVjNFRZQk1DRDRfal82UzZKWTczR3I5TFpUYjRXUDBtN1h1cmJMRTkzS3hianBHOGpHaFM0eXJiNGp6cDFWUGpqbFNyMFlyQ05GWGpseVg2T2s2Sk5DRWpnRlE=;slave_user=gh_1b2959761a7d;',
    'token': 373179898
}
返回:一个 dict 对象, key 为 tokencookies
get_plugin_token_appid()

获取当前 plugin_token 及 appid, 供手动缓存使用

返回 dict 示例:

{
    'plugin_token': 'll1D85fGDCTr4AAxC_RrFIsfaM1eajMksOjZN_eXodroIeT77QkrMfckyYdG0qj8CnvWGUPp7-mpBOs07dbuG-iwULOcyjoEvlTsghm1K34C0oj3AI8egAxGqixxhRs8',
    'appid': 'wxd0c09648a48b3798'
}
返回:一个 dict 对象, key 为 plugin_tokenappid
send_message(fakeid, content)

主动发送文本消息

参数:
  • fakeid (str) – 用户的 UID (即 fakeid )
  • content (str) – 发送的内容
Raises:

NeedLoginError 操作未执行成功, 需要再次尝试登录, 异常内容为服务器返回的错误数据

Raises:

ValueError 参数出错, 具体内容有 fake id not exist

get_user_list(page=0, pagesize=10, groupid=0)

获取用户列表

返回JSON示例

{
    "contacts": [
        {
            "id": 2431798261,
            "nick_name": "Doraemonext",
            "remark_name": "",
            "group_id": 0
        },
        {
            "id": 896229760,
            "nick_name": "微信昵称",
            "remark_name": "",
            "group_id": 0
        }
    ]
}
参数:
  • page (integer) – 页码 (从 0 开始)
  • pagesize (integer) – 每页大小
  • groupid (integer) – 分组 ID
返回:

返回的 JSON 数据

Raises:

NeedLoginError 操作未执行成功, 需要再次尝试登录, 异常内容为服务器返回的错误数据

stat_article_detail_list(page=1, start_date=str(date.today()+timedelta(days=-30)), end_date=str(date.today()))

获取图文分析数据

返回JSON示例

{
    "hasMore": true,  // 说明是否可以增加 page 页码来获取数据
    "data": [
        {
            "index": [
                "20,816",  // 送达人数
                "1,944",  // 图文页阅读人数
                "2,554",  // 图文页阅读次数
                "9.34%",  // (图文页阅读人数 / 送达人数)
                "0",  // 原文页阅读人数
                "0",  // 原文页阅读次数
                "0%",  // (原文页阅读人数 / 图文页阅读人数)
                "47",  // 分享转发人数
                "61",  // 分享转发次数
                "1"  // 微信收藏人数
            ],
            "time": "2015-01-21",
            "table_data": "{\"fields\":{\"TargetUser\":{\"thText\":\"\\u9001\\u8fbe\\u4eba\\u6570\",\"number\":false,\"colAlign\":\"center\",\"needOrder\":false,\"precision\":0},\"IntPageReadUser\":{\"thText\":\"\\u4eba\\u6570\",\"number\":true,\"colAlign\":\"right\",\"needOrder\":false,\"precision\":0},\"IntPageReadCount\":{\"thText\":\"\\u6b21\\u6570\",\"number\":true,\"colAlign\":\"right\",\"needOrder\":false,\"precision\":0},\"PageConversion\":{\"thText\":\"\\u56fe\\u6587\\u8f6c\\u5316\\u7387\",\"number\":true,\"colAlign\":\"right\",\"needOrder\":false,\"precision\":\"2\"},\"OriPageReadUser\":{\"thText\":\"\\u4eba\\u6570\",\"number\":true,\"colAlign\":\"right\",\"needOrder\":false,\"precision\":0},\"OriPageReadCount\":{\"thText\":\"\\u6b21\\u6570\",\"number\":true,\"colAlign\":\"right\",\"needOrder\":false,\"precision\":0},\"Conversion\":{\"thText\":\"\\u539f\\u6587\\u8f6c\\u5316\\u7387\",\"number\":true,\"colAlign\":\"right\",\"needOrder\":false,\"precision\":\"2\"},\"ShareUser\":{\"thText\":\"\\u4eba\\u6570\",\"number\":true,\"colAlign\":\"right\",\"needOrder\":false,\"precision\":0},\"ShareCount\":{\"thText\":\"\\u6b21\\u6570\",\"number\":true,\"colAlign\":\"right\",\"needOrder\":false,\"precision\":0},\"AddToFavUser\":{\"thText\":\"\\u5fae\\u4fe1\\u6536\\u85cf\\u4eba\\u6570\",\"number\":true,\"colAlign\":\"right\",\"needOrder\":false,\"precision\":0}},\"data\":[{\"MsgId\":\"205104027_1\",\"Title\":\"\\u56de\\u5bb6\\u5927\\u4f5c\\u6218 | \\u5feb\\u6765\\u5e26\\u6211\\u56de\\u5bb6\",\"RefDate\":\"20150121\",\"TargetUser\":\"20,816\",\"IntPageReadUser\":\"1,944\",\"IntPageReadCount\":\"2,554\",\"OriPageReadUser\":\"0\",\"OriPageReadCount\":\"0\",\"ShareUser\":\"47\",\"ShareCount\":\"61\",\"AddToFavUser\":\"1\",\"Conversion\":\"0%\",\"PageConversion\":\"9.34%\"}],\"fixedRow\":false,\"cssSetting\":{\"\":\"\"},\"complexHeader\":[[{\"field\":\"TargetUser\",\"thText\":\"\\u9001\\u8fbe\\u4eba\\u6570\",\"rowSpan\":2,\"colSpan\":1},{\"thText\":\"\\u56fe\\u6587\\u9875\\u9605\\u8bfb\",\"colSpan\":3},{\"thText\":\"\\u539f\\u6587\\u9875\\u9605\\u8bfb\",\"colSpan\":3},{\"thText\":\"\\u5206\\u4eab\\u8f6c\\u53d1\",\"colSpan\":2},{\"field\":\"AddToFavUser\",\"thText\":\"\\u5fae\\u4fe1\\u6536\\u85cf\\u4eba\\u6570\",\"rowSpan\":2,\"enable\":true}],[{\"field\":\"IntPageReadUser\",\"thText\":\"\\u4eba\\u6570\"},{\"field\":\"IntPageReadCount\",\"thText\":\"\\u6b21\\u6570\"},{\"field\":\"PageConversion\",\"thText\":\"\\u56fe\\u6587\\u8f6c\\u5316\\u7387\"},{\"field\":\"OriPageReadUser\",\"thText\":\"\\u4eba\\u6570\"},{\"field\":\"OriPageReadCount\",\"thText\":\"\\u6b21\\u6570\"},{\"field\":\"Conversion\",\"thText\":\"\\u539f\\u6587\\u8f6c\\u5316\\u7387\"},{\"field\":\"ShareUser\",\"thText\":\"\\u4eba\\u6570\"},{\"field\":\"ShareCount\",\"thText\":\"\\u6b21\\u6570\"}]]}",
            "id": "205104027_1",
            "title": "回家大作战 | 快来带我回家"
        },
        {
            "index": [
                "20,786",  // 送达人数
                "2,598",  // 图文页阅读人数
                "3,368",  // 图文页阅读次数
                "12.5%",  // (图文页阅读人数 / 送达人数)
                "0",  // 原文页阅读人数
                "0",  // 原文页阅读次数
                "0%",  // (原文页阅读人数 / 图文页阅读人数)
                "73",  // 分享转发人数
                "98",  // 分享转发次数
                "1"  // 微信收藏人数
            ],
            "time": "2015-01-20",
            "table_data": "{\"fields\":{\"TargetUser\":{\"thText\":\"\\u9001\\u8fbe\\u4eba\\u6570\",\"number\":false,\"colAlign\":\"center\",\"needOrder\":false,\"precision\":0},\"IntPageReadUser\":{\"thText\":\"\\u4eba\\u6570\",\"number\":true,\"colAlign\":\"right\",\"needOrder\":false,\"precision\":0},\"IntPageReadCount\":{\"thText\":\"\\u6b21\\u6570\",\"number\":true,\"colAlign\":\"right\",\"needOrder\":false,\"precision\":0},\"PageConversion\":{\"thText\":\"\\u56fe\\u6587\\u8f6c\\u5316\\u7387\",\"number\":true,\"colAlign\":\"right\",\"needOrder\":false,\"precision\":\"2\"},\"OriPageReadUser\":{\"thText\":\"\\u4eba\\u6570\",\"number\":true,\"colAlign\":\"right\",\"needOrder\":false,\"precision\":0},\"OriPageReadCount\":{\"thText\":\"\\u6b21\\u6570\",\"number\":true,\"colAlign\":\"right\",\"needOrder\":false,\"precision\":0},\"Conversion\":{\"thText\":\"\\u539f\\u6587\\u8f6c\\u5316\\u7387\",\"number\":true,\"colAlign\":\"right\",\"needOrder\":false,\"precision\":\"2\"},\"ShareUser\":{\"thText\":\"\\u4eba\\u6570\",\"number\":true,\"colAlign\":\"right\",\"needOrder\":false,\"precision\":0},\"ShareCount\":{\"thText\":\"\\u6b21\\u6570\",\"number\":true,\"colAlign\":\"right\",\"needOrder\":false,\"precision\":0},\"AddToFavUser\":{\"thText\":\"\\u5fae\\u4fe1\\u6536\\u85cf\\u4eba\\u6570\",\"number\":true,\"colAlign\":\"right\",\"needOrder\":false,\"precision\":0}},\"data\":[{\"MsgId\":\"205066833_1\",\"Title\":\"\\u56de\\u5bb6\\u5927\\u4f5c\\u6218 | \\u5982\\u4f55\\u4f18\\u96c5\\u5730\\u53bb\\u5f80\\u8f66\\u7ad9\\u548c\\u673a\\u573a\",\"RefDate\":\"20150120\",\"TargetUser\":\"20,786\",\"IntPageReadUser\":\"2,598\",\"IntPageReadCount\":\"3,368\",\"OriPageReadUser\":\"0\",\"OriPageReadCount\":\"0\",\"ShareUser\":\"73\",\"ShareCount\":\"98\",\"AddToFavUser\":\"1\",\"Conversion\":\"0%\",\"PageConversion\":\"12.5%\"}],\"fixedRow\":false,\"cssSetting\":{\"\":\"\"},\"complexHeader\":[[{\"field\":\"TargetUser\",\"thText\":\"\\u9001\\u8fbe\\u4eba\\u6570\",\"rowSpan\":2,\"colSpan\":1},{\"thText\":\"\\u56fe\\u6587\\u9875\\u9605\\u8bfb\",\"colSpan\":3},{\"thText\":\"\\u539f\\u6587\\u9875\\u9605\\u8bfb\",\"colSpan\":3},{\"thText\":\"\\u5206\\u4eab\\u8f6c\\u53d1\",\"colSpan\":2},{\"field\":\"AddToFavUser\",\"thText\":\"\\u5fae\\u4fe1\\u6536\\u85cf\\u4eba\\u6570\",\"rowSpan\":2,\"enable\":true}],[{\"field\":\"IntPageReadUser\",\"thText\":\"\\u4eba\\u6570\"},{\"field\":\"IntPageReadCount\",\"thText\":\"\\u6b21\\u6570\"},{\"field\":\"PageConversion\",\"thText\":\"\\u56fe\\u6587\\u8f6c\\u5316\\u7387\"},{\"field\":\"OriPageReadUser\",\"thText\":\"\\u4eba\\u6570\"},{\"field\":\"OriPageReadCount\",\"thText\":\"\\u6b21\\u6570\"},{\"field\":\"Conversion\",\"thText\":\"\\u539f\\u6587\\u8f6c\\u5316\\u7387\"},{\"field\":\"ShareUser\",\"thText\":\"\\u4eba\\u6570\"},{\"field\":\"ShareCount\",\"thText\":\"\\u6b21\\u6570\"}]]}",
            "id": "205066833_1",
            "title": "回家大作战 | 如何优雅地去往车站和机场"
        },
        {
            "index": [
                "20,745",  // 送达人数
                "1,355",  // 图文页阅读人数
                "1,839",  // 图文页阅读次数
                "6.53%",  // (图文页阅读人数 / 送达人数)
                "145",  // 原文页阅读人数
                "184",  // 原文页阅读次数
                "10.7%",  // (原文页阅读人数 / 图文页阅读人数)
                "48",  // 分享转发人数
                "64",  // 分享转发次数
                "5"  // 微信收藏人数
            ],
            "time": "2015-01-19",
            "table_data": "{\"fields\":{\"TargetUser\":{\"thText\":\"\\u9001\\u8fbe\\u4eba\\u6570\",\"number\":false,\"colAlign\":\"center\",\"needOrder\":false,\"precision\":0},\"IntPageReadUser\":{\"thText\":\"\\u4eba\\u6570\",\"number\":true,\"colAlign\":\"right\",\"needOrder\":false,\"precision\":0},\"IntPageReadCount\":{\"thText\":\"\\u6b21\\u6570\",\"number\":true,\"colAlign\":\"right\",\"needOrder\":false,\"precision\":0},\"PageConversion\":{\"thText\":\"\\u56fe\\u6587\\u8f6c\\u5316\\u7387\",\"number\":true,\"colAlign\":\"right\",\"needOrder\":false,\"precision\":\"2\"},\"OriPageReadUser\":{\"thText\":\"\\u4eba\\u6570\",\"number\":true,\"colAlign\":\"right\",\"needOrder\":false,\"precision\":0},\"OriPageReadCount\":{\"thText\":\"\\u6b21\\u6570\",\"number\":true,\"colAlign\":\"right\",\"needOrder\":false,\"precision\":0},\"Conversion\":{\"thText\":\"\\u539f\\u6587\\u8f6c\\u5316\\u7387\",\"number\":true,\"colAlign\":\"right\",\"needOrder\":false,\"precision\":\"2\"},\"ShareUser\":{\"thText\":\"\\u4eba\\u6570\",\"number\":true,\"colAlign\":\"right\",\"needOrder\":false,\"precision\":0},\"ShareCount\":{\"thText\":\"\\u6b21\\u6570\",\"number\":true,\"colAlign\":\"right\",\"needOrder\":false,\"precision\":0},\"AddToFavUser\":{\"thText\":\"\\u5fae\\u4fe1\\u6536\\u85cf\\u4eba\\u6570\",\"number\":true,\"colAlign\":\"right\",\"needOrder\":false,\"precision\":0}},\"data\":[{\"MsgId\":\"205028693_1\",\"Title\":\"\\u5145\\u7535\\u65f6\\u95f4 | \\u542c\\u542c\\u7535\\u53f0\\uff0c\\u4f18\\u96c5\\u5730\\u63d0\\u5347\\u5b66\\u4e60\\u6548\\u7387\",\"RefDate\":\"20150119\",\"TargetUser\":\"20,745\",\"IntPageReadUser\":\"1,355\",\"IntPageReadCount\":\"1,839\",\"OriPageReadUser\":\"145\",\"OriPageReadCount\":\"184\",\"ShareUser\":\"48\",\"ShareCount\":\"64\",\"AddToFavUser\":\"5\",\"Conversion\":\"10.7%\",\"PageConversion\":\"6.53%\"}],\"fixedRow\":false,\"cssSetting\":{\"\":\"\"},\"complexHeader\":[[{\"field\":\"TargetUser\",\"thText\":\"\\u9001\\u8fbe\\u4eba\\u6570\",\"rowSpan\":2,\"colSpan\":1},{\"thText\":\"\\u56fe\\u6587\\u9875\\u9605\\u8bfb\",\"colSpan\":3},{\"thText\":\"\\u539f\\u6587\\u9875\\u9605\\u8bfb\",\"colSpan\":3},{\"thText\":\"\\u5206\\u4eab\\u8f6c\\u53d1\",\"colSpan\":2},{\"field\":\"AddToFavUser\",\"thText\":\"\\u5fae\\u4fe1\\u6536\\u85cf\\u4eba\\u6570\",\"rowSpan\":2,\"enable\":true}],[{\"field\":\"IntPageReadUser\",\"thText\":\"\\u4eba\\u6570\"},{\"field\":\"IntPageReadCount\",\"thText\":\"\\u6b21\\u6570\"},{\"field\":\"PageConversion\",\"thText\":\"\\u56fe\\u6587\\u8f6c\\u5316\\u7387\"},{\"field\":\"OriPageReadUser\",\"thText\":\"\\u4eba\\u6570\"},{\"field\":\"OriPageReadCount\",\"thText\":\"\\u6b21\\u6570\"},{\"field\":\"Conversion\",\"thText\":\"\\u539f\\u6587\\u8f6c\\u5316\\u7387\"},{\"field\":\"ShareUser\",\"thText\":\"\\u4eba\\u6570\"},{\"field\":\"ShareCount\",\"thText\":\"\\u6b21\\u6570\"}]]}",
            "id": "205028693_1",
            "title": "充电时间 | 听听电台,优雅地提升学习效率"
        }
    ]
}
参数:
  • page (integer) – 页码 (由于腾讯接口限制,page 从 1 开始,3 条数据为 1 页)
  • start_date (str) – 开始时间,默认是今天-30天 (类型: str 格式示例: “2015-01-15”)
  • end_date (str) – 结束时间,默认是今天 (类型: str 格式示例: “2015-02-01”)
返回:

返回的 JSON 数据,具体的各项内容解释参见上面的 JSON 返回示例

Raises:

NeedLoginError 操作未执行成功, 需要再次尝试登录, 异常内容为服务器返回的错误数据

get_group_list()

获取分组列表

返回JSON示例:

{
    "groups": [
        {
            "cnt": 8,
            "id": 0,
            "name": "未分组"
        },
        {
            "cnt": 0,
            "id": 1,
            "name": "黑名单"
        },
        {
            "cnt": 0,
            "id": 2,
            "name": "星标组"
        }
    ]
}
返回:返回的 JSON 数据
Raises:NeedLoginError 操作未执行成功, 需要再次尝试登录, 异常内容为服务器返回的错误数据
get_news_list(page, pagesize=10)

获取图文信息列表

返回JSON示例:

[
    {
        "multi_item": [
            {
                "seq": 0,
                "title": "98路公交线路",
                "show_cover_pic": 1,
                "author": "",
                "cover": "https://mmbiz.qlogo.cn/mmbiz/D2pflbZwStFibz2Sb1kWOuHrxtDMPKJic3GQgcgkDSoEm668gClFVDt3BR8GGQ5eB8HoL4vDezzKtSblIjckOf7A/0",
                "content_url": "http://mp.weixin.qq.com/s?__biz=MjM5MTA2ODcwOA==&mid=204884970&idx=1&sn=bf25c51f07260d4ed38305a1cbc0ce0f#rd",
                "source_url": "",
                "file_id": 204884939,
                "digest": "98路线路1.农大- 2.金阳小区- 3.市客运司- 4.市制药厂- 5.新农大- 6.独山子酒店- 7.三"
            }
        ],
        "seq": 0,
        "title": "98路公交线路",
        "show_cover_pic": 1,
        "author": "",
        "app_id": 204884970,
        "content_url": "http://mp.weixin.qq.com/s?__biz=MjM5MTA2ODcwOA==&mid=204884970&idx=1&sn=bf25c51f07260d4ed38305a1cbc0ce0f#rd",
        "create_time": "1405237966",
        "file_id": 204884939,
        "img_url": "https://mmbiz.qlogo.cn/mmbiz/D2pflbZwStFibz2Sb1kWOuHrxtDMPKJic3GQgcgkDSoEm668gClFVDt3BR8GGQ5eB8HoL4vDezzKtSblIjckOf7A/0",
        "digest": "98路线路1.农大- 2.金阳小区- 3.市客运司- 4.市制药厂- 5.新农大- 6.独山子酒店- 7.三"
    },
    {
        "multi_item": [
            {
                "seq": 0,
                "title": "2013年新疆软件园大事记",
                "show_cover_pic": 0,
                "author": "",
                "cover": "https://mmbiz.qlogo.cn/mmbiz/D2pflbZwStFibz2Sb1kWOuHrxtDMPKJic3icvFgkxZRyIrkLbic9I5ZKLa3XB8UqNlkT8CYibByHuraSvVoeSzdTRLQ/0",
                "content_url": "http://mp.weixin.qq.com/s?__biz=MjM5MTA2ODcwOA==&mid=204883415&idx=1&sn=68d62215052d29ece3f2664e9c4e8cab#rd",
                "source_url": "",
                "file_id": 204883412,
                "digest": "1月1.新疆软件园展厅设计方案汇报会2013年1月15日在维泰大厦4楼9号会议室召开新疆软件园展厅设计工作完"
            },
            {
                "seq": 1,
                "title": "2012年新疆软件园大事记",
                "show_cover_pic": 0,
                "author": "",
                "cover": "https://mmbiz.qlogo.cn/mmbiz/D2pflbZwStFibz2Sb1kWOuHrxtDMPKJic3oErGEhSicRQc82icibxZOZ2YAGNgiaGYfOFYppmPzOOS0v1xfZ1nvyT58g/0",
                "content_url": "http://mp.weixin.qq.com/s?__biz=MjM5MTA2ODcwOA==&mid=204883415&idx=2&sn=e7db9b30d770c85c61008d2f523b8610#rd",
                "source_url": "",
                "file_id": 204883398,
                "digest": "1月1.新疆软件园环评顺利通过专家会评审2012年1月30日,新疆软件园环境影响评价顺利通过专家会评审,与会"
            },
            {
                "seq": 2,
                "title": "2011年新疆软件园大事记",
                "show_cover_pic": 0,
                "author": "",
                "cover": "https://mmbiz.qlogo.cn/mmbiz/D2pflbZwStFibz2Sb1kWOuHrxtDMPKJic3qA7tEN8GvkgDwnOfKsGsicJeQ6PxQSgWuJXfQaXkpM4VNlQicOWJM4Tg/0",
                "content_url": "http://mp.weixin.qq.com/s?__biz=MjM5MTA2ODcwOA==&mid=204883415&idx=3&sn=4cb1c6d25cbe6dfeff37f52a62532bd0#rd",
                "source_url": "",
                "file_id": 204883393,
                "digest": "6月1.软件园召开第一次建设领导小组会议2011年6月7日,第一次软件园建设领导小组会议召开,会议认为,新疆"
            },
            {
                "seq": 3,
                "title": "2010年新疆软件园大事记",
                "show_cover_pic": 0,
                "author": "",
                "cover": "https://mmbiz.qlogo.cn/mmbiz/D2pflbZwStFibz2Sb1kWOuHrxtDMPKJic3YG4sSuf9X9ecMPjDRju842IbIvpFWK7tuZs0Po4kZCz4URzOBj5rnQ/0",
                "content_url": "http://mp.weixin.qq.com/s?__biz=MjM5MTA2ODcwOA==&mid=204883415&idx=4&sn=4319f7f051f36ed972e2f05a221738ec#rd",
                "source_url": "",
                "file_id": 204884043,
                "digest": "5月1.新疆软件园与开发区(头屯河区)管委会、经信委签署《新疆软件园建设战略合作协议》2010年5月12日,"
            }
        ],
        "seq": 1,
        "title": "2013年新疆软件园大事记",
        "show_cover_pic": 0,
        "author": "",
        "app_id": 204883415,
        "content_url": "http://mp.weixin.qq.com/s?__biz=MjM5MTA2ODcwOA==&mid=204883415&idx=1&sn=68d62215052d29ece3f2664e9c4e8cab#rd",
        "create_time": "1405232974",
        "file_id": 204883412,
        "img_url": "https://mmbiz.qlogo.cn/mmbiz/D2pflbZwStFibz2Sb1kWOuHrxtDMPKJic3icvFgkxZRyIrkLbic9I5ZKLa3XB8UqNlkT8CYibByHuraSvVoeSzdTRLQ/0",
        "digest": "1月1.新疆软件园展厅设计方案汇报会2013年1月15日在维泰大厦4楼9号会议室召开新疆软件园展厅设计工作完"
    }
]
参数:
  • page (integer) – 页码 (从 0 开始)
  • pagesize (integer) – 每页数目
返回:

返回的 JSON 数据

Raises:

NeedLoginError 操作未执行成功, 需要再次尝试登录, 异常内容为服务器返回的错误数据

get_dialog_message(fakeid[, last_msgid=0, create_time=0])

获取与指定用户的对话内容, 获取的内容由 last_msgid (需要获取的对话中时间最早的 公众号发送给用户 的消息ID) 和 create_time (需要获取的对话中时间最早的消息时间戳) 进行过滤

消息过滤规则:

  1. 首先按照 last_msgid 过滤 (不需要按照 last_msgid 过滤则不需要传入此参数)

    1. fakeid 为用户 UID
    2. 通过 last_msgid 去匹配公众号过去发送给用户的某一条消息
    3. 如果匹配成功, 则返回这条消息之后与这个用户相关的所有消息内容 (包括发送的消息和接收的)
    4. 如果匹配失败 (没有找到), 则返回与这个用户相关的所有消息 (包括发送的消息和接收的)
  2. 第一条规则返回的消息内容接着按照 create_time 进行过滤, 返回 create_time 时间戳之时及之后的所有消息 (不需要按照 create_time 过滤则不需要传入此参数)

返回JSON示例:

{
    "to_nick_name": "Doraemonext",
    "msg_items": {
        "msg_item": [
            {
                "date_time": 1408671873,
                "has_reply": 0,
                "multi_item": [ ],
                "msg_status": 4,
                "nick_name": "Doraemonext",
                "to_uin": 2391068708,
                "content": "你呢",
                "source": "",
                "fakeid": "844735403",
                "send_stat": {
                    "fail": 0,
                    "succ": 0,
                    "total": 0
                },
                "refuse_reason": "",
                "type": 1,
                "id": 206439567
            },
            {
                "date_time": 1408529750,
                "send_stat": {
                    "fail": 0,
                    "succ": 0,
                    "total": 0
                },
                "app_sub_type": 3,
                "multi_item": [
                    {
                        "seq": 0,
                        "title": "软件企业有望拎包入住新疆软件园",
                        "show_cover_pic": 1,
                        "author": "",
                        "cover": "https://mmbiz.qlogo.cn/mmbiz/D2pflbZwStFibz2Sb1kWOuHrxtDMPKJic3oErGEhSicRQc82icibxZOZ2YAGNgiaGYfOFYppmPzOOS0v1xfZ1nvyT58g/0",
                        "content_url": "http://mp.weixin.qq.com/s?__biz=MjM5MTA2ODcwOA==&mid=204885255&idx=1&sn=40e07d236a497e36d2d3e9711dfe090a#rd",
                        "source_url": "",
                        "content": "",
                        "file_id": 204885252,
                        "vote_id": [ ],
                        "digest": "12月8日,国家软件公共服务平台新疆分平台在乌鲁木齐经济技术开发区(头屯河区)揭牌。这意味着,软件企业有"
                    }
                ],
                "msg_status": 2,
                "title": "软件企业有望拎包入住新疆软件园",
                "nick_name": "Doraemonext",
                "to_uin": 844735403,
                "content_url": "http://mp.weixin.qq.com/s?__biz=MjM5MTA2ODcwOA==&mid=204885255&idx=1&sn=40e07d236a497e36d2d3e9711dfe090a#rd",
                "show_type": 1,
                "content": "",
                "source": "biz",
                "fakeid": "2391068708",
                "file_id": 204885252,
                "has_reply": 0,
                "refuse_reason": "",
                "type": 6,
                "id": 206379033,
                "desc": "12月8日,国家软件公共服务平台新疆分平台在乌鲁木齐经济技术开发区(头屯河区)揭牌。这意味着,软件企业有"
            }
        ]
    }
}
参数:
  • fakeid (str) – 用户 UID (即 fakeid )
  • last_msgid (str) – 公众号之前发送给用户(fakeid)的消息 ID, 为 0 则表示全部消息
  • create_time (str) – 获取这个时间戳之时及之后的消息,为 0 则表示全部消息
返回:

返回的 JSON 数据

Raises:

NeedLoginError 操作未执行成功, 需要再次尝试登录, 异常内容为服务器返回的错误数据

send_news(fakeid, msgid)

向指定用户发送图文消息 (必须从图文库里选取消息ID传入)

参数:
  • fakeid (str) – 用户的 UID (即 fakeid)
  • msgid (str) – 图文消息 ID
Raises:

NeedLoginError 操作未执行成功, 需要再次尝试登录, 异常内容为服务器返回的错误数据

Raises:

ValueError 参数出错, 具体内容有 fake id not existmessage id not exist

add_news(news)

在素材库中创建图文消息

参数:news (list) –

list 对象, 其中的每个元素为一个 dict 对象, 代表一条图文, key 值分别为 title, author, summary, content, picture_id, from_url, 对应内容为标题, 作者, 摘要, 内容, 素材库里的图片ID(可通过 upload_file 函数上传获取), 来源链接。

其中必须提供的 key 值为 titlecontent

示例:

[
    {
        'title': '图文标题',
        'author': '图文作者',
        'summary': '图文摘要',
        'content': '图文内容',
        'picture_id': '23412341',
        'from_url': 'http://www.baidu.com',
    },
    {
        'title': '最少图文标题',
        'content': '图文内容',
    }
]
Raises:ValueError 参数提供错误时抛出
Raises:NeedLoginError 操作未执行成功, 需要再次尝试登录, 异常内容为服务器返回的错误数据
upload_file(filepath)

上传素材 (图片/音频/视频)

参数:filepath (str) – 本地文件路径
返回:直接返回上传后的文件 ID (fid)
Raises:NeedLoginError 操作未执行成功, 需要再次尝试登录, 异常内容为服务器返回的错误数据
Raises:ValueError 参数出错, 错误原因直接打印异常即可 (常见错误内容: file not exist: 找不到本地文件, audio too long: 音频文件过长, file invalid type: 文件格式不正确, 还有其他错误请自行检查)
send_file(fakeid, fid, type)

向特定用户发送媒体文件

参数:
  • fakeid (str) – 用户 UID (即 fakeid)
  • fid (str) – 文件 ID
  • type (integer) – 文件类型 (2: 图片, 3: 音频, 4: 视频)
Raises:

NeedLoginError 操作未执行成功, 需要再次尝试登录, 异常内容为服务器返回的错误数据

Raises:

ValueError 参数出错, 错误原因直接打印异常即可 (常见错误内容: system errorcan not send this type of msg: 文件类型不匹配, user not exist: 用户 fakeid 不存在, file not exist: 文件 fid 不存在, 还有其他错误请自行检查)

get_file_list(type, page[, count=10])

获取素材库文件列表

返回JSON示例:

{
    "type": 2,
    "file_item": [
        {
            "update_time": 1408723089,
            "name": "Doraemonext.png",
            "play_length": 0,
            "file_id": 206471048,
            "type": 2,
            "size": "53.7 K"
        },
        {
            "update_time": 1408722328,
            "name": "Doraemonext.png",
            "play_length": 0,
            "file_id": 206470809,
            "type": 2,
            "size": "53.7 K"
        }
    ],
    "file_cnt": {
        "voice_cnt": 1,
        "app_msg_cnt": 10,
        "commondity_msg_cnt": 0,
        "video_cnt": 0,
        "img_cnt": 29,
        "video_msg_cnt": 0,
        "total": 40
    }
}
参数:
  • type (integer) – 文件类型 (2: 图片, 3: 音频, 4: 视频)
  • page (integer) – 页码 (从 0 开始)
  • count (integer) – 每页大小
返回:

返回的 JSON 数据

Raises:

NeedLoginError 操作未执行成功, 需要再次尝试登录, 异常内容为服务器返回的错误数据

send_image(fakeid, fid)

给指定用户 fakeid 发送图片信息

参数:
  • fakeid (str) – 用户的 UID (即 fakeid)
  • fid (str) – 文件 ID
Raises:

NeedLoginError 操作未执行成功, 需要再次尝试登录, 异常内容为服务器返回的错误数据

Raises:

ValueError 参数出错, 错误原因直接打印异常即可 (常见错误内容: system errorcan not send this type of msg: 文件类型不匹配, user not exist: 用户 fakeid 不存在, file not exist: 文件 fid 不存在, 还有其他错误请自行检查)

send_audio(fakeid, fid)

给指定用户 fakeid 发送语音信息

参数:
  • fakeid (str) – 用户的 UID (即 fakeid)
  • fid (str) – 文件 ID
Raises:

NeedLoginError 操作未执行成功, 需要再次尝试登录, 异常内容为服务器返回的错误数据

Raises:

ValueError 参数出错, 错误原因直接打印异常即可 (常见错误内容: system errorcan not send this type of msg: 文件类型不匹配, user not exist: 用户 fakeid 不存在, file not exist: 文件 fid 不存在, 还有其他错误请自行检查)

send_video(fakeid, fid)

给指定用户 fakeid 发送视频消息

参数:
  • fakeid (str) – 用户的 UID (即 fakeid)
  • fid (str) – 文件 ID
Raises:

NeedLoginError 操作未执行成功, 需要再次尝试登录, 异常内容为服务器返回的错误数据

Raises:

ValueError 参数出错, 错误原因直接打印异常即可 (常见错误内容: system errorcan not send this type of msg: 文件类型不匹配, user not exist: 用户 fakeid 不存在, file not exist: 文件 fid 不存在, 还有其他错误请自行检查)

get_user_info(fakeid)

获取指定用户的个人信息

返回JSON示例:

{
    "province": "湖北",
    "city": "武汉",
    "gender": 1,
    "nick_name": "Doraemonext",
    "country": "中国",
    "remark_name": "",
    "fake_id": 844735403,
    "signature": "",
    "group_id": 0,
    "user_name": ""
}
参数:fakeid (str) – 用户的 UID (即 fakeid)
返回:返回的 JSON 数据
Raises:NeedLoginError 操作未执行成功, 需要再次尝试登录, 异常内容为服务器返回的错误数据
get_avatar(fakeid)

获取用户头像信息

参数:fakeid (str) – 用户的 UID (即 fakeid)
返回:二进制 JPG 数据字符串, 可直接作为 File Object 中 write 的参数
Raises:NeedLoginError 操作未执行成功, 需要再次尝试登录, 异常内容为服务器返回的错误数据
get_new_message_num(lastid=0)

获取新消息的数目

参数:lastid – 最近获取的消息 ID, 为 0 时获取总消息数目
返回:消息数目
返回类型:int
get_top_message()

获取最新一条消息

返回JSON示例:

{
    "msg_item": [
        {
            "id": 206448489,
            "type": 2,
            "fakeid": "844735403",
            "nick_name": "Doraemonext",
            "date_time": 1408696938,
            "source": "",
            "msg_status": 4,
            "has_reply": 0,
            "refuse_reason": "",
            "multi_item": [ ],
            "to_uin": 2391068708,
            "send_stat": {
                "total": 0,
                "succ": 0,
                "fail": 0
            }
        }
    ]
}
返回:返回的 JSON 数据
Raises:NeedLoginError 操作未执行成功, 需要再次尝试登录, 异常内容为服务器返回的错误数据
get_message_list(lastid=0, offset=0, count=20, day=7, star=False)

获取消息列表

返回JSON示例

{
    "msg_item": [
        {
            "id": 206439583,
            "type": 1,
            "fakeid": "844735403",
            "nick_name": "Doraemonext",
            "date_time": 1408671892,
            "content": "测试消息",
            "source": "",
            "msg_status": 4,
            "has_reply": 0,
            "refuse_reason": "",
            "multi_item": [ ],
            "to_uin": 2391068708,
            "send_stat": {
                "total": 0,
                "succ": 0,
                "fail": 0
            }
        },
        {
            "id": 206439579,
            "type": 1,
            "fakeid": "844735403",
            "nick_name": "Doraemonext",
            "date_time": 1408671889,
            "content": "wechat-python-sdk",
            "source": "",
            "msg_status": 4,
            "has_reply": 0,
            "refuse_reason": "",
            "multi_item": [ ],
            "to_uin": 2391068708,
            "send_stat": {
                "total": 0,
                "succ": 0,
                "fail": 0
            }
        }
    ]
}
参数:
  • lastid (integer) – 传入最后的消息 id 编号, 为 0 则从最新一条起倒序获取
  • offset (integer) – lastid 起算第一条的偏移量
  • count (integer) – 获取数目
  • day (integer) – 最近几天消息 (0: 今天, 1: 昨天, 2: 前天, 3: 更早, 7: 全部), 这里的全部仅有5天
  • star (boolean) – 是否只获取星标消息
返回:

返回的 JSON 数据

Raises:

NeedLoginError 操作未执行成功, 需要再次尝试登录, 异常内容为服务器返回的错误数据

get_message_image(msgid, mode='large')

根据消息 ID 获取图片消息内容

参数:
  • msgid (str) – 消息 ID
  • mode (str) – 图片尺寸 (‘large’或’small’)
返回:

二进制 JPG 图片字符串, 可直接作为 File Object 中 write 的参数

Raises:

NeedLoginError 操作未执行成功, 需要再次尝试登录, 异常内容为服务器返回的错误数据

Raises:

ValueError 参数出错, 错误原因直接打印异常即可, 错误内容: image message not exist: msg参数无效, mode error: mode参数无效

get_message_voice(msgid)

根据消息 ID 获取语音消息内容

参数:msgid (str) – 消息 ID
返回:二进制 MP3 音频字符串, 可直接作为 File Object 中 write 的参数
Raises:NeedLoginError 操作未执行成功, 需要再次尝试登录, 异常内容为服务器返回的错误数据
Raises:ValueError 参数出错, 错误原因直接打印异常即可, 错误内容: voice message not exist: msg参数无效
get_message_video(msgid)

根据消息 ID 获取视频消息内容

参数:msgid (str) – 消息 ID
返回:二进制 MP4 视频字符串, 可直接作为 File Object 中 write 的参数
Raises:NeedLoginError 操作未执行成功, 需要再次尝试登录, 异常内容为服务器返回的错误数据
Raises:ValueError 参数出错, 错误原因直接打印异常即可, 错误内容: video message not exist: msg参数无效

微信消息类 WechatMessage

文档已经转移到新地址: http://wechat-python-sdk.com/

目前此开发包提供以下几种消息类:TextMessage (文本消息类), ImageMessage (图片消息类), VideoMessage (视频消息类), LocationMessage (位置消息类), LinkMessage (链接消息类), EventMessage (事件消息类), VoiceMessage (语音消息类),它们都继承自 WechatMessage (公共消息类)

这些消息类都在 wechat_sdk.messages 中定义

公共消息类 WechatMessage

下面所有的消息类均有此处的公共属性

name value
id 消息ID
target 目标用户 OpenID
source 来源用户 OpenID
time 信息发送时间,一个UNIX时间戳。
raw 信息的原始 XML 格式

文本消息类 TextMessage

name value
type ‘text’
content 信息的内容

图片消息类 ImageMessage

name value
type ‘image’
picurl 图片网址,可以从这个网址访问到图片

视频消息类 VideoMessage

name value
type ‘video’
media_id 视频消息媒体 ID
thumb_media_id 视频消息缩略图的媒体 ID

小视频消息类 ShortVideoMessage

name value
type ‘shortvideo’
media_id 视频消息媒体 ID
thumb_media_id 视频消息缩略图的媒体 ID

链接消息类 LinkMessage

name value
type ‘link’
title 消息标题
description 消息描述
url 消息链接

地理位置消息类 LocationMessage

name value
type ‘location’
location 一个元组(纬度, 经度)
scale 地图缩放大小
label 地理位置信息

事件消息类 EventMessage

关注事件
name value
type ‘subscribe’
key None
ticket None

请注意,普通的关注事件和扫描二维码造成的关注事件的 type 均为 subscribe ,如果是普通的关注事件,则 keyticket 均为 None ,可以通过判断它们来识别是普通关注事件还是扫描二维码造成的关注事件。

取消关注事件
name value
type ‘unsubscribe’
二维码事件
name value
type ‘subscribe’ 或 ‘scan’
key

事件 key 值

当用户未关注时(type = ‘subscribe’),qrscene_为前缀,后面为二维码的参数值;

当用户已关注时(type = ‘scan’),是一个32位无符号整数,即创建二维码时的二维码scene_id

ticket 二维码 Ticket,可用来换取二维码图片
上报地理位置事件
name value
type ‘location’
latitude 地理位置纬度
longitude 地理位置经度
precision 地理位置精度
自定义菜单事件
name value
type

‘click’

‘view’

‘scancode_push’

‘scancode_waitmsg’

‘pic_sysphoto’

‘pic_photo_or_album’

‘pic_weixin’

‘location_select’

key

事件 key 值

当 type = ‘click’ 时,它与自定义菜单接口中KEY值对应;

当 type = ‘view’ 时,它是设置的跳转URL

当 type 为其他取值时,它是事件KEY值,由开发者在创建菜单时设定

ScanCodeInfo 扫描信息,当且仅当 type = ‘scancode_push’ 或 ‘scancode_waitmsg’ 时存在
SendPicsInfo 发送的图片信息,当且仅当 type = ‘pic_sysphoto’ 或 ‘pic_photo_or_album’ 或 ‘pic_weixin’ 时存在
SendLocationInfo 发送的位置信息,当且仅当 type = ‘location_select’ 时存在
模板消息事件
name value
type ‘templatesendjobfinish’
status 发送状态

语音消息类 VoiceMessage

name value
type ‘voice’
media_id 语音消息媒体 ID
format 声音格式
recognition 语音识别结果(如未开通语音识别功能,则值为 None )

上下文对话支持

文档已经转移到新地址: http://wechat-python-sdk.com/

为了实现用户状态的维持与记录, wechat-python-sdk 实现了上下文对话功能。

由于作者精力有限,目前仅实现了 Django 下的上下文对话支持,其他方式或其他框架下的上下文对话适配将在后续版本中逐渐完成。如果您有精力、有兴趣,欢迎向本项目贡献代码 :)

Django

该上下文对话支持功能在 Django 1.6+ 环境下测试通过。

对于一个单独的公众号而言,每个已关注用户都会有一个对该公众号唯一的OpenID,所以,我们可以通过OpenID来确定并记录用户身份、状态等信息。

安装

在你的 settings.py 的 INSTALLED_APPS 中添加 wechat_sdk.context.framework.django ,如下:

INSTALLED_APPS = (
    # ...
    'wechat_sdk.context.framework.django',
)

然后执行数据库同步

如果你是 Django 1.7+ 版本,执行:

python manage.py migrate wechat_sdk_django

否则,执行:

python manage.py syncdb wechat_sdk_django

安装完成:)

现在在你的数据库中可以看到, wechat-python-sdk 在其中新建了一个名为 wechat_context 的数据表,这就是用来存储微信上下文的地方。

使用说明

初始化上下文对话需要传入用户的 OpenID,初始化的过程非常简单,假设存储当前请求用户 OpenID 的变量名称为 source ,则有如下代码:

from wechat_sdk.context.framework.django import DatabaseContextStore

context = DatabaseContextStore(openid=source)

如果当前用户尚未存储任何上下文对话数据, DatabaseContextStore 会自动新建记录,否则会自动取出数据库的已有记录,无需任何干预。

对于我们现在得到的这个 context 上下文对话,你可以自由读写,并且可以多次编辑其中的内容。

class backends.ContextBase

这是所有上下文对话的基类。它支持下面这些标准的字典方法:

__getitem__(key)

示例: fav_color = context['fav_color']

__setitem__(key, value)

示例: context['fav_color'] = 'blue'

__delitem__(key)

示例: del context['fav_color']

__contains__(key)

示例: 'fav_color' in context

get(key, default=None)

示例: fav_color = context.get('fav_color', 'red')

pop(key)

示例: fav_color = context.pop('fav_color')

keys()
items()
setdefault()
clear()

它还有支持下面这些方法:

flush()

本方法会在数据库中删除该用户的所有信息,执行前请确认不再需要该用户的任何数据。

get_expiry_age()

本方法返回当前上下文对话还有多少秒失效。

本方法接收两个可选的关键字参数:

  • modification: 该上下文对话的最后修改时间,需要为 datetime 对象。默认是当前时间。
  • expiry: 该上下文对话的过期时间信息。可以是 datetime 对象,也可以是 int ,或者是 None 。默认为 set_expire 所设定的过期日期。
get_expire_date()

本方法返回当前上下文对话的过期日期 (datetime 对象)

本方法接受的两个可选的关键字参数和 get_expire_age() 相同。

set_expiry(value)

设置当前上下文对话的过期时间。你可以用不同的方式来传入你想要设定的过期时间:

  • 如果 value 是一个数字,那么当前上下文对话将会在 value 秒后失效。举例来说,如果你调用了 context.set_expire(300) ,那么当前上下文对话将会在 5 分钟后失效。
  • 如果 value 是一个 datetimetimedelta 对象,那么当前上下文对话将会在该指定的时间失效。
  • 如果 valueNone ,那么当前上下文对话的过期时间将会重置到系统所设定的值(WECHAT_CONTEXT_AGE)。
clear_expired()

本方法会在数据库中清空所有的过期信息,无需手动调用,每次执行 save() 时会自动进行清理。

save()

本方法会将所有的当前的上下文对话信息存入数据库。请务必要在代码的结束位置调用本方法,否则所有数据都不会被保存。

示例: context.save()

使用准则

不要尝试直接访问或设置 context 实例中的除上面提到的方法和属性,仅仅把它当做一个普通的 python 字典就可以了。

使用示例

这里用一个非常简单的小例子来帮助大家理解并使用上下文对话功能。它的功能很简单,如果我一直朝这个 home 函数发文字信息的请求,它会记录当前是第多少次对话以及上一次的对话内容是什么。

# -*- coding: utf-8 -*-

from django.http.response import HttpResponse, HttpResponseBadRequest
from django.views.decorators.csrf import csrf_exempt
from wechat_sdk import WechatBasic
from wechat_sdk.exceptions import ParseError
from wechat_sdk.messages import TextMessage
from wechat_sdk.context.framework.django import DatabaseContextStore


@csrf_exempt
def home(request):
    # 从 request 中提取基本信息 (signature, timestamp, nonce, xml)
    signature = request.GET.get('signature')
    timestamp = request.GET.get('timestamp')
    nonce = request.GET.get('nonce')
    xml = request.body

    # 实例化 WechatBasic 并检验合法性
    wechat_instance = WechatBasic(token='MY_WECHAT_TOKEN')
    if not wechat_instance.check_signature(signature=signature, timestamp=timestamp, nonce=nonce):
        return HttpResponseBadRequest('Verify Failed')

    # 解析本次请求的 XML 数据
    try:
        wechat_instance.parse_data(data=xml)
    except ParseError:
        return HttpResponseBadRequest('Invalid XML Data')

    message = wechat_instance.get_message()  # 获取解析好的微信请求信息
    context = DatabaseContextStore(openid=message.source)  # 利用本次请求中的用户OpenID来初始化上下文对话

    if isinstance(message, TextMessage):
        step = context.get('step', 1)  # 从上下文对话数据中取出 'step' 所对应的内容(当前对话次数),如果没有则返回 1
        last_text = context.get('last_text')  # 从上下文对话数据中取出 'last_text' 所对应的内容(上次对话内容)
        # 生成字符串
        now_text = u'这是第 %d 次对话' % step
        if step > 1:
            now_text += u',上一次对话文字:%s' % last_text
        # 将新的数据存入上下文对话中
        context['step'] = step + 1
        context['last_text'] = message.content
        response = wechat_instance.response_text(content=now_text)
    else:
        response = wechat_instance.response_text(content=u'错误的信息类型')

    context.save()  # 非常重要!请勿忘记!最后需要将所有临时数据保存入数据库!
    return HttpResponse(response)
可用设置项

wechat-python-sdk 为您提供了设置项,它有自己的默认值,但是您也可以通过修改它来适应自己的需求。

WECHAT_CONTEXT_AGE = 7200 上下文对话默认过期时间(s)

如果需要修改,直接在 settings.py 中加上上面的设置项即可;不需修改则不必在 settings.py 中增加该项。

异常类

文档已经转移到新地址: http://wechat-python-sdk.com/

class wechat_sdk.exceptions.NeedParamError

构造参数提供不全异常

class wechat_sdk.exceptions.ParseError

解析微信服务器数据异常

class wechat_sdk.exceptions.NeedParseError

尚未解析微信服务器请求数据异常

class wechat_sdk.exceptions.OfficialAPIError

微信官方 API 请求出错异常

class wechat_sdk.exceptions.UnOfficialAPIError

微信非官方 API 请求出错异常

class wechat_sdk.exceptions.NeedLoginError

微信非官方API请求出错异常 - 需要登录

该类为 wechat_sdk.exceptions.UnOfficialAPIError 的子类

class wechat_sdk.exceptions.LoginError

微信非官方API请求出错异常 - 登录出错

该类为 wechat_sdk.exceptions.UnOfficialAPIError 的子类

class wechat_sdk.exceptions.LoginVerifyCodeError

微信非官方API请求出错异常 - 登录出错 - 验证码错误

该类为 wechat_sdk.exceptions.LoginError 的子类

FAQ 汇总

文档已经转移到新地址: http://wechat-python-sdk.com/

  1. 当使用 == 操作符比较两边内容时出现警告:
UnicodeWarning: Unicode equal comparison failed to convert both arguments to Unicode - interpreting them as being unequal

解决方案:

因为在 wechat-python-sdk 内部,所有中文字符串均为 unicode 类型,如果您使用了一个 str 类型的字符串作比较,就会出现上述问题,解决方案很简单,把您的 str 类型的字符串转换为 unicode 类型即可。

感谢 WeRoBot 项目,本项目中官方接口的许多代码均借鉴于此。

Indices and tables