微信机器人 / 可能是最优雅的微信个人号 API
wxpy 在 itchat 的基础上,通过大量接口优化提升了模块的易用性,并进行丰富的功能扩展
注意
强烈建议仅使用小号运行机器人!
从近期 (17年6月下旬) 反馈来看,使用机器人存在一定概率被限制登录的可能性。
主要表现为无法登陆 Web 微信 (但不影响手机等其他平台)。
https://github.com/youfou/wxpy
一些常见的场景
总而言之,可用来实现各种微信个人号的自动化操作
wxpy 支持 Python 3.4-3.6,以及 2.7 版本
将下方命令中的 “pip” 替换为 “pip3” 或 “pip2”,可确保安装到对应的 Python 版本中
pip install -U wxpy
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()
全面对象化接口,调用更优雅
默认多线程响应消息,回复更快
包含 聊天机器人、共同好友 等 实用组件
只需两行代码,在其他项目中 用微信接收警告
愉快的探索和调试,无需涂涂改改
可混合使用 itchat 的原接口
当然,还覆盖了各类常见基本功能:
- 发送文本、图片、视频、文件
- 通过关键词或用户属性搜索 好友、群聊、群成员等
- 获取好友/群成员的昵称、备注、性别、地区等信息
- 加好友,建群,邀请入群,移出群
https://github.com/youfou/wxpy/releases
机器人 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!')
参数:
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)
获取所有群聊对象
一些不活跃的群可能无法被获取到,可通过在群内发言,或修改群名称的方式来激活
参数:
返回: 群聊合集
返回类型: wxpy.Groups
Bot.mps(update=False)
获取所有公众号
参数: update – 是否更新
返回: 聊天对象合集
返回类型:wxpy.Chats
Bot.chats(update=False)
获取所有聊天对象
参数: update – 是否更新
返回: 聊天对象合集
返回类型:wxpy.Chats
注解
ensure_one()
搜索好友:
# 搜索名称包含 '游否' 的深圳男性好友
found = bot.friends().search('游否', sex=MALE, city='深圳')
# []
# 确保搜索结果是唯一的,并取出唯一结果
youfou = ensure_one(found)
#
搜索群聊:
# 搜索名称包含 'wxpy',且成员中包含 `游否` 的群聊对象
wxpy_groups = bot.groups().search('wxpy', [youfou])
# [, ]
在群聊中搜素:
# 在刚刚找到的第一个群中搜索
group = wxpy_groups[0]
# 搜索该群中所有浙江的群友
found = group.search(province='浙江')
# [, , ...]
搜索任何类型的聊天对象 (但不包含群内成员)
# 搜索名称含有 'wxpy' 的任何聊天对象
found = bot.search('wxpy')
# [, , ]
Bot.add_friend(user, verify_content=’’)
添加用户为好友
参数:
Bot.add_mp(user)
添加/关注 公众号
参数: user – 公众号对象,或 user_name
Bot.accept_friend(user, verify_content=’’)
接受用户为好友
参数:
返回:
新的好友对象
返回类型: wxpy.Friend
自动接受好友请求:
# 注册好友请求类消息
@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.create_group(users, topic=None)
创建一个新的群聊
参数:
返回: 若建群成功,返回一个新的群聊对象
返回类型: wxpy.Group
Bot.user_details(user_or_users, chunk_size=50)
获取单个或批量获取多个用户的详细信息(地区、性别、签名等),但不可用于群聊成员
参数:
返回: 单个或多个用户用户的详细信息
Bot.upload_file(path)
上传文件,并获取 media_id
可用于重复发送图片、表情、视频,和文件
参数: path – 文件路径
返回: media_id
返回类型: str
Bot.join()
堵塞进程,直到结束消息监听 (例如,机器人被登出时)
Bot.logout()
登出当前账号
仅需初始化多个 Bot
对象,即可同时控制多个微信:
bot1 = Bot()
bot2 = Bot()
通过机器人对象 Bot
的 chats()
, friends()
,groups()
, mps()
方法, 可分别获取到当前机器人的 所有聊天对象、好友、群聊,以及公众号列表。
而获得到的聊天对象合集 Chats
和 Groups
具有一些合集方法,例如:Chats.search()
可用于按条件搜索聊天对象:
from wxpy import *
bot = Bot()
my_friend = bot.friends().search('游否', sex=MALE, city='深圳')[0]
#
在找到好友(或其他聊天对象)后,还可使用该聊天对象的 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
Chat.send()
, 获取头像 Chat.get_avatar()
等方法单个聊天对象 User
继承于 Chat
,表示个体聊天对象 (而非群聊)。
被以下聊天对象所继承
Friend
Member
MP
拥有 性别、省份、城市、是否为好友 等属性
拥有 加为好友 User.add()
, 接受为好友 User.accept()
等方法
在实际使用过程中,我们会更多的用到以下实际聊天对象类型。
小技巧
请牢记,除了自身私有的属性和方法外,它们还拥有对应基础类的属性和方法 (未重复列出)。
Friend
Group
Member
MP
注解
阅读以下内容,你将了解:
- 如何获取他们的各种属性 (ID、昵称、性别、地区、是否为好友关系等)
- 如何对他们进行发送消息、加为好友、加入群聊、下载头像 等操作
所有聊天对象都继承于”基本聊天对象”,并拥有相应的属性和方法。
class wxpy.Chat(raw, bot)
单个用户 (User
) 和群聊 (Group
) 的基础类
bot
所属的 机器人对象
raw
原始数据
puid
持续有效,且稳定唯一的聊天对象/用户ID,适用于持久保存
请使用 Bot.enable_puid()
来启用 puid 属性
小技巧
puid
是 wxpy 特有的聊天对象/用户ID
不同于其他 ID 属性,puid 可始终被获取到,且具有稳定的唯一性
注意
puid 映射数据 不可跨机器人使用
nick_name
该聊天对象的昵称 (好友、群员的昵称,或群名称)
name
该聊天对象的友好名称
具体为: 从 备注名称、群聊显示名称、昵称(或群名称),或微信号中
按序选取第一个可用的
send(content=None, media_id=None)
动态发送不同类型的消息,具体类型取决于 msg 的前缀。
参数:
返回类型: wxpy.SentMessage
send_msg
(msg=None)
发送文本消息
参数: msg – 文本内容
返回类型: wxpy.SentMessage
send_image(path, media_id=None)
发送图片
参数:
返回类型: wxpy.SentMessage
send_file(path, media_id=None)
发送文件
参数:
返回类型: wxpy.SentMessage
send_video(path=None, media_id=None)
发送视频
参数:
返回类型: wxpy.SentMessage
send_raw_msg(raw_type, raw_content, uri=None, msg_ext=None)
以原始格式发送其他类型的消息。
参数:
返回类型: wxpy.SentMessage
例如,发送好友或公众号的名片:
my_friend.send_raw_msg(
# 名片的原始消息类型
raw_type=42,
# 注意 `username` 在这里应为微信 ID,且被发送的名片必须为自己的好友
raw_content=' '
)
mark_as_read()
消除当前聊天对象的未读提示小红点
pin()
将聊天对象置顶
unpin()
取消聊天对象的置顶状态
get_avatar(save_path=None)
获取头像
参数: save_path – 保存路径(后缀通常为.jpg),若为 None 则返回字节数据
uin
微信中的聊天对象ID,固定且唯一
因微信的隐私策略,该属性有时无法被获取到
建议使用 puid
作为用户的唯一 ID
alias
若用户进行过一次性的 “设置微信号” 操作,则该值为用户设置的”微信号”,固定且唯一
因微信的隐私策略,该属性有时无法被获取到
建议使用 puid
作为用户的唯一 ID
wxid
聊天对象的微信ID (实际为 .alias 或 .uin)
因微信的隐私策略,该属性有时无法被获取到
建议使用 puid
作为用户的唯一 ID
user_name
该聊天对象的内部 ID,通常不需要用到
注意
同个聊天对象在不同用户中,此 ID 不一致 ,且可能在新会话中 被改变!
class wxpy.User(raw, bot)
好友(Friend
)、群聊成员(Member
),和公众号(MP
) 的基础类
remark_name
备注名称
set_remark_name(remark_name)
设置或修改好友的备注名称
参数: remark_name – 新的备注名称
sex
性别,目前有:
# 男性
MALE = 1
# 女性
FEMALE = 2
未设置时为 None
province
省份
city
城市
signature
个性签名
is_friend
判断当前用户是否为好友关系
返回: 若为好友关系,返回对应的好友,否则返回 False
add(verify_content=’’)
把当前用户加为好友
参数: verify_content – 验证信息(文本)
accept(verify_content=’’)
接受当前用户为好友
参数: verify_content – 验证信息(文本)
返回: 新的好友对象
返回类型: wxpy.Friend
class wxpy.Friend(raw, bot)
好友对象
class wxpy.Group(raw, bot)
群聊对象
members
群聊的成员列表
search(keywords=None, **attributes)
在群聊中搜索成员
注解
搜索结果为一个 Chats (列表)
对象
建议搭配 ensure_one()
使用
参数:
返回: 匹配的群聊成员
返回类型: wxpy.Chats
owner
返回群主对象
is_owner
判断所属 bot 是否为群管理员
self
机器人自身 (作为群成员)
update_group(members_details=False)
更新群聊的信息
参数: members_details – 是否包括群聊成员的详细信息 (地区、性别、签名等)
add_members(users, use_invitation=False)
向群聊中加入用户
参数:
remove_members(members)
从群聊中移除用户
参数: members – 待移除的用户列表或单个用户
rename_group(name)
修改群聊名称
参数: name – 新的名称,超长部分会被截断 (最长32字节)
class wxpy.Member(raw, group)
群聊成员对象
display_name
在群聊中的显示昵称
remove()
从群聊中移除该成员
name
该群成员的友好名称
具体为: 从 群聊显示名称、昵称(或群名称),或微信号中,按序选取第一个可用的
判断一位用户是否在群中只需用 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))
# is
class wxpy.MP(raw, bot)
公众号对象
在 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()
使用
参数:
返回: 匹配的聊天对象合集
返回类型: wxpy.Chats
stats(attribs=(‘sex’, ‘province’, ‘city’))
统计各属性的分布情况
参数: attribs – 需统计的属性列表或元组
返回: 统计结果
stats_text(total=True, sex=True, top_provinces=10, top_cities=10)
简单的统计结果的文本
参数:
返回: 统计结果文本
add_all(interval=3, verify_content=’’)
将合集中的所有用户加为好友,请小心应对调用频率限制!
参数:
class wxpy.Groups(group_list=None)
群聊的合集,可用于按条件搜索
search(keywords=None, users=None, **attributes)
在群聊合集中,根据给定的条件进行搜索
参数:
返回: 匹配条件的群聊列表
返回类型:wxpy.Groups
每当机器人接收到消息时,会自动执行以下两个步骤
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.bot
接收此消息的 机器人对象
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
返回类型: NoneType, wxpy.Member
Message.card
Message.member
返回类型: NoneType, `wxpy.Member
Message.is_at
当消息来自群聊,且被 @ 时,为 True
Message.create_time
服务端发送时间
Message.receive_time
本地接收时间
Message.latency
消息的延迟秒数 (发送时间和接收时间的差值)
Message.url
分享类消息中的网页 URL
Message.articles
公众号推送中的文章列表 (首篇的 标题/地址 与消息中的 text/url 相同)
其中,每篇文章均有以下属性:
Message.location
位置消息中的地理位置信息
Message.img_height
图片高度
Message.img_width
图片宽度
Message.play_length
视频长度
Message.voice_length
语音长度
Message.reply(…)
等同于 Message.chat.send(...)
Message.reply_image(…)
等同于 Message.chat.send_image(...)
Message.reply_file(…)
等同于 Message.chat.send_file(...)
Message.reply_video(…)
等同于 Message.chat.send_video(...)
Message.reply_msg(…)
等同于 Message.chat.send_msg(...)
Message.reply_raw_msg(…)
等同于 Message.chat.send_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)
装饰器:用于注册消息配置
参数:
小技巧
注解
在完成注册操作后,若没有其他操作,程序会因主线程执行完成而退出。
因此务必堵塞线程以保持监听状态!
wxpy 的 embed()
可在堵塞线程的同时,进入 Python 命令行,方便调试,一举两得。
from wxpy import *
bot = Bot()
@bot.register()
def print_messages(msg):
print(msg)
# 堵塞线程,并进入 Python 命令行
embed()
wxpy.embed(local=None, banner=’’, shell=None)
进入交互式的 Python 命令行界面,并堵塞当前线程
支持使用 ipython, bpython 以及原生 python
参数:
shell (str) –
指定命令行类型,可设为 ‘ipython’,’bpython’,’python’,或它们的首字母;
若为 None,则按上述优先级进入首个可用的 Python 命令行。
local (dict) – 设定本地变量环境,若为 None,则获取进入之前的变量环境。
banner (str) – 设定欢迎内容,将在进入命令行后展示。
在以下例子中,机器人将
初始化机器人,并找到好友和群聊:
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
# [,
# ,
# ]
关闭所有注册配置:
bot.registered.disable()
重新开启 just_print 函数:
bot.registered.enable(just_print)
查看当前开启的注册配置:
bot.registered.enabled
# []
class wxpy.api.messages.Registered(bot)
保存当前机器人所有已注册的消息配置
参数: bot – 所属的机器人
get_config(msg)
获取给定消息的注册配置。每条消息仅匹配一个注册配置,后注册的配置具有更高的匹配优先级。
参数: msg – 给定的消息
返回: 匹配的回复配置
get_config_by_func(func)
通过给定的函数找到对应的注册配置
参数: func – 给定的函数
返回: 对应的注册配置
enable(func=None)
开启指定函数的对应配置。若不指定函数,则开启所有已注册配置。
参数: func – 指定的函数
disable(func=None)
关闭指定函数的对应配置。若不指定函数,则关闭所有已注册配置。
参数: func – 指定的函数
enabled
检查处于开启状态的配置
返回: 处于开启状态的配置
disabled
检查处于关闭状态的配置
返回: 处于关闭状态的配置
class wxpy.SentMessage(attributes)
程序中通过 .send/reply() 系列方法发出的消息
使用程序发送的消息也将被记录到历史消息 bot.messages 中
提示
大部分属性与 Message
相同
recall()
撤回本条消息 (应为 2 分钟内发出的消息)
可通过访问 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
search(keywords=None, **attributes)
搜索消息记录
参数:
返回:所有匹配的消息
返回类型:wxpy.Messages
# 搜索所有自己发送的,文本中包含 'wxpy' 的消息
bot.messages.search('wxpy', sender=bot.self)
通过利用微信强大的通知能力,我们可以把程序中的警告/日志发到自己的微信上。
wxpy 提供以下两种方式来实现这个需求。
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('现在你又收到了什么?')
class wxpy.WeChatLoggingHandler(receiver=None)
可向指定微信聊天对象发送日志的 Logging Handler
参数:
receiver –
机器人
时,将发送到该机器人的”文件传输助手”聊天对象
时,将发送到该聊天对象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()
放在代码中的任何位置。运行后,就可以从那儿开始探索和调试。
例如,初始化一个机器人,然后看看它能做些什么:
from wxpy import *
bot = Bot()
embed() # 进入 Python 命令行
# 输入对象名称并回车
>>> bot
# Out[1]:
>>> bot.friends()
# Out[2]: [, , ]
wxpy.embed(local=None, banner=’’, shell=None)
进入交互式的 Python 命令行界面,并堵塞当前线程
支持使用 ipython, bpython 以及原生 python
参数:
shell (str) –
指定命令行类型,可设为 ‘ipython’,’bpython’,’python’,或它们的首字母;
若为 None,则按上述优先级进入首个可用的 Python 命令行。
local (dict) – 设定本地变量环境,若为 None,则获取进入之前的变量环境。
banner (str) – 设定欢迎内容,将在进入命令行后展示。
注解
适用于在命令行中边写边探索
第二种情况:想要简单写几行,而不想创建脚本,那么使用 wxpy 命令行边写边探索,更方便。
在命令行中输入 wxpy -h 可快速查看使用说明。
bot1 bot2 bot3…
-c / –cache
-q 宽度 / –console_qr 宽度
-l 等级 / –logging_level 等级 (注意是小写 L,不是 I)
-s 交互界面 / –shell 交互界面
-v / –version
初始化一个名为 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 存在调用限制,建议自行申请。
免费申请: http://www.tuling123.com/
参数: 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)
do_reply(msg, at_member=True)
回复消息,并返回答复文本
参数:
返回: 答复文本
返回类型:str
reply_text(msg, at_member=True)
仅返回消息的答复文本
参数:
返回: 答复文本
返回类型:str
class wxpy.XiaoI(key, secret)
与 wxpy 深度整合的小 i 机器人
需要通过注册获得 key 和 secret
免费申请: http://cloud.xiaoi.com/
参数:
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)
do_reply(msg)
回复消息,并返回答复文本
参数: msg – Message 对象
返回: 答复文本
reply_text(msg)
仅返回答复文本
参数: msg – Message 对象,或消息文本
返回: 答复文本
wxpy.mutual_friends(args)
找到多个微信用户的共同好友
参数: args – 每个参数为一个微信用户的机器人(Bot),或是聊天对象合集(Chats)
返回: 共同好友列表
返回类型: wxpy.Chats
bot1 = Bot()
bot2 = Bot()
# 打印共同好友
for mf in mutual_friends(bot, bot2):
print(mf)
wxpy.ensure_one(found)
确保列表中仅有一个项,并返回这个项,否则抛出 ValueError 异常
通常可用在查找聊天对象时,确保查找结果的唯一性,并直接获取唯一项
参数: found – 列表
返回: 唯一项
bot = Bot()
# 确保只找到了一个叫"游否"的好友,并返回这个好友
my_friend = ensure_one(bot.search('游否'))
#
wxpy.sync_message_in_groups(msg, groups, prefix=None, suffix=None, raise_for_unsupported=False, run_async=True)
将消息同步到多个微信群中
支持以下消息类型
- 但不支持表情商店中的表情
- 仅支持公众号名片,以及自己发出的个人号名片
- 会被转化为 标题 + 链接 形式的纯文本
- 会以文件方式发送
- 会转化为位置名称 + 地图链接 形式的文本消息
参数:
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 微信操作的频率限制,获得限制次数和周期
参数:
返回:限制次数, 限制周期(秒数)
例如,测试发送文本消息的频率限制:
bot = Bot('test.pkl')
# 定义需要检测的操作
def action():
bot.file_helper.send()
# 执行检测
result = detect_freq_limit(action)
# 查看结果
print(result)
# (120, 120.111222333)
wxpy.dont_raise_response_error(func)
装饰器:用于避免被装饰的函数在运行过程中抛出 ResponseError 错误
每当使用 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 进行完善。
通常因为操作频率过高。需要控制频率,避免再次引起该错误。
注意
Web 微信对 加好友、建群 这两种操作的频率限制尤其严格!
对于微信而言,为了机器人避免打扰其他用户,以及控制服务器的负载压力,需要对各种不同的操作进行频率限制。
通常每种操作可有多层频率限制,而每层频率限制分为两个参数:
周期、次数,分布表示: 在 x 周期内,只能发送 y 个请求。
举个例子:
对于 发送消息 操作,可能会是这样 (数值为虚构):
层 | 限制周期 | 限制次数 |
---|---|---|
1 | 2 分钟 | 120 |
2 | 10 分钟 | 300 |
3 | 1 小时 | 1000 |
4 | 24 小时 | 2000 |
可能会有用户在 1 分钟内狂发 100 条消息。
但这样的频率不可能维持一整天,所以一天内 3000 条是足够的。
通过以上方式,微信可实现较为合理的限制。
通常因为操作对象不为好友关系。例如尝试向一位不为好友的群员发送消息时,会引起这个错误。
通常表示机器人已经掉线,需要重新登录。
请重新初始化 Bot
对象,并重新注册消息。
因为重新登录后,聊天对象的 user_name 可能已经变化,所以原先的消息注册也会因此失效。
正是得益于 itchat 的坚实基础,wxpy 才能够在短时间内快速实现这些新的接口和功能。
感谢 itchat 维护者们的辛勤付出。
以下为如何在 wxpy 中混合使用 itchat 的原接口和原始数据。
只需在 wxpy 的 Bot
对象后紧跟 .core.*即可调用 itchat 的原接口。
例如,使用 itchat 的search_friends 接口:
from wxpy import *
bot = Bot()
found = bot.core.search_friends('游否')
注意
通过 itchat 原接口所获取到的结果为原始数据,可能无法直接传递到 wxpy 的对应方法中。
wxpy 的所有 聊天对象 和 消息对象 均基于从 itchat 获取到的数据进行封装。若需使用原始数据,只需在对象后紧跟 .raw。
例如,查看一个 好友
对象的原始数据:
from wxpy import *
bot = Bot()
a_friend = bot.friends()[0]
print(a_friend.raw)
提示
这里罗列了一些常见的问题,在提出新的问题前,请先看完本文。
因为主线程执行完成了,程序自然会退出。
只需在代码结尾加一句embed()
即可堵塞线程,还能进入 Python 命令行:
from wxpy import *
# 你的其他代码...
# 堵塞线程,并进入 Python 命令行
embed()
或者,也可以使用 Bot.join()
仅仅堵塞线程:
bot = Bot()
# 你的其他代码...
# 仅仅堵塞线程
bot.join()
# 机器人登出后会继续往下执行
可启用登陆状态缓存功能,在短时间内重新运行程序,可自动登录。
具体请见Bot
中的 cache_path 参数说明。
wxpy 不依赖于图形界面,因此完全兼容各种纯终端的服务器。
但有一点需要注意,在纯终端环境中,登陆时必须使用”终端二维码”参数。
具体请见 Bot
中的 console_qr 参数说明。
小技巧
遇到以下错误?请使用 Bot
的 console_qr 参数。
FileNotFoundError: [Errno 2] No such file or directory: ‘xdg-open’
wxpy 使用了 Web 微信的通讯协议,因此仅能覆盖 Web 微信本身所具备的功能。
所以以下功能目前 均不支持
send_raw_msg()
转发wxpy 的初衷是帮助人们利用微信来使生活和工作更轻松。
注解
希望每位使用者在使用机器人时
wxpy文档:https://wxpy.readthedocs.io/zh/latest/
itchat文档:
https://itchat.readthedocs.io/zh/latest/
https://github.com/littlecodersh/ItChat