一、介绍QQBot 是一个用 python 实现的、基于腾讯 SmartQQ 协议的简单 QQ 机器人,可运行在 Linux 、 Windows 和 Mac OSX 平台下。 本项目 github 地址: https://github.com/pandolia/qqbot 你可以通过扩展 QQBot 来实现:
二、安装方法在 Python 2.7/3.4/3.5 下使用,用 pip 安装: ?
原 2.0 版的用户请先到 issue74 查看 2.1 版的升级和改动。 注:一般安装有 Python 的系统都已经自带 pip 了。 Windows 下,请确保安装 Python 的时候勾选了 pip 和 Add python.exe to Path。如果系统中没有 pip ,请到 pip主页 下载 get-pip.py 并运行,可将 pip 安装至系统中。 三、使用方法1. 启动 QQBot 在命令行输入: qqbot 。启动过程中会自动弹出二维码图片,需要用手机 QQ 客户端扫码并授权登录。启动成功后,会将本次登录信息保存到本地文件中,下次启动时,可以输入: qqbot -q qq号码 ,先尝试从本地文件中恢复登录信息(不需要手动扫码),只有恢复不成功或登录信息已过期时才会需要手动扫码登录。一般来说,保存的登录信息将在 2 天之后过期。 注意: Linux 下,需要系统中有 gvfs-open 或者 shotwell 命令才能自动弹出二维码图片(一般安装有 GNOME 虚拟文件系统 gvfs 的系统中都会含这两个命令之一)。 Windows10 下,需要系统中已设置了 png 图片文件的默认打开程序才能自动弹出二维码图片。 若系统无法自动弹出二维码图片,可以手动打开图片文件进行扫码,也可以将二维码显示模式设置为 邮箱模式/服务器模式/文本模式 进行扫码,详见本文档的第七节。 2. 操作 QQBot QQBot 启动后,在另一个控制台窗口使用 qq 命令来操作 QQBot ,目前提供以下命令: ?
list 命令提供强大的联系人查询功能,用法示例如下: ?
其中第三、四个参数如果是 key=val 的格式,则应为 name=xx|nick=xx|mark=xx|card=xx|qq=xx 的格式,如果不是 key=val 的格式,则按以下原则进行处理:若是一串数字,则按 QQ 号进行查询,否则,按名称进行查询。 如果存在重名现象,会列出所有重名的联系人。如: ?
将列出所有名为 “机器人测试” 的群。 send 命令中第三个参数和 list 命令中的第三、四个参数格式一致。要注意,如果有重名现象,会给所有重名的联系人发信息。 另外要注意,第二个参数只能是 buddy/group/discuss ,不能是 group-member/discuss-member 。 可以在消息内容中嵌入“/微笑”等表情关键词来向对方发送表情,详见 facemap.py。还可以在消息内容中使用 \n,\t 这两个转义字符(如: send buddy jack 第一行\n第二行)。 群管理命令中的 ginfo 和 minfo 和 list 命令中的第三、四个参数格式一致。例如: ?
以上所有命令都提供对应的 HTTP API 接口,供 web 前端开发者调用,接口的 url 地址为 http://127.0.0.1:8188/{command} ,只需要将 qq 后面的命令各参数用 "/" 分隔开替换 url 中的 command 就可以了,如: http://127.0.0.1:8188/send/buddy/jack/hello ,其他示例详见 urltestbot.txt 。注意:如果命令中含有中文或特殊字符,需要先进行 url 编码( utf8 ),例如,调用 http://127.0.0.1:8188/send/buddy/jack/nihao%20%E4%BD%A0%E5%A5%BD%20wohao 将发送消息 ”nihao 你好 wohao“ 。(提示:在 JavaScript 中,可以使用 encodeURIComponent 函数进行编码)。 另外,QQBot 启动后,用另外一个 QQ 向本 QQ 发送 “--version” ,则 QQBot 会自动回复: “QQBot-v2.x.x” 。 四、实现你自己的 QQ 机器人实现自己的 QQ 机器人非常简单,只需要注册一个自己的消息响应函数。示例代码: ?
注意,上面注册的响应函数的函数名必须为 “onQQMessage” ,函数参数也必须和上面的一致。 将以上代码另存为 sample.py ,关掉前面的 qqbot 进程,再在命令行输入 “python sample.py -q QQ号码” ,就可以启动自己的 QQ 机器人。此时,用另外一个 QQ 向本 QQ 发送消息 “-hello”,则会自动回复 “你好,我是 QQ 机器人”,发送消息 “-stop” 则会关闭 QQ 机器人。 QQBot 开始运行后,每收到一条 QQ 消息,会将消息来源、消息内容以及一个 QQBot 对象传递给上面注册的消息响应函数。其中: ?
一个 QContact 对象代表一个联系人,它的 ctype 属性可以为 'buddy'/'group'/'discuss'/'group-member'/'discuss-member' ,代表 好友/群/讨论组/群成员/讨论组成员 。注意所有 QContact 对象都是 只读对象 ,只能读取它的属性,不能设置它的属性,也不能向它添加额外的属性。 不同类型的 QContact 对象的 nick/mark/card/name 属性所代表的含义有所不同,参见 contact-attr-meannings.png 。 可以调用 QQBot 对象的 SendTo 接口向 QContact 对象发送消息,但要注意:只可以向 好友/群/讨论组 发消息, 不可以向 群成员/讨论组成员 发送消息 。 除了直接运行 sample.py 文件,还可以将此文件当做一个插件,在 qqbot 的运行过程中动态的加载和卸载。将该文件保存在系统中可以 import 到的目录下(如 python 的安装目录下的 Lib/site-packages 目录),之后,运行 qqbot ,待 QQBot 完全启动后,在另一个控制台输入 qq plug sample ,则可以将此文件中的 onQQMessage 函数注册到 QQBot 的相应事件上去。输入 qq unplugin sample 可以卸载此插件。可以同时加载多个插件,此时各插件中的相应函数会依次被调用(但调用顺序和加载次序无关)。 如果按插件的形式加载 sample.py ,则该文件的内容可简化为: ?
插件本质上是一个模块,因此,它可以是一个 py 文件,也可以是一个 package ,只要它放在系统中可以 import 到的目录即可(本文档第七节介绍了指定插件目录的方法)。建议尽量使用插件的形式来扩展 QQBot 。 原 2.1.10 版中的使用继承 QQBot 类来进行扩展的方式可以继续使用,但是,若使用此方式,则插件功能无法使用。 五、 QQBot 对象的接口QQBot 对象提供 List/SendTo/GroupSetAdmin/GroupSetCard/GroupShut/GroupKick/Stop/Restart 八个公开接口,一般情况下,请勿 调用/存取 此对象的其他 方法/属性 。以下介绍前 6 个接口。 (1) bot.List(tinfo, [cinfo]) --> [contact0, contact1, ..., ]/[]/None 对应上面的 list 命令。返回联系人对象( QContact 对象)列表或者 None 。 List 接口的第一个参数 tinfo 可以为 'buddy'/'group'/'discuss' ,第二个参数是可选的(和 list 命令的第三个参数格式一致)。示例: ?
List 接口的第一个参数 tinfo 也可以是一个 ctype 等于 'group'/'discuss' 的 QContact 对象,此时,返回的是该 群/讨论组 的成员列表,如以下第二句和第三句分别返回 群“456班” 的成员列表和该群中名片为 “jack” 的成员列表: ?
注意上面第三句不允许是 bot.List(g, card='jack') 的格式。 List 接口的内部执行顺序: 首先在 QQBot 的联系人数据库内查找 tinfo 所代表的联系人列表;若数据库内已有此列表,则在此列表内进行搜索,并返回一个包含 “此列表中所有和 cinfo 匹配的联系人” 的列表;若数据库内没有此列表,则向 QQ 服务器请求数据获取联系人列表,获取成功后将联系人列表保存到数据库内,然后再进行搜索并返回一个包含 “此列表中所有和 cinfo 匹配的联系人” 的列表;如果在向 QQ 服务器请求数据的过程中出错了,则打印相关的失败信息,并返回 None 。 List 接口返回值的含义: 返回一个非空列表表示 tinfo 所指定的联系人列表内所有和 cinfo 匹配的联系人;返回一个空列表表示该联系人列表内没有和 cinfo 匹配的联系人;返回 None 表示向 QQ 服务器请求联系人列表和资料失败,不知道是否有相匹配的联系人。 调用 List 接口后, 务必 先根据以上三种情况对返回值进行判断,然后再执行后续代码。 (2) bot.SendTo(contact, content) --> '向 xx 发消息成功'/'错误:...' 向联系人发送消息。第一个参数为 QContact 对象,第二个参数为消息内容。再次提醒: 只可以向 好友/群/讨论组 发消息, 不允许向 群成员/讨论组成员 发消息 。 可以在消息内容中嵌入“/微笑”等表情关键词来向对方发送表情,详见 facemap.py。 若发送成功,返回字符串('向 xx 发消息成功')。否则,返回含错误原因的字符串('错误:...')。 (3) bot.GroupXXX(group, membs[, arg]) --> ['成功:...', '成功:...', '错误:...'] 对应第三节的群管理命令,共四个接口:
其中第一个参数 group 为 群对象( ctype 等于 'group' 的 QContact 对象),第二个参数 membs 为被操作的成员列表。返回值为 membs 中各成员的操作信息。 注意: 1) 第二个参数 membs 是一个 list 对象(如: [memb0,memb1,...] ),而不是一个 QContact 对象; 2) 若 membs 中的某个成员是管理员,则除 SetCard 外的其他接口可能对其无效,尽管此时返回成功信息。 3) 使用这四个接口时,请自行保证登录的用户是该群的管理员,且 membs 中的各成员均属于该群。 六、 注册回调函数、被他人 @ 的通知、定制定时任务注册回调函数 除了上面提到的 onQQMessage 响应函数,还可以注册 onNewContact/onLostContact/onInterval/onStartupComplete/onFetchComplete 五种事件的回调函数,所有事件以及函数参数格式、含义如下: ?
再次提醒:注册的响应函数的函数名以及函数参数(数量和名称)必须和上面一致,不允许注册其他名称的函数 。 被群内其他成员 @ 的通知 QQBot 收到群消息时,会先根据消息内容判断是否有人 @ 自己。如果是,则在消息内容的开头加一个 '[@ME] ' 的标记,再传递给 onQQMessage 函数;否则,将消息内容中的所有 '@ME' 替换成 '@Me' 再传给 onQQMessage 。因此,在 onQQMessage 函数内,只需要判断 content 内是否含有 '@ME' 就知道自己是否被消息发送者 @ 了。例如: ?
定制定时任务 从 2.1.13 起, qqbot 中提供一个功能强大的函数装饰器 -- QQBotSched 来定制定时任务,示例代码: ?
以上代码运行(或以插件形式加载)后,每到 11:55 和 17:55 ,都会自动向 群“456班” 发送消息:“同志们:开饭啦啦啦啦啦啦!!!” 。 QQBotSched 装饰器接受 year, month, day, week, day_of_week, hour, minute, second, start_date, end_date, timezone 共计 11 个关键词作为参数,每个参数表示任务的定制时间的分量所应匹配的值。例如: hour='11,17' 表示应在 11:xx 或 17:xx 执行任务, minute='55' 表示应在 xx:55 执行任务, minute='0-55/5' 表示应在 xx:x0 或 xx:x5 执行任务。 QQBotSched 是对 Python 的定时任务框架 apscheduler 的简单封装,其各项参数应采用 Unix 系统中的 crontab 格式输入。有关 crontab 以及 Python 的定时任务框架 apscheduler 的内容可参见以下参考资料:
注册回调函数和定制定时任务的注意事项
七、二维码管理器、QQBot 配置及命令行参数二维码的显示模式 SmartQQ 登录时需要用手机 QQ 扫描二维码图片,在 QQBot 中,二维码图片可以通过以下三种模式显示:
GUI 模式是默认的模式,只适用于个人电脑。邮箱模式可以适用于个人电脑和远程服务器。服务器模式一般只在有公网ip的系统中使用。如果使用 QQ 邮箱来接收二维码,则当发送二维码图片后,手机 QQ 客户端会立即收到通知,在手机 QQ 客户端上打开邮件,再长按二维码就可以扫描了。文本模式方便在开发过程或者服务器部署时使用,为开发者提供快捷方式登陆 QQ ,注意:文本模式在某些 terminal 中(如 gnome-terminal , mate-terminal )的显示效果不太好。 注意:当开启了 邮箱模式/服务器模式/文本模式 时, GUI 模式是关闭的,登陆时不会自动弹出二维码图片。 每次登录时会创建一个二维码管理器 (QrcodeManager 对象) ,二维码管理器会根据配置文件及命令行参数来选择二维码图片的显示方式。 配置文件的使用方法 配置文件为 ~/.qqbot-tmp/v2.1.conf ,第一次运行 QQBot 后就会自动创建这个配置文件,其中内容如下: ?
可以在配置文件中添加自己的用户配置(即在该文件的字典中新增一个 item ,此 item 的 key 就代表一个用户),例如,该文件中已有的 somebody 项目就代表名为 somebody 的用户,运行 QQBot 时,输入 qqbot -u somebody 或 python sample.py -u somebody ,则会加载 somebody 项目下的各项配置。 下面介绍配置文件中各项配置的功能,以下内容均假定已修改了 somebody 下的配置,且以 qqbot -u somebody 或 python sample.py -u somebody 的方式运行。 邮箱模式的配置( mailAccount 和 mailAuthCode ) 如果需要使用邮箱模式显示二维码,可以将 mailAccount 和 mailAuthCode 项中分别设置为邮箱账号和授权码,运行后,二维码管理器会将二维码图片发送至该邮箱。 注意:授权码不是邮箱的登录密码,而是邮箱服务商提供的开通 IMAP/SMTP 服务的授权码, QQ 邮箱可以在网页版的邮箱设置里面开通此项服务,并得到授权码。如果只定义了 mailAccount 而没定义 mailAuthCode ,则程序运行的开始时会要求手工输入此授权码。 由于网易的邮箱对 IMAP 协议的支持非常有限,无法在 QQBot 中使用。 QQ 的邮箱已通过测试,其他服务商的邮箱还未测试过,因此建议还是使用 QQ 邮箱。 服务器模式的配置( httpServerIP 和 httpServerPort ) 如果需要使用服务器模式,可以配置 httpServerIP 和 httpServerPort 项,一般来说应该设置为公网 ip 。服务器模式开启后,可以通过 http://httpServerIP:httpServerPort/qqbot/qrcode 来访问二维码图片。 当邮箱模式和服务器模式同时开启时,发邮件时不会发送真正的图片,只会将图片地址发到邮箱中去,而且只发送一次,二维码过期时刷新一下邮件就可以了。如果只开启邮箱模式,则发邮件时会发送真正的图片,当二维码过期时,需要将邮件设置为已读(用手机 QQ 打开邮件后该邮件就是已读了),之后才会发送最新的二维码图片。 自动登录的 QQ 号码( qq ) 配置文件中每个用户都有 qq 这一项,若此项已设置为某 QQ 号码,会先使用此 QQ 号上次登录保存的登录信息来自动登录。 掉线后自动重启( restartOnOffline ) 如果配置文件中将 restartOnOffline 项设置为 True ,则当 QQBot 掉线或出错终止时,会自动重新启动 QQBot 。 联系人列表更新的间歇时间( fetchInterval ) QQBot 启动后,会在后台获取并更新联系人列表,当所有联系人列表获取完毕后,会 sleep 两分钟然后开始下一轮获取及更新。可以在配置文件中将 fetchInterval 项设置为其他值(单位:秒)来控制这个间歇时间。如果此值设置为负数,则只进行一次联系人列表获取(之后再也不获取了)。 联系人列表获取完成后再启动( startAfterFetch ) 一般情况下,扫码登录完成就立即启动 QQBot,同时开始在后台获取并更新联系人列表。如果将配置文件中的 startAfterFetch 设置为 True ,则 QQBot 会等待所有联系人列表获取完成后才启动 ,注意,如果联系人较多,会耗费较长的时间。 QQBot-term 服务器端口号( termServerPort ) QQBot 启动后,会开启一个 QQBot-term 服务器监听用户通过 qq 命令行工具发过来的操作命令以及通过 HTTP API 接口发过来的操作命令,此服务器端口号默认为 8188 ,可以通过修改 termServerPort 的值来修改此端口号。 如果配置的 QQBot-term 服务器端口号不是默认的 8188 ,那么在运行 qq 命令时,需要在第一个参数中指定端口号,如: ?
同样,HTTP API 接口的端口号也需要改变,如: http://127.0.0.1:8100/send/buddy/jack/hello 。 如果需要在同一台机器上登录多个 QQ 号码,则需要对不同的 QQ 号码设置不同的 termServerPort 和 httpServerPort ,以免端口号冲突。 文本模式显示二维码(cmdQrcode) 若 cmdQrcode 项设置为 True ,则会在 term 中以文本模式显示二维码。注意:要使用文本模式,需要自行安装 pillow 库,可使用 pip 安装。 调试模式( debug ) 若 debug 项设置为 True ,则运行过程中会打印调试信息。 需要被监视的联系人列表( monitorTables ) 一般情况下联系人变动事件(onNewContact/onLostContact)滞后 5 ~ 10 分钟,可以将关心的联系人列表加入到配置文件的 monitorTables 中去,若 monitorTables 中的列表数量较少,则被监视的列表中的联系人变动事件延后时间将大幅缩短。例如,如果关心 群”456班“ 的联系人变动,可以设置 monitorTables = ['group-member-456班'] ,则该群的成员变动事件仅滞后 1~3 秒。 插件的配置( pluginPath 和 plugins ) 一般情况下,插件需要存放在系统的 import 目录下,可以在 pluginPath 选项中配置插件的存放目录,放在该选项指定的目录下也可以被 QQBot 动态加载。另外,在 plugins 选项中可以指定 QQBot 启动时需要加载的插件(注意:这些插件需要保存在系统的 import 目录下或 pluginPath 所指定的目录下)。 命令行参数及配置的优先级 配置文件中的所有选项都有对应的命令行参数,在命令行参数中输入的选项优先级比配置文件高。输入 qqbot -h 或 python sample.py -h 可查看所有命令行参数格式。 程序一共有四个级别的配置,其优先级如下: ?
其中:根配置 是固定的,用户无法修改; 默认配置 和 用户配置 可由用户在 v2.1.conf 文件中进行修改;最后,还可以在 命令行参数 中输入配置。 八、 smartqq 协议支持及限制本项目已实现绝大部分 smartqq 协议支持的功能,如下:
其他功能
因 smartqq 协议的限制,以下问题无解决办法
九、参考资料QQBot 参考了以下开源项目:
在此感谢以上三位作者的无私分享,特别是感谢 ScienJus 对 SmartQQ 协议所做出的深入细致的分析。 |
|