wxpy: 用 Python 玩微信¶
- 微信机器人 / 可能是最优雅的微信个人号 API
- wxpy 在 itchat 的基础上,通过大量接口优化提升了模块的易用性,并进行丰富的功能扩展
注意
用来干啥¶
一些常见的场景
- 控制路由器、智能家居等具有开放接口的玩意儿
- 运行脚本时自动把日志发送到你的微信
- 加群主为好友,自动拉进群中
- 跨号或跨群转发消息
- 自动陪人聊天
- 逗人玩
- ...
总而言之,可用来实现各种微信个人号的自动化操作
轻松安装¶
wxpy 支持 Python 3.4-3.6,以及 2.7 版本
将下方命令中的 “pip” 替换为 “pip3” 或 “pip2”,可确保安装到对应的 Python 版本中
- 从 PYPI 官方源下载安装 (在国内可能比较慢或不稳定):
pip install -U wxpy
- 从豆瓣 PYPI 镜像源下载安装 (推荐国内用户选用):
pip install -U wxpy -i "https://pypi.doubanio.com/simple/"
简单上手¶
登陆微信:
# 导入模块
from wxpy import *
# 初始化机器人,扫码登陆
bot = Bot()
找到好友:
# 搜索名称含有 "游否" 的男性深圳好友
my_friend = bot.friends().search('游否', sex=MALE, city="深圳")[0]
发送消息:
# 发送文本给好友
my_friend.send('Hello WeChat!')
# 发送图片
my_friend.send_image('my_picture.jpg')
自动响应各类消息:
# 打印来自其他好友、群聊和公众号的消息
@bot.register()
def print_others(msg):
print(msg)
# 回复 my_friend 的消息 (优先匹配后注册的函数!)
@bot.register(my_friend)
def reply_my_friend(msg):
return 'received: {} ({})'.format(msg.text, msg.type)
# 自动接受新的好友请求
@bot.register(msg_types=FRIENDS)
def auto_accept_friends(msg):
# 接受好友请求
new_friend = msg.card.accept()
# 向新的好友发送消息
new_friend.send('哈哈,我自动接受了你的好友请求')
保持登陆/运行:
# 进入 Python 命令行、让程序保持运行
embed()
# 或者仅仅堵塞线程
# bot.join()
模块特色¶
文档目录¶
机器人对象¶
机器人 Bot
对象可被理解为一个 Web 微信客户端。
初始化/登陆¶
注解
Bot
在初始化时便会执行登陆操作,需要手机扫描登陆。
-
class
wxpy.
Bot
(cache_path=None, console_qr=False, qr_path=None, qr_callback=None, login_callback=None, logout_callback=None)[源代码]¶ 机器人对象,用于登陆和操作微信账号,涵盖大部分 Web 微信的功能:
from wxpy import * bot = Bot() # 机器人账号自身 myself = bot.self # 向文件传输助手发送消息 bot.file_helper.send('Hello from wxpy!')
参数: - cache_path –
- 设置当前会话的缓存路径,并开启缓存功能;为 None (默认) 则不开启缓存功能。
- 开启缓存后可在短时间内避免重复扫码,缓存失效时会重新要求登陆。
- 设为 True 时,使用默认的缓存路径 ‘wxpy.pkl’。
- console_qr –
- 在终端中显示登陆二维码,需要安装 pillow 模块 (pip3 install pillow)。
- 可为整数(int),表示二维码单元格的宽度,通常为 2 (当被设为 True 时,也将在内部当作 2)。
- 也可为负数,表示以反色显示二维码,适用于浅底深字的命令行界面。
- 例如: 在大部分 Linux 系统中可设为 True 或 2,而在 macOS Terminal 的默认白底配色中,应设为 -2。
- qr_path – 保存二维码的路径
- qr_callback – 获得二维码后的回调,可以用来定义二维码的处理方式,接收参数: uuid, status, qrcode
- login_callback – 登陆成功后的回调,若不指定,将进行清屏操作,并删除二维码文件
- logout_callback – 登出时的回调
- cache_path –
-
Bot.
enable_puid
(path='wxpy_puid.pkl')[源代码]¶ 可选操作: 启用聊天对象的
puid
属性:# 启用 puid 属性,并指定 puid 所需的映射数据保存/载入路径 bot.enable_puid('wxpy_puid.pkl') # 指定一个好友 my_friend = bot.friends().search('游否')[0] # 查看他的 puid print(my_friend.puid) # 'edfe8468'
小技巧
puid
是 wxpy 特有的聊天对象/用户ID不同于其他 ID 属性,puid 可始终被获取到,且具有稳定的唯一性参数: path – puid 所需的映射数据保存/载入路径
-
Bot.
auto_mark_as_read
¶ 为 True 时,将自动消除手机端的新消息小红点提醒 (默认为 False)
获取聊天对象¶
-
Bot.
self
¶ 机器人自身 (作为一个聊天对象)
若需要给自己发送消息,请先进行以下一次性操作:
# 在 Web 微信中把自己加为好友 bot.self.add() bot.self.accept() # 发送消息给自己 bot.self.send('能收到吗?')
-
Bot.
file_helper
¶ 文件传输助手
-
Bot.
friends
(update=False)[源代码]¶ 获取所有好友
参数: update – 是否更新 返回: 聊天对象合集 返回类型: wxpy.Chats
-
Bot.
groups
(update=False, contact_only=False)[源代码]¶ 获取所有群聊对象
一些不活跃的群可能无法被获取到,可通过在群内发言,或修改群名称的方式来激活
参数: - update – 是否更新
- contact_only – 是否限于保存为联系人的群聊
返回: 群聊合集
返回类型:
-
Bot.
mps
(update=False)[源代码]¶ 获取所有公众号
参数: update – 是否更新 返回: 聊天对象合集 返回类型: wxpy.Chats
-
Bot.
chats
(update=False)[源代码]¶ 获取所有聊天对象
参数: update – 是否更新 返回: 聊天对象合集 返回类型: wxpy.Chats
搜索聊天对象¶
注解
- 通过 .search() 获得的搜索结果 均为列表
- 若希望找到唯一结果,可使用
ensure_one()
搜索好友:
# 搜索名称包含 '游否' 的深圳男性好友
found = bot.friends().search('游否', sex=MALE, city='深圳')
# [<Friend: 游否>]
# 确保搜索结果是唯一的,并取出唯一结果
youfou = ensure_one(found)
# <Friend: 游否>
搜索群聊:
# 搜索名称包含 'wxpy',且成员中包含 `游否` 的群聊对象
wxpy_groups = bot.groups().search('wxpy', [youfou])
# [<Group: wxpy 交流群 1>, <Group: wxpy 交流群 2>]
在群聊中搜素:
# 在刚刚找到的第一个群中搜索
group = wxpy_groups[0]
# 搜索该群中所有浙江的群友
found = group.search(province='浙江')
# [<Member: 浙江群友 1>, <Group: 浙江群友 2>, <Group: 浙江群友 3> ...]
搜索任何类型的聊天对象 (但不包含群内成员)
# 搜索名称含有 'wxpy' 的任何聊天对象
found = bot.search('wxpy')
# [<Friend: wxpy 机器人>, <Group: wxpy 交流群 1>, <Group: wxpy 交流群 2>]
加好友和建群¶
-
Bot.
add_friend
(user, verify_content='')[源代码]¶ 添加用户为好友
参数: - user – 用户对象,或 user_name
- verify_content – 验证说明信息
-
Bot.
accept_friend
(user, verify_content='')[源代码]¶ 接受用户为好友
参数: - user – 用户对象或 user_name
- verify_content – 验证说明信息
返回: 新的好友对象
返回类型:
自动接受好友请求:
# 注册好友请求类消息
@bot.register(msg_types=FRIENDS)
# 自动接受验证信息中包含 'wxpy' 的好友请求
def auto_accept_friends(msg):
# 判断好友请求中的验证文本
if 'wxpy' in msg.text.lower():
# 接受好友 (msg.card 为该请求的用户对象)
new_friend = bot.accept_friend(msg.card)
# 或 new_friend = msg.card.accept()
# 向新的好友发送消息
new_friend.send('哈哈,我自动接受了你的好友请求')
聊天对象¶
通过机器人对象 Bot
的
chats()
,
friends()
,groups()
,
mps()
方法,
可分别获取到当前机器人的 所有聊天对象、好友、群聊,以及公众号列表。
而获得到的聊天对象合集 Chats
和 Groups
具有一些合集方法,例如:Chats.search()
可用于按条件搜索聊天对象:
from wxpy import *
bot = Bot()
my_friend = bot.friends().search('游否', sex=MALE, city='深圳')[0]
# <Friend: 游否>
在找到好友(或其他聊天对象)后,还可使用该聊天对象的 send
系列方法,对其发送消息:
# 发送文本
my_friend.send('Hello, WeChat!')
# 发送图片
my_friend.send_image('my_picture.png')
# 发送视频
my_friend.send_video('my_video.mov')
# 发送文件
my_friend.send_file('my_file.zip')
# 以动态的方式发送图片
my_friend.send('@img@my_picture.png')
各类型的继承关系¶
在继续了解各个聊天对象之前,我们需要首先 理解各种不同类型聊天对象的继承关系
基础类¶
所有聊天对象,均继承于以下两种基础类,并拥有相应的属性和方法。
- 基本聊天对象
Chat
- 所有的聊天对象均继承于此类型
- 拥有 微信ID、昵称 等属性
- 拥有 发送消息
Chat.send()
, 获取头像Chat.get_avatar()
等方法
- 单个聊天对象
User
- 继承于
Chat
,表示个体聊天对象 (而非群聊)。 - 拥有 性别、省份、城市、是否为好友 等属性
- 拥有 加为好友
User.add()
, 接受为好友User.accept()
等方法
- 继承于
基本聊天对象¶
所有聊天对象都继承于”基本聊天对象”,并拥有相应的属性和方法。
-
class
wxpy.
Chat
(raw, bot)[源代码]¶ -
-
raw
¶ 原始数据
-
puid
¶ 持续有效,且稳定唯一的聊天对象/用户ID,适用于持久保存
请使用
Bot.enable_puid()
来启用 puid 属性小技巧
puid
是 wxpy 特有的聊天对象/用户ID不同于其他 ID 属性,puid 可始终被获取到,且具有稳定的唯一性注意
puid 映射数据 不可跨机器人使用
-
nick_name
¶ 该聊天对象的昵称 (好友、群员的昵称,或群名称)
-
name
¶ - 该聊天对象的友好名称具体为: 从 备注名称、群聊显示名称、昵称(或群名称),或微信号中按序选取第一个可用的
-
send
(content=None, media_id=None)[源代码]¶ 动态发送不同类型的消息,具体类型取决于 msg 的前缀。
参数: - content –
- 由 前缀 和 内容 两个部分组成,若 省略前缀,将作为纯文本消息发送
- 前缀 部分可为: ‘@fil@’, ‘@img@’, ‘@msg@’, ‘@vid@’ (不含引号)
- 分别表示: 文件,图片,纯文本,视频
- 内容 部分可为: 文件、图片、视频的路径,或纯文本的内容
- media_id – 填写后可省略上传过程
返回类型: - content –
-
send_msg
(msg=None)[源代码]¶ 发送文本消息
参数: msg – 文本内容 返回类型: wxpy.SentMessage
-
send_raw_msg
(raw_type, raw_content, uri=None, msg_ext=None)[源代码]¶ 以原始格式发送其他类型的消息。
参数: - raw_type (int) – 原始的整数消息类型
- raw_content (str) – 原始的消息内容
- uri (str) – 请求路径,默认为 ‘/webwxsendmsg’
- msg_ext (dict) – 消息的扩展属性 (会被更新到 Msg 键中)
返回类型: 例如,发送好友或公众号的名片:
my_friend.send_raw_msg( # 名片的原始消息类型 raw_type=42, # 注意 `username` 在这里应为微信 ID,且被发送的名片必须为自己的好友 raw_content='<msg username="wxpy_bot" nickname="wxpy 机器人"/>' )
-
user_name
¶ 该聊天对象的内部 ID,通常不需要用到
注意
同个聊天对象在不同用户中,此 ID 不一致 ,且可能在新会话中 被改变!
-
单个聊天对象¶
-
class
wxpy.
User
(raw, bot)[源代码]¶ 好友(
Friend
)、群聊成员(Member
),和公众号(MP
) 的基础类-
remark_name
¶ 备注名称
-
sex
¶ 性别,目前有:
# 男性 MALE = 1 # 女性 FEMALE = 2
未设置时为 None
-
province
¶ 省份
-
city
¶ 城市
-
signature
¶ 个性签名
-
is_friend
¶ 判断当前用户是否为好友关系
返回: 若为好友关系,返回对应的好友,否则返回 False
-
accept
(verify_content='')[源代码]¶ 接受当前用户为好友
参数: verify_content – 验证信息(文本) 返回: 新的好友对象 返回类型: wxpy.Friend
-
群聊¶
-
class
wxpy.
Group
(raw, bot)[源代码]¶ 群聊对象
-
members
¶ 群聊的成员列表
-
search
(keywords=None, **attributes)[源代码]¶ 在群聊中搜索成员
注解
搜索结果为一个Chats (列表)
对象建议搭配ensure_one()
使用参数: - keywords – 成员名称关键词
- attributes – 属性键值对
返回: 匹配的群聊成员
返回类型:
-
owner
¶ 返回群主对象
-
is_owner
¶ 判断所属 bot 是否为群管理员
-
self
¶ 机器人自身 (作为群成员)
-
群成员¶
实用技巧¶
判断一位用户是否在群中只需用 in 语句:
friend = bot.friends().search('游否')[0]
group = bot.groups().search('wxpy 交流群')[0]
if friend in group:
print('是的,{} 在 {} 中!'.format(friend.name, group.name))
# 是的,游否 在 wxpy 交流群 中!
若要遍历群成员,可直接对群对象使用 for 语句:
# 打印所有群成员
for member in group:
print(member)
若需查看群成员数量,直接使用 len() 即可:
len(group) # 这个群的成员数量
若需判断一位群成员是否就是某个好友,使用 == 即可:
member = group.search('游否')[0]
if member == friend:
print('{} is {}'.format(member, friend))
# <Member: 游否> is <Friend: 游否>
聊天对象合集¶
好友、公众号、群聊成员的合集¶
在 Chats
对象中,除了最常用到的 search()
外,还有两个特别的方法,stats()
与 stats_text()
,可用来统计好友或群成员的性别和地区分布:
bot.friends().stats_text()
# 游否 共有 100 位微信好友\n\n男性: 67 (67.0%)\n女性: 23 (23.0%) ...
-
class
wxpy.
Chats
(chat_list=None, source=None)[源代码]¶ 多个聊天对象的合集,可用于搜索或统计
-
search
(keywords=None, **attributes)[源代码]¶ 在聊天对象合集中进行搜索
注解
搜索结果为一个Chats (列表)
对象建议搭配ensure_one()
使用参数: - keywords – 聊天对象的名称关键词
- attributes – 属性键值对,键可以是 sex(性别), province(省份), city(城市) 等。例如可指定 province=’广东’
返回: 匹配的聊天对象合集
返回类型:
-
消息处理¶
每当机器人接收到消息时,会自动执行以下两个步骤
- 将消息保存到
Bot.messages
中 - 查找消息预先注册的函数,并执行(若有匹配的函数)
消息对象¶
消息对象代表每一条从微信获取到的消息。
基本属性¶
-
Message.
type
¶ 消息的类型,目前可为以下值:
# 文本 TEXT = 'Text' # 位置 MAP = 'Map' # 名片 CARD = 'Card' # 提示 NOTE = 'Note' # 分享 SHARING = 'Sharing' # 图片 PICTURE = 'Picture' # 语音 RECORDING = 'Recording' # 文件 ATTACHMENT = 'Attachment' # 视频 VIDEO = 'Video' # 好友请求 FRIENDS = 'Friends' # 系统 SYSTEM = 'System'
返回类型: str
-
Message.
id
¶ 消息的唯一 ID (通常为大于 0 的 64 位整型)
内容数据¶
-
Message.
text
¶ 消息的文本内容
-
Message.
get_file
(save_path=None)[源代码]¶ 下载图片、视频、语音、附件消息中的文件内容。
可与
Message.file_name
配合使用。参数: save_path – 文件的保存路径。若为 None,将直接返回字节数据
-
Message.
file_name
¶ 消息中文件的文件名
-
Message.
file_size
¶ 消息中文件的体积大小
-
Message.
media_id
¶ 文件类消息中的文件资源 ID (但图片视频语音等其他消息中为空)
-
Message.
raw
¶ 原始数据 (dict 数据)
用户相关¶
-
Message.
chat
¶ 消息所在的聊天会话,即:
- 对于自己发送的消息,为消息的接收者
- 对于别人发送的消息,为消息的发送者
返回类型: wxpy.User
,wxpy.Group
-
Message.
sender
¶ 消息的发送者
返回类型: wxpy.User
,wxpy.Group
-
Message.
receiver
¶ 消息的接收者
返回类型: wxpy.User
,wxpy.Group
-
Message.
member
¶ - 若消息来自群聊,则此属性为消息的实际发送人(具体的群成员)
- 若消息来自其他聊天对象(非群聊),则此属性为 None
返回类型: NoneType, wxpy.Member
-
Message.
card
¶ - 好友请求中的请求用户
- 名片消息中的推荐用户
群聊相关¶
-
Message.
member
- 若消息来自群聊,则此属性为消息的实际发送人(具体的群成员)
- 若消息来自其他聊天对象(非群聊),则此属性为 None
返回类型: NoneType, wxpy.Member
-
Message.
is_at
¶ 当消息来自群聊,且被 @ 时,为 True
时间相关¶
-
Message.
create_time
¶ 服务端发送时间
-
Message.
receive_time
¶ 本地接收时间
-
Message.
latency
¶ 消息的延迟秒数 (发送时间和接收时间的差值)
其他属性¶
-
Message.
url
¶ 分享类消息中的网页 URL
-
Message.
articles
¶ 公众号推送中的文章列表 (首篇的 标题/地址 与消息中的 text/url 相同)
其中,每篇文章均有以下属性:
- title: 标题
- summary: 摘要
- url: 文章 URL
- cover: 封面或缩略图 URL
-
Message.
location
¶ 位置消息中的地理位置信息
-
Message.
img_height
¶ 图片高度
-
Message.
img_width
¶ 图片宽度
-
Message.
play_length
¶ 视频长度
-
Message.
voice_length
¶ 语音长度
回复方法¶
-
Message.
reply
(...)¶
-
Message.
reply_image
(...)¶
-
Message.
reply_file
(...)¶
-
Message.
reply_video
(...)¶
-
Message.
reply_msg
(...)¶
-
Message.
reply_raw_msg
(...)¶
转发消息¶
-
Message.
forward
(chat, prefix=None, suffix=None, raise_for_unsupported=False)[源代码]¶ 将本消息转发给其他聊天对象
- 支持以下消息类型
文本 (TEXT)
视频(VIDEO)
文件 (ATTACHMENT)
图片/自定义表情 (PICTURE)
- 但不支持表情商店中的表情
名片 (CARD)
- 仅支持公众号名片,以及自己发出的个人号名片
分享 (SHARING)
- 会转化为 标题 + 链接 形式的文本消息
语音 (RECORDING)
- 会以文件方式发送
地图 (MAP)
- 会转化为 位置名称 + 地图链接 形式的文本消息
参数: - chat (Chat) – 接收转发消息的聊天对象
- prefix (str) – 转发时增加的 前缀 文本,原消息为文本时会自动换行
- suffix (str) – 转发时增加的 后缀 文本,原消息为文本时会自动换行
- raise_for_unsupported (bool) – 为 True 时,将为不支持的消息类型抛出 NotImplementedError 异常
例如,将公司群中的老板消息转发出来:
from wxpy import * bot = Bot() # 定位公司群 company_group = ensure_one(bot.groups().search('公司微信群')) # 定位老板 boss = ensure_one(company_group.search('老板大名')) # 将老板的消息转发到文件传输助手 @bot.register(company_group) def forward_boss_message(msg): if msg.member == boss: msg.forward(bot.file_helper, prefix='老板发言') # 堵塞线程 embed()
自动处理消息¶
可通过 预先注册 的方式,实现消息的自动处理。
- “预先注册” 是指
- 预先将特定聊天对象的特定类型消息,注册到对应的处理函数,以实现自动回复等功能。
注册消息¶
提示
消息对象
作为唯一参数传入该函数。将 Bot.register()
作为函数的装饰器,即可完成注册。
# 打印所有*群聊*对象中的*文本*消息
@bot.register(Group, TEXT)
def print_group_msg(msg):
print(msg)
注意
优先匹配 后注册 的函数,且仅匹配 一个 注册函数。
-
Bot.
register
(chats=None, msg_types=None, except_self=True, run_async=True, enabled=True)[源代码]¶ 装饰器:用于注册消息配置
参数: - chats – 消息所在的聊天对象:单个或列表形式的多个聊天对象或聊天类型,为空时匹配所有聊天对象
- msg_types – 消息的类型:单个或列表形式的多个消息类型,为空时匹配所有消息类型 (SYSTEM 类消息除外)
- except_self – 排除由自己发送的消息
- run_async – 是否异步执行所配置的函数:可提高响应速度
- enabled – 当前配置的默认开启状态,可事后动态开启或关闭
小技巧
- chats 和 msg_types 参数可以接收一个列表或干脆一个单项。按需使用,方便灵活。
- chats 参数既可以是聊天对象实例,也可以是对象类。当为类时,表示匹配该类型的所有聊天对象。
- 在被注册函数中,可以通过直接 return <回复内容> 的方式来回复消息,等同于调用 msg.reply(<回复内容>)。
开始运行¶
注解
from wxpy import *
bot = Bot()
@bot.register()
def print_messages(msg):
print(msg)
# 堵塞线程,并进入 Python 命令行
embed()
示例代码¶
在以下例子中,机器人将
- 忽略 “一个无聊的群” 的所有消息
- 回复好友 “游否” 和其他群聊中被 @ 的 TEXT 类消息
- 打印所有其他消息
初始化机器人,并找到好友和群聊:
from wxpy import *
bot = Bot()
my_friend = bot.friends().search('游否')[0]
boring_group = bot.groups().search('一个无聊的群')[0]
打印所有其他消息:
@bot.register()
def just_print(msg):
# 打印消息
print(msg)
回复好友”游否”和其他群聊中被 @ 的 TEXT 类消息:
@bot.register([my_friend, Group], TEXT)
def auto_reply(msg):
# 如果是群聊,但没有被 @,则不回复
if isinstance(msg.chat, Group) and not msg.is_at:
return
else:
# 回复消息内容和类型
return '收到消息: {} ({})'.format(msg.text, msg.type)
忽略”一个无聊的群”的所有消息:
@bot.register(boring_group)
def ignore(msg):
# 啥也不做
return
堵塞线程,并进入 Python 命令行:
embed()
动态开关注册配置¶
注解
该操作需要在额外的线程中进行!
查看当前的注册配置情况:
bot.registered
# [<MessageConfig: just_print (Async, Enabled)>,
# <MessageConfig: auto_reply (Async, Enabled)>,
# <MessageConfig: ignore (Async, Enabled)>]
关闭所有注册配置:
bot.registered.disable()
重新开启 just_print 函数:
bot.registered.enable(just_print)
查看当前开启的注册配置:
bot.registered.enabled
# [<MessageConfig: just_print (Async, Enabled)>]
已发送消息¶
历史消息¶
可通过访问 bot.messages 来查看历史消息列表。
消息列表为 Messages
对象,具有搜索功能。
例如,搜索所有自己在手机上发出的消息:
sent_msgs = bot.messages.search(sender=bot.self)
print(sent_msgs)
-
class
wxpy.
Messages
(msg_list=None, max_history=200)[源代码]¶ 多条消息的合集,可用于记录或搜索
-
max_history
¶ 设置最大保存条数,即:仅保存最后的 n 条消息。
bot = Bot() # 设置历史消息的最大保存数量为 10000 条 bot.messages.max_history = 10000
-
用微信监控你的程序¶
通过利用微信强大的通知能力,我们可以把程序中的警告/日志发到自己的微信上。
wxpy 提供以下两种方式来实现这个需求。
获得专用 Logger¶
-
wxpy.
get_wechat_logger
(receiver=None, name=None, level=30)[源代码]¶ 获得一个可向指定微信聊天对象发送日志的 Logger
参数: 返回: Logger
from wxpy import get_wechat_logger
# 获得一个专用 Logger
# 当不设置 `receiver` 时,会将日志发送到随后扫码登陆的微信的"文件传输助手"
logger = get_wechat_logger()
# 发送警告
logger.warning('这是一条 WARNING 等级的日志,你收到了吗?')
# 接收捕获的异常
try:
1 / 0
except:
logger.exception('现在你又收到了什么?')
加入到现有的 Logger¶
import logging
from wxpy import WeChatLoggingHandler
# 这是你现有的 Logger
logger = logging.getLogger(__name__)
# 初始化一个微信 Handler
wechat_handler = WeChatLoggingHandler()
# 加到入现有的 Logger
logger.addHandler(wechat_handler)
logger.warning('你有一条新的告警,请查收。')
指定接收者¶
当然,我们也可以使用其他聊天对象来接收日志。
比如,先在微信中建立一个群聊,并在里面加入需要关注这些日志的人员。然后把这个群作为接收者。
from wxpy import *
# 初始化机器人
bot = Bot()
# 找到需要接收日志的群 -- `ensure_one()` 用于确保找到的结果是唯一的,避免发错地方
group_receiver = ensure_one(bot.groups().search('XX业务-告警通知'))
# 指定这个群为接收者
logger = get_wechat_logger(group_receiver)
logger.error('打扰大家了,但这是一条重要的错误日志...')
愉快的探索和调试¶
想要做点小试验,调试代码,或是探索 wxpy 的功能特性?反复修改和运行太麻烦。
试试下面两种玩法,告别涂涂改改的摸索方式。
使用 embed()¶
注解
适用于在现有的代码中进行探索和调试
只需将 embed()
放在代码中的任何位置。运行后,就可以从那儿开始探索和调试。
例如,初始化一个机器人,然后看看它能做些什么:
from wxpy import *
bot = Bot()
embed() # 进入 Python 命令行
# 输入对象名称并回车
>>> bot
# Out[1]: <Bot: 游否>
>>> bot.friends()
# Out[2]: [<Friend: 路人甲>, <Friend: 路人乙>, <Friend: 路人丙>]
-
wxpy.
embed
(local=None, banner='', shell=None)[源代码] - 进入交互式的 Python 命令行界面,并堵塞当前线程支持使用 ipython, bpython 以及原生 python
参数: - shell (str) – 指定命令行类型,可设为 ‘ipython’,’bpython’,’python’,或它们的首字母;若为 None,则按上述优先级进入首个可用的 Python 命令行。
- local (dict) – 设定本地变量环境,若为 None,则获取进入之前的变量环境。
- banner (str) – 设定欢迎内容,将在进入命令行后展示。
- shell (str) –
使用 wxpy 命令¶
注解
适用于在命令行中边写边探索
第二种情况:想要简单写几行,而不想创建脚本,那么使用 wxpy 命令行边写边探索,更方便。
在命令行中输入 wxpy -h 可快速查看使用说明。
选项¶
- bot1 bot2 bot3...
- 一个或多个需要初始化的机器人对象的名称,以空格分割
- 默认:不初始化机器人
- 例子: bot1 bot2
- -c / –cache
- 使用会话缓存功能,将创建 wxpy_*.pkl 缓存文件
- 默认:不缓存会话
- 例子:-c
- -q 宽度 / –console_qr 宽度
- 终端二维码的单元格宽度
- 默认:不使用终端二维码
- 例子:-q 2
- -l 等级 / –logging_level 等级 (注意是小写 L,不是 I)
- 日志等级
- 默认:INFO
- 例子:-l DEBUG
- -s 交互界面 / –shell 交互界面
- 选择所需使用的 Python 交互界面
- 可为:ipython,bpython,python,或它们的首字母
- 默认:以上首个可用的 Python 命令行
- 例子:-s bpython
- -v / –version
- 展示版本信息并退出z
- 例子:-v
例子¶
初始化一个名为 bot 的机器人:
wxpy bot
在此基础上,使用终端二维码,且单元格宽度为 2:
wxpy bot -q 2
分别初始化名为 bot1 和 bot2 的两个机器人:
wxpy bot1 bot2
在此基础上,使用会话缓存功能:
wxpy bot1 bot2 -c
在此基础上,指定使用 bpython:
wxpy bot1 bot2 -c -s bpython
实用组件¶
额外内置了一些实用的小组件,可按需使用。
聊天机器人¶
目前提供了以下两种自动聊天机器人接口。
图灵¶
-
class
wxpy.
Tuling
(api_key=None)[源代码]¶ 与 wxpy 深度整合的图灵机器人
内置的 api key 存在调用限制,建议自行申请。参数: api_key – 你申请的 api key bot = Bot() my_friend = ensure_one(bot.search('游否')) tuling = Tuling(api_key='你申请的 API KEY') # 使用图灵机器人自动与指定好友聊天 @bot.register(my_friend) def reply_my_friend(msg): tuling.do_reply(msg)
小 i¶
-
class
wxpy.
XiaoI
(key, secret)[源代码]¶ 与 wxpy 深度整合的小 i 机器人
需要通过注册获得 key 和 secret免费申请: http://cloud.xiaoi.com/参数: - key – 你申请的 key
- secret – 你申请的 secret
bot = Bot() my_friend = ensure_one(bot.search('寒风')) xiaoi = XiaoI('你申请的 Key', '你申请的 Secret') # 使用小 i 机器人自动与指定好友聊天 @bot.register(my_friend) def reply_my_friend(msg): xiaoi.do_reply(msg)
查找共同好友¶
-
wxpy.
mutual_friends
(*args)[源代码]¶ 找到多个微信用户的共同好友
参数: args – 每个参数为一个微信用户的机器人(Bot),或是聊天对象合集(Chats) 返回: 共同好友列表 返回类型: wxpy.Chats
bot1 = Bot() bot2 = Bot() # 打印共同好友 for mf in mutual_friends(bot, bot2): print(mf)
确保查找结果的唯一性¶
在多个群中同步消息¶
-
wxpy.
sync_message_in_groups
(msg, groups, prefix=None, suffix=None, raise_for_unsupported=False, run_async=True)[源代码]¶ 将消息同步到多个微信群中
- 支持以下消息类型
文本 (TEXT)
视频(VIDEO)
文件 (ATTACHMENT)
图片/自定义表情 (PICTURE)
- 但不支持表情商店中的表情
名片 (CARD)
- 仅支持公众号名片,以及自己发出的个人号名片
分享 (SHARING)
- 会被转化为 标题 + 链接 形式的纯文本
语音 (RECORDING)
- 会以文件方式发送
地图 (MAP)
- 会转化为 位置名称 + 地图链接 形式的文本消息
参数: - msg (Message) – 需同步的消息对象
- groups (Group) – 需同步的群列表
- prefix (str) –
- 转发时的 前缀 文本,原消息为文本时会自动换行
- 若不设定,则使用默认前缀作为提示
- suffix (str) –
- 转发时的 后缀 文本,原消息为文本时会自动换行
- 默认为空
- raise_for_unsupported (bool) – 为 True 时,将为不支持的消息类型抛出 NotImplementedError 异常
- run_async (bool) – 是否异步执行,为 True 时不堵塞线程
my_groups = [group1, group2, group3 ...] @bot.register(my_groups, except_self=False) def sync_my_groups(msg): sync_message_in_groups(msg, my_groups)
检测频率限制¶
-
wxpy.
detect_freq_limit
(func, *args, **kwargs)[源代码]¶ 检测各类 Web 微信操作的频率限制,获得限制次数和周期
参数: - func – 需要执行的操作函数
- args – 操作函数的位置参数
- kwargs – 操作函数的命名参数
返回: 限制次数, 限制周期(秒数)
例如,测试发送文本消息的频率限制:
bot = Bot('test.pkl') # 定义需要检测的操作 def action(): bot.file_helper.send() # 执行检测 result = detect_freq_limit(action) # 查看结果 print(result) # (120, 120.111222333)
异常处理¶
异常的抛出和捕捉¶
每当使用 wxpy 向微信发出请求 (例如发送消息、加好友、建群等操作),wxpy 都会在收到服务端响应后进行检查。
若响应中的错误码不为 0,程序将抛出 ResponseError
异常。
-
class
wxpy.
ResponseError
(err_code, err_msg)[源代码]¶ 当 BaseResponse 的返回值不为 0 时抛出的异常
-
err_code
¶ 错误码 (int)
-
err_msg
¶ 错误消息 (文本),但可能为空
-
捕捉异常:
try:
# 尝试向某个群员发送消息
group.members[3].send('Hello')
except ResponseError as e:
# 若群员还不是好友,将抛出 ResponseError 错误
print(e.err_code, e.err_msg) # 查看错误号和错误消息
已知错误码¶
通常来说,每个错误码表示一种类型的错误。
但因微信未公开 (也没有义务公开) 这套错误码体系的具体说明,我们只能根据经验猜测部分错误码的定义。
以下为一些常见的已知错误码。欢迎提交 PR 进行完善。
1205¶
通常因为操作频率过高。需要控制频率,避免再次引起该错误。
注意
Web 微信对 加好友、建群 这两种操作的频率限制尤其严格!
对于微信而言,为了机器人避免打扰其他用户,以及控制服务器的负载压力,需要对各种不同的操作进行频率限制。
通常每种操作可有多层频率限制,而每层频率限制分为两个参数:
周期、次数,分布表示: 在 x 周期内,只能发送 y 个请求。
举个例子:
对于 发送消息 操作,可能会是这样 (数值为虚构):
层 限制周期 限制次数 1 2 分钟 120 2 10 分钟 300 3 1 小时 1000 4 24 小时 2000 可能会有用户在 1 分钟内狂发 100 条消息。但这样的频率不可能维持一整天,所以一天内 3000 条是足够的。通过以上方式,微信可实现较为合理的限制。
1204¶
通常因为操作对象不为好友关系。例如尝试向一位不为好友的群员发送消息时,会引起这个错误。
itchat 与原始数据¶
正是得益于 itchat 的坚实基础,wxpy 才能够在短时间内快速实现这些新的接口和功能。
感谢 itchat 维护者们的辛勤付出。
以下为如何在 wxpy 中混合使用 itchat 的原接口和原始数据。
必看: 常见问题 FAQ¶
提示
这里罗列了一些常见的问题,在提出新的问题前,请先看完本文。
启动后马上退出了?¶
因为主线程执行完成了,程序自然会退出。
只需在代码结尾加一句 embed()
即可堵塞线程,还能进入 Python 命令行:
from wxpy import *
# 你的其他代码...
# 堵塞线程,并进入 Python 命令行
embed()
或者,也可以使用 Bot.join()
仅仅堵塞线程:
bot = Bot()
# 你的其他代码...
# 仅仅堵塞线程
bot.join()
# 机器人登出后会继续往下执行
可以在 Linux 中使用吗?¶
wxpy 不依赖于图形界面,因此完全兼容各种纯终端的服务器。
但有一点需要注意,在纯终端环境中,登陆时必须使用”终端二维码”参数。
具体请见 Bot
中的 console_qr 参数说明。
小技巧
遇到以下错误?请使用 Bot
的 console_qr 参数。
FileNotFoundError: [Errno 2] No such file or directory: 'xdg-open'
支持 红包、转账、朋友圈… 吗?¶
wxpy 使用了 Web 微信的通讯协议,因此仅能覆盖 Web 微信本身所具备的功能。
所以以下功能目前 均不支持
- 支付相关 - 红包、转账、收款 等都不支持
- 在群聊中@他人 - 是的,Web 微信中被人@后也不会提醒
- 发送名片 - 但可以通过
send_raw_msg()
转发 - 发送分享链接 - 也无法转发
- 发送语音消息
- 朋友圈相关