一,、介紹QQBot 是一個用 python 實(shí)現(xiàn)的、基于騰訊 SmartQQ 協(xié)議的簡單 QQ 機(jī)器人,可運(yùn)行在 Linux ,、 Windows 和 Mac OSX 平臺下。 本項(xiàng)目 github 地址: https://github.com/pandolia/qqbot 你可以通過擴(kuò)展 QQBot 來實(shí)現(xiàn):
二,、安裝方法在 Python 2.7/3.4/3.5 下使用,用 pip 安裝: ?
原 2.0 版的用戶請先到 issue74 查看 2.1 版的升級和改動,。 注:一般安裝有 Python 的系統(tǒng)都已經(jīng)自帶 pip 了,。 Windows 下,請確保安裝 Python 的時候勾選了 pip 和 Add python.exe to Path。如果系統(tǒng)中沒有 pip ,,請到 pip主頁 下載 get-pip.py 并運(yùn)行,,可將 pip 安裝至系統(tǒng)中。 三,、使用方法1. 啟動 QQBot 在命令行輸入: qqbot ,。啟動過程中會自動彈出二維碼圖片,需要用手機(jī) QQ 客戶端掃碼并授權(quán)登錄,。啟動成功后,,會將本次登錄信息保存到本地文件中,下次啟動時,,可以輸入: qqbot -q qq號碼 ,,先嘗試從本地文件中恢復(fù)登錄信息(不需要手動掃碼),只有恢復(fù)不成功或登錄信息已過期時才會需要手動掃碼登錄,。一般來說,,保存的登錄信息將在 2 天之后過期。 注意: Linux 下,,需要系統(tǒng)中有 gvfs-open 或者 shotwell 命令才能自動彈出二維碼圖片(一般安裝有 GNOME 虛擬文件系統(tǒng) gvfs 的系統(tǒng)中都會含這兩個命令之一),。 Windows10 下,需要系統(tǒng)中已設(shè)置了 png 圖片文件的默認(rèn)打開程序才能自動彈出二維碼圖片,。 若系統(tǒng)無法自動彈出二維碼圖片,,可以手動打開圖片文件進(jìn)行掃碼,也可以將二維碼顯示模式設(shè)置為 郵箱模式/服務(wù)器模式/文本模式 進(jìn)行掃碼,,詳見本文檔的第七節(jié),。 2. 操作 QQBot QQBot 啟動后,在另一個控制臺窗口使用 qq 命令來操作 QQBot ,,目前提供以下命令: ?
list 命令提供強(qiáng)大的聯(lián)系人查詢功能,,用法示例如下: ?
其中第三、四個參數(shù)如果是 key=val 的格式,,則應(yīng)為 name=xx|nick=xx|mark=xx|card=xx|qq=xx 的格式,,如果不是 key=val 的格式,則按以下原則進(jìn)行處理:若是一串?dāng)?shù)字,,則按 QQ 號進(jìn)行查詢,,否則,按名稱進(jìn)行查詢,。 如果存在重名現(xiàn)象,,會列出所有重名的聯(lián)系人。如: ?
將列出所有名為 “機(jī)器人測試” 的群。 send 命令中第三個參數(shù)和 list 命令中的第三,、四個參數(shù)格式一致,。要注意,如果有重名現(xiàn)象,,會給所有重名的聯(lián)系人發(fā)信息,。 另外要注意,第二個參數(shù)只能是 buddy/group/discuss ,,不能是 group-member/discuss-member ,。 可以在消息內(nèi)容中嵌入“/微笑”等表情關(guān)鍵詞來向?qū)Ψ桨l(fā)送表情,詳見 facemap.py,。還可以在消息內(nèi)容中使用 \n,\t 這兩個轉(zhuǎn)義字符(如: send buddy jack 第一行\(zhòng)n第二行),。 群管理命令中的 ginfo 和 minfo 和 list 命令中的第三、四個參數(shù)格式一致,。例如: ?
以上所有命令都提供對應(yīng)的 HTTP API 接口,,供 web 前端開發(fā)者調(diào)用,接口的 url 地址為 http://127.0.0.1:8188/{command} ,,只需要將 qq 后面的命令各參數(shù)用 "/" 分隔開替換 url 中的 command 就可以了,,如: http://127.0.0.1:8188/send/buddy/jack/hello ,其他示例詳見 urltestbot.txt ,。注意:如果命令中含有中文或特殊字符,,需要先進(jìn)行 url 編碼( utf8 ),例如,,調(diào)用 http://127.0.0.1:8188/send/buddy/jack/nihao%20%E4%BD%A0%E5%A5%BD%20wohao 將發(fā)送消息 ”nihao 你好 wohao“ ,。(提示:在 JavaScript 中,可以使用 encodeURIComponent 函數(shù)進(jìn)行編碼),。 另外,,QQBot 啟動后,用另外一個 QQ 向本 QQ 發(fā)送 “--version” ,,則 QQBot 會自動回復(fù): “QQBot-v2.x.x” 。 四,、實(shí)現(xiàn)你自己的 QQ 機(jī)器人實(shí)現(xiàn)自己的 QQ 機(jī)器人非常簡單,,只需要注冊一個自己的消息響應(yīng)函數(shù)。示例代碼: ?
注意,,上面注冊的響應(yīng)函數(shù)的函數(shù)名必須為 “onQQMessage” ,函數(shù)參數(shù)也必須和上面的一致,。 將以上代碼另存為 sample.py ,,關(guān)掉前面的 qqbot 進(jìn)程,再在命令行輸入 “python sample.py -q QQ號碼” ,就可以啟動自己的 QQ 機(jī)器人,。此時,,用另外一個 QQ 向本 QQ 發(fā)送消息 “-hello”,則會自動回復(fù) “你好,,我是 QQ 機(jī)器人”,,發(fā)送消息 “-stop” 則會關(guān)閉 QQ 機(jī)器人。 QQBot 開始運(yùn)行后,,每收到一條 QQ 消息,,會將消息來源、消息內(nèi)容以及一個 QQBot 對象傳遞給上面注冊的消息響應(yīng)函數(shù),。其中: ?
一個 QContact 對象代表一個聯(lián)系人,,它的 ctype 屬性可以為 'buddy'/'group'/'discuss'/'group-member'/'discuss-member' ,,代表 好友/群/討論組/群成員/討論組成員 。注意所有 QContact 對象都是 只讀對象 ,,只能讀取它的屬性,,不能設(shè)置它的屬性,也不能向它添加額外的屬性,。 不同類型的 QContact 對象的 nick/mark/card/name 屬性所代表的含義有所不同,,參見 contact-attr-meannings.png 。 可以調(diào)用 QQBot 對象的 SendTo 接口向 QContact 對象發(fā)送消息,,但要注意:只可以向 好友/群/討論組 發(fā)消息,, 不可以向 群成員/討論組成員 發(fā)送消息 。 除了直接運(yùn)行 sample.py 文件,,還可以將此文件當(dāng)做一個插件,,在 qqbot 的運(yùn)行過程中動態(tài)的加載和卸載。將該文件保存在系統(tǒng)中可以 import 到的目錄下(如 python 的安裝目錄下的 Lib/site-packages 目錄),,之后,,運(yùn)行 qqbot ,待 QQBot 完全啟動后,,在另一個控制臺輸入 qq plug sample ,,則可以將此文件中的 onQQMessage 函數(shù)注冊到 QQBot 的相應(yīng)事件上去,。輸入 qq unplugin sample 可以卸載此插件??梢酝瑫r加載多個插件,,此時各插件中的相應(yīng)函數(shù)會依次被調(diào)用(但調(diào)用順序和加載次序無關(guān))。 如果按插件的形式加載 sample.py ,,則該文件的內(nèi)容可簡化為: ?
插件本質(zhì)上是一個模塊,因此,,它可以是一個 py 文件,,也可以是一個 package ,只要它放在系統(tǒng)中可以 import 到的目錄即可(本文檔第七節(jié)介紹了指定插件目錄的方法),。建議盡量使用插件的形式來擴(kuò)展 QQBot ,。 原 2.1.10 版中的使用繼承 QQBot 類來進(jìn)行擴(kuò)展的方式可以繼續(xù)使用,但是,,若使用此方式,,則插件功能無法使用。 五,、 QQBot 對象的接口QQBot 對象提供 List/SendTo/GroupSetAdmin/GroupSetCard/GroupShut/GroupKick/Stop/Restart 八個公開接口,,一般情況下,請勿 調(diào)用/存取 此對象的其他 方法/屬性 ,。以下介紹前 6 個接口,。 (1) bot.List(tinfo, [cinfo]) --> [contact0, contact1, ..., ]/[]/None 對應(yīng)上面的 list 命令。返回聯(lián)系人對象( QContact 對象)列表或者 None ,。 List 接口的第一個參數(shù) tinfo 可以為 'buddy'/'group'/'discuss' ,,第二個參數(shù)是可選的(和 list 命令的第三個參數(shù)格式一致)。示例: ?
List 接口的第一個參數(shù) tinfo 也可以是一個 ctype 等于 'group'/'discuss' 的 QContact 對象,,此時,,返回的是該 群/討論組 的成員列表,如以下第二句和第三句分別返回 群“456班” 的成員列表和該群中名片為 “jack” 的成員列表: ?
注意上面第三句不允許是 bot.List(g, card='jack') 的格式,。 List 接口的內(nèi)部執(zhí)行順序: 首先在 QQBot 的聯(lián)系人數(shù)據(jù)庫內(nèi)查找 tinfo 所代表的聯(lián)系人列表,;若數(shù)據(jù)庫內(nèi)已有此列表,則在此列表內(nèi)進(jìn)行搜索,,并返回一個包含 “此列表中所有和 cinfo 匹配的聯(lián)系人” 的列表,;若數(shù)據(jù)庫內(nèi)沒有此列表,則向 QQ 服務(wù)器請求數(shù)據(jù)獲取聯(lián)系人列表,,獲取成功后將聯(lián)系人列表保存到數(shù)據(jù)庫內(nèi),然后再進(jìn)行搜索并返回一個包含 “此列表中所有和 cinfo 匹配的聯(lián)系人” 的列表,;如果在向 QQ 服務(wù)器請求數(shù)據(jù)的過程中出錯了,,則打印相關(guān)的失敗信息,,并返回 None 。 List 接口返回值的含義: 返回一個非空列表表示 tinfo 所指定的聯(lián)系人列表內(nèi)所有和 cinfo 匹配的聯(lián)系人,;返回一個空列表表示該聯(lián)系人列表內(nèi)沒有和 cinfo 匹配的聯(lián)系人,;返回 None 表示向 QQ 服務(wù)器請求聯(lián)系人列表和資料失敗,不知道是否有相匹配的聯(lián)系人,。 調(diào)用 List 接口后,, 務(wù)必 先根據(jù)以上三種情況對返回值進(jìn)行判斷,然后再執(zhí)行后續(xù)代碼,。 (2) bot.SendTo(contact, content) --> '向 xx 發(fā)消息成功'/'錯誤:...' 向聯(lián)系人發(fā)送消息,。第一個參數(shù)為 QContact 對象,第二個參數(shù)為消息內(nèi)容,。再次提醒: 只可以向 好友/群/討論組 發(fā)消息,, 不允許向 群成員/討論組成員 發(fā)消息 。 可以在消息內(nèi)容中嵌入“/微笑”等表情關(guān)鍵詞來向?qū)Ψ桨l(fā)送表情,,詳見 facemap.py,。 若發(fā)送成功,返回字符串('向 xx 發(fā)消息成功'),。否則,,返回含錯誤原因的字符串('錯誤:...')。 (3) bot.GroupXXX(group, membs[, arg]) --> ['成功:...', '成功:...', '錯誤:...'] 對應(yīng)第三節(jié)的群管理命令,,共四個接口:
其中第一個參數(shù) group 為 群對象( ctype 等于 'group' 的 QContact 對象),,第二個參數(shù) membs 為被操作的成員列表。返回值為 membs 中各成員的操作信息,。 注意: 1) 第二個參數(shù) membs 是一個 list 對象(如: [memb0,memb1,...] ),,而不是一個 QContact 對象; 2) 若 membs 中的某個成員是管理員,,則除 SetCard 外的其他接口可能對其無效,,盡管此時返回成功信息。 3) 使用這四個接口時,,請自行保證登錄的用戶是該群的管理員,,且 membs 中的各成員均屬于該群。 六,、 注冊回調(diào)函數(shù),、被他人 @ 的通知、定制定時任務(wù)注冊回調(diào)函數(shù) 除了上面提到的 onQQMessage 響應(yīng)函數(shù),,還可以注冊 onNewContact/onLostContact/onInterval/onStartupComplete/onFetchComplete 五種事件的回調(diào)函數(shù),,所有事件以及函數(shù)參數(shù)格式、含義如下: ?
再次提醒:注冊的響應(yīng)函數(shù)的函數(shù)名以及函數(shù)參數(shù)(數(shù)量和名稱)必須和上面一致,,不允許注冊其他名稱的函數(shù) ,。 被群內(nèi)其他成員 @ 的通知 QQBot 收到群消息時,會先根據(jù)消息內(nèi)容判斷是否有人 @ 自己,。如果是,,則在消息內(nèi)容的開頭加一個 '[@ME] ' 的標(biāo)記,再傳遞給 onQQMessage 函數(shù),;否則,,將消息內(nèi)容中的所有 '@ME' 替換成 '@Me' 再傳給 onQQMessage 。因此,,在 onQQMessage 函數(shù)內(nèi),,只需要判斷 content 內(nèi)是否含有 '@ME' 就知道自己是否被消息發(fā)送者 @ 了。例如: ?
定制定時任務(wù) 從 2.1.13 起,, qqbot 中提供一個功能強(qiáng)大的函數(shù)裝飾器 -- QQBotSched 來定制定時任務(wù),示例代碼: ?
以上代碼運(yùn)行(或以插件形式加載)后,,每到 11:55 和 17:55 ,,都會自動向 群“456班” 發(fā)送消息:“同志們:開飯啦啦啦啦啦啦!??!” ,。 QQBotSched 裝飾器接受 year, month, day, week, day_of_week, hour, minute, second, start_date, end_date, timezone 共計(jì) 11 個關(guān)鍵詞作為參數(shù),,每個參數(shù)表示任務(wù)的定制時間的分量所應(yīng)匹配的值,。例如: hour='11,17' 表示應(yīng)在 11:xx 或 17:xx 執(zhí)行任務(wù), minute='55' 表示應(yīng)在 xx:55 執(zhí)行任務(wù),, minute='0-55/5' 表示應(yīng)在 xx:x0 或 xx:x5 執(zhí)行任務(wù),。 QQBotSched 是對 Python 的定時任務(wù)框架 apscheduler 的簡單封裝,其各項(xiàng)參數(shù)應(yīng)采用 Unix 系統(tǒng)中的 crontab 格式輸入,。有關(guān) crontab 以及 Python 的定時任務(wù)框架 apscheduler 的內(nèi)容可參見以下參考資料:
注冊回調(diào)函數(shù)和定制定時任務(wù)的注意事項(xiàng)
七,、二維碼管理器,、QQBot 配置及命令行參數(shù)二維碼的顯示模式 SmartQQ 登錄時需要用手機(jī) QQ 掃描二維碼圖片,在 QQBot 中,,二維碼圖片可以通過以下三種模式顯示:
GUI 模式是默認(rèn)的模式,,只適用于個人電腦。郵箱模式可以適用于個人電腦和遠(yuǎn)程服務(wù)器,。服務(wù)器模式一般只在有公網(wǎng)ip的系統(tǒng)中使用,。如果使用 QQ 郵箱來接收二維碼,則當(dāng)發(fā)送二維碼圖片后,,手機(jī) QQ 客戶端會立即收到通知,,在手機(jī) QQ 客戶端上打開郵件,再長按二維碼就可以掃描了,。文本模式方便在開發(fā)過程或者服務(wù)器部署時使用,,為開發(fā)者提供快捷方式登陸 QQ ,,注意:文本模式在某些 terminal 中(如 gnome-terminal , mate-terminal )的顯示效果不太好,。 注意:當(dāng)開啟了 郵箱模式/服務(wù)器模式/文本模式 時,, GUI 模式是關(guān)閉的,登陸時不會自動彈出二維碼圖片,。 每次登錄時會創(chuàng)建一個二維碼管理器 (QrcodeManager 對象) ,,二維碼管理器會根據(jù)配置文件及命令行參數(shù)來選擇二維碼圖片的顯示方式。 配置文件的使用方法 配置文件為 ~/.qqbot-tmp/v2.1.conf ,,第一次運(yùn)行 QQBot 后就會自動創(chuàng)建這個配置文件,,其中內(nèi)容如下: ?
可以在配置文件中添加自己的用戶配置(即在該文件的字典中新增一個 item ,,此 item 的 key 就代表一個用戶),例如,,該文件中已有的 somebody 項(xiàng)目就代表名為 somebody 的用戶,,運(yùn)行 QQBot 時,輸入 qqbot -u somebody 或 python sample.py -u somebody ,,則會加載 somebody 項(xiàng)目下的各項(xiàng)配置,。 下面介紹配置文件中各項(xiàng)配置的功能,以下內(nèi)容均假定已修改了 somebody 下的配置,,且以 qqbot -u somebody 或 python sample.py -u somebody 的方式運(yùn)行,。 郵箱模式的配置( mailAccount 和 mailAuthCode ) 如果需要使用郵箱模式顯示二維碼,可以將 mailAccount 和 mailAuthCode 項(xiàng)中分別設(shè)置為郵箱賬號和授權(quán)碼,,運(yùn)行后,,二維碼管理器會將二維碼圖片發(fā)送至該郵箱。 注意:授權(quán)碼不是郵箱的登錄密碼,,而是郵箱服務(wù)商提供的開通 IMAP/SMTP 服務(wù)的授權(quán)碼,, QQ 郵箱可以在網(wǎng)頁版的郵箱設(shè)置里面開通此項(xiàng)服務(wù),并得到授權(quán)碼,。如果只定義了 mailAccount 而沒定義 mailAuthCode ,,則程序運(yùn)行的開始時會要求手工輸入此授權(quán)碼。 由于網(wǎng)易的郵箱對 IMAP 協(xié)議的支持非常有限,,無法在 QQBot 中使用,。 QQ 的郵箱已通過測試,其他服務(wù)商的郵箱還未測試過,因此建議還是使用 QQ 郵箱,。 服務(wù)器模式的配置( httpServerIP 和 httpServerPort ) 如果需要使用服務(wù)器模式,,可以配置 httpServerIP 和 httpServerPort 項(xiàng),一般來說應(yīng)該設(shè)置為公網(wǎng) ip ,。服務(wù)器模式開啟后,,可以通過 http://httpServerIP:httpServerPort/qqbot/qrcode 來訪問二維碼圖片。 當(dāng)郵箱模式和服務(wù)器模式同時開啟時,,發(fā)郵件時不會發(fā)送真正的圖片,,只會將圖片地址發(fā)到郵箱中去,而且只發(fā)送一次,,二維碼過期時刷新一下郵件就可以了。如果只開啟郵箱模式,,則發(fā)郵件時會發(fā)送真正的圖片,,當(dāng)二維碼過期時,需要將郵件設(shè)置為已讀(用手機(jī) QQ 打開郵件后該郵件就是已讀了),,之后才會發(fā)送最新的二維碼圖片,。 自動登錄的 QQ 號碼( qq ) 配置文件中每個用戶都有 qq 這一項(xiàng),若此項(xiàng)已設(shè)置為某 QQ 號碼,,會先使用此 QQ 號上次登錄保存的登錄信息來自動登錄,。 掉線后自動重啟( restartOnOffline ) 如果配置文件中將 restartOnOffline 項(xiàng)設(shè)置為 True ,則當(dāng) QQBot 掉線或出錯終止時,,會自動重新啟動 QQBot ,。 聯(lián)系人列表更新的間歇時間( fetchInterval ) QQBot 啟動后,會在后臺獲取并更新聯(lián)系人列表,,當(dāng)所有聯(lián)系人列表獲取完畢后,,會 sleep 兩分鐘然后開始下一輪獲取及更新??梢栽谂渲梦募袑?fetchInterval 項(xiàng)設(shè)置為其他值(單位:秒)來控制這個間歇時間,。如果此值設(shè)置為負(fù)數(shù),則只進(jìn)行一次聯(lián)系人列表獲?。ㄖ笤僖膊猾@取了),。 聯(lián)系人列表獲取完成后再啟動( startAfterFetch ) 一般情況下,掃碼登錄完成就立即啟動 QQBot,,同時開始在后臺獲取并更新聯(lián)系人列表,。如果將配置文件中的 startAfterFetch 設(shè)置為 True ,則 QQBot 會等待所有聯(lián)系人列表獲取完成后才啟動 ,,注意,,如果聯(lián)系人較多,會耗費(fèi)較長的時間。 QQBot-term 服務(wù)器端口號( termServerPort ) QQBot 啟動后,,會開啟一個 QQBot-term 服務(wù)器監(jiān)聽用戶通過 qq 命令行工具發(fā)過來的操作命令以及通過 HTTP API 接口發(fā)過來的操作命令,,此服務(wù)器端口號默認(rèn)為 8188 ,可以通過修改 termServerPort 的值來修改此端口號,。 如果配置的 QQBot-term 服務(wù)器端口號不是默認(rèn)的 8188 ,那么在運(yùn)行 qq 命令時,,需要在第一個參數(shù)中指定端口號,如: ?
同樣,,HTTP API 接口的端口號也需要改變,,如: http://127.0.0.1:8100/send/buddy/jack/hello 。 如果需要在同一臺機(jī)器上登錄多個 QQ 號碼,,則需要對不同的 QQ 號碼設(shè)置不同的 termServerPort 和 httpServerPort ,,以免端口號沖突,。 文本模式顯示二維碼(cmdQrcode) 若 cmdQrcode 項(xiàng)設(shè)置為 True ,,則會在 term 中以文本模式顯示二維碼。注意:要使用文本模式,,需要自行安裝 pillow 庫,可使用 pip 安裝,。 調(diào)試模式( debug ) 若 debug 項(xiàng)設(shè)置為 True ,,則運(yùn)行過程中會打印調(diào)試信息,。 需要被監(jiān)視的聯(lián)系人列表( monitorTables ) 一般情況下聯(lián)系人變動事件(onNewContact/onLostContact)滯后 5 ~ 10 分鐘,,可以將關(guān)心的聯(lián)系人列表加入到配置文件的 monitorTables 中去,,若 monitorTables 中的列表數(shù)量較少,,則被監(jiān)視的列表中的聯(lián)系人變動事件延后時間將大幅縮短,。例如,,如果關(guān)心 群”456班“ 的聯(lián)系人變動,,可以設(shè)置 monitorTables = ['group-member-456班'] ,則該群的成員變動事件僅滯后 1~3 秒,。 插件的配置( pluginPath 和 plugins ) 一般情況下,插件需要存放在系統(tǒng)的 import 目錄下,,可以在 pluginPath 選項(xiàng)中配置插件的存放目錄,放在該選項(xiàng)指定的目錄下也可以被 QQBot 動態(tài)加載,。另外,,在 plugins 選項(xiàng)中可以指定 QQBot 啟動時需要加載的插件(注意:這些插件需要保存在系統(tǒng)的 import 目錄下或 pluginPath 所指定的目錄下)。 命令行參數(shù)及配置的優(yōu)先級 配置文件中的所有選項(xiàng)都有對應(yīng)的命令行參數(shù),,在命令行參數(shù)中輸入的選項(xiàng)優(yōu)先級比配置文件高,。輸入 qqbot -h 或 python sample.py -h 可查看所有命令行參數(shù)格式。 程序一共有四個級別的配置,,其優(yōu)先級如下: ?
其中:根配置 是固定的,,用戶無法修改; 默認(rèn)配置 和 用戶配置 可由用戶在 v2.1.conf 文件中進(jìn)行修改;最后,,還可以在 命令行參數(shù) 中輸入配置。 八,、 smartqq 協(xié)議支持及限制本項(xiàng)目已實(shí)現(xiàn)絕大部分 smartqq 協(xié)議支持的功能,,如下:
其他功能
因 smartqq 協(xié)議的限制,以下問題無解決辦法
九,、參考資料QQBot 參考了以下開源項(xiàng)目:
在此感謝以上三位作者的無私分享,,特別是感謝 ScienJus 對 SmartQQ 協(xié)議所做出的深入細(xì)致的分析。 |
|