歡迎光臨
每天分享高質量文章

Python&QQBot:一個簡單、好用的QQ機器人

介紹

qqbot 是一個用 python 實現的、基於騰訊 SmartQQ 協議的 QQ 機器人,可運行在 Linux 、 Windows 和 Mac OSX 平臺下。


你可以通過擴展 qqbot 來實現:

  • 監控、收集 QQ 訊息

  • 自動訊息推送

  • 聊天機器人

  • 通過 QQ 遠程控制你的設備

安裝方法

在 Python 2.7/3.4+ 下使用,用 pip 安裝:

pip install qqbot

使用方法

1. 啟動 QQBot

在命令列輸入: qqbot ,即可啟動一個 QQBot 。

啟動過程中會自動彈出二維碼圖片,需要用手機 QQ 客戶端掃碼並授權登錄。啟動成功後,會將本次登錄信息儲存到本地檔案中,下次啟動時,可以輸入: qqbot -q qq號碼 ,先嘗試從本地檔案中恢復登錄信息(不需要手動掃碼),只有恢復不成功或登錄信息已過期時才會需要手動掃碼登錄。一般來說,儲存的登錄信息將在 2 天之後過期。

註意: Linux 下,需要系統中有 gvfs-open 或者 shotwell 命令才能自動彈出二維碼圖片(一般安裝有 GNOME 虛擬檔案系統 gvfs 的系統中都會含這兩個命令之一)。 Windows10 下,需要系統中已設置了 png 圖片檔案的預設打開程式才能自動彈出二維碼圖片。

若系統無法自動彈出二維碼圖片,可以手動打開圖片檔案進行掃碼,也可以將二維碼顯示樣式設置為 郵箱樣式 、 服務器樣式 或 文本樣式 進行掃碼,

2. 操作 QQBot

QQBot 啟動後,在另一個控制台視窗使用 qq 命令操作 QQBot ,目前提供以下命令:

1) 幫助、停機和重啟命令

    qq help|stop|restart|fresh-restart


2) 聯繫人查詢、搜索命令

    qq list buddy|group|discuss [$cinfo|$clike]
    ( $cinfo --> $qq|$name|$key=$val )
    ( $clike --> :like:$qq|:like:$name|$key:like:$name )

    qq list group-member|discuss-member $oinfo|$olike [$cinfo|$clike]
    ( $oinfo --> $oqq|$oname|$okey=$oval )
    ( $cinfo --> $qq|$name|$key=$val )
    ( $olike --> :like:$oqq|:like:$oname|$okey:like:$oname )
    ( $clike --> :like:$qq|:like:$name|$key:like:$name )


3) 聯繫人更新命令

    qq update buddy|group|discuss

    qq update group-member|discuss-member $ginfo


4) 訊息發送命令

    qq send buddy|group|discuss $rinfo $message


5) 群管理命令: 設置/取消管理員 、 設置/刪除群名片 、 群成員禁言 以及 踢除群成員

    qq group-set-admin $ginfo $minfo1,$minfo2,...

    qq group-unset-admin $ginfo $minfo1,$minfo2,...

    qq group-set-card $ginfo $minfo1,$minfo2,... card

    qq group-unset-card $ginfo $minfo1,$minfo2,...

    qq group-shut $ginfo $minfo1,$minfo2,... [t]

    qq group-kick $ginfo $minfo1,$minfo2,...


6) 加載/卸載/顯示插件

    qq plug/unplug myplugin

    qq plugins

list 命令提供強大的聯繫人查詢和搜索功能,用法示例如下:

# 列出所有好友
qq list buddy

# 列出 QQ 為 123456 的群
qq list group 123456

# 列出備註名為 jack 的好友
qq list buddy mark=jack

# 列出 群“456班” 的所有成員
qq list group-member 456班

# 列出 群“456班” 中名片為 “mike” 的成員
qq list group-member 456班 card=mike

# 列出 討論組“XX小組” 中名為 jack 的好友
qq list discuss-member XX小組 jack

其中第三、四個引數如果是 key=val 的格式,則應為 name=xx|nick=xx|mark=xx|card=xx|qq=xx 的格式,如果不是 key=val 的格式,則按以下原則進行處理:若是一串數字,則按 QQ 號進行查詢,否則,按名稱進行查詢。

如果存在重名現象,會列出所有重名的聯繫人。如:

qq list group 機器人測試

將列出所有名為 “機器人測試” 的群。

如果在 list 命令的第三、四個引數中加入 “:like:” ,則會按部分匹配的樣式進行搜索,用法示例如下:

# 列出名稱中含有 “李” 的好友
qq list buddy :like:李

# 列出 QQ 中含有 “234” 的群
qq list group :like:234

# 列出備註名中含有 jack 的好友
qq list buddy mark:like:jack

# 列出 群“456班” 的中名稱中含有 “李” 的成員
qq list group-member 456班 :like:李

# 列出 群“456班” 中名片中含有 “mike” 的成員
qq list group-member 456班 card:like:mike

# 列出的 討論組“xx小組” 中名為 jack 的好友
qq list discuss-member :like:小組 jack

從 v2.2.5 版開始, list 命令採用表格的形式輸出聯繫人串列,其輸出樣式示例如下:

為保證表格在終端中的顯示效果,建議將終端的輸出字體設置為 consolas 、且每行可打印的最大字符數大於 120 。另外需要註意:為保證表格的顯示效果,當聯繫人的名稱、名片等屬性的長度太長或含有特殊字符時,將對這些屬性進行截斷或過濾後再輸出至終端。

update 命令更新指定的聯繫人串列,其引數含義和 list 命令相同,如:

# 更新好友串列
qq update buddy

# 更新群串列
qq update group

# 更新 群“456班” 的成員串列
qq update group-member 456班

send 命令中第三個引數和 list 命令中的第三個引數格式一致。要註意,如果有重名現象,會給所有重名的聯繫人發信息。 另外要註意,第二個引數只能是 buddy/group/discuss ,不能是 group-member/discuss-member 。示例:

# 給 好友“jack” 發訊息 “你好”
qq send buddy jack 你好

# 給 群“198班” 發訊息 “大家好”
qq send group 198班 大家好

# 給 QQ 為 12345 的好友發訊息
qq send buddy 12345 xxx

# 給討論組發訊息
qq send discuss MyDiscuss hello

可以在訊息內容中嵌入“/可愛”等表情關鍵詞來向對方發送表情,詳見 facemap.py。還可以在訊息內容中使用 \n,\t 這兩個轉義字符(如: send buddy jack 第一行\n第二行)。

群管理命令中的 $ginfo 和 $minfo 和 list 命令中的第三、四個引數格式一致。例如:

# 禁止 群“456班” 中的 jack,mike,jim 發言( 2 分鐘)
qq group-shut 456班 jack,mike,jm 120

以上所有命令都提供對應的 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.md 。註意:如果命令中含有中文或特殊字符,需要先進行 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 機器人非常簡單,只需要定義一個自己的訊息響應函式並按插件加載。示例代碼:

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

def onQQMessage(bot, contact, member, content):
    if content == '-hello':
        bot.SendTo(contact, '你好,我是QQ機器人')
    elif content == '-stop':
        bot.SendTo(contact, 'QQ機器人已關閉')
        bot.Stop()

註意,上面註冊的響應函式的函式名必須為 “onQQMessage” ,函式引數也必須和上面的一致。

將以上代碼另存為 sample.py (註意儲存為 utf8 編碼的檔案)。放到 ~/.qqbot-tmp/plugins/ 目錄下( ~ 代表用戶主目錄, win7 下為 C:\Users\xxx ),或系統中可以 import 到的目錄下(如 python 的安裝目錄下的 Lib/site-packages 目錄)。

之後,保持前面的 qqbot 行程運行,在另一個控制台輸入 qq plug sample ,則可將此檔案中的 onQQMessage 函式註冊到 QQBot 的相應事件上去。此時,用另外一個 QQ 向本 QQ 發送訊息 “-hello”,則會自動回覆 “你好,我是 QQ 機器人”,發送訊息 “-stop” 則會關閉 QQ 機器人。

在控制台輸入 qq unplug sample 可以卸載此插件及相應的回呼函式。可以同時加載多個插件,此時各插件中的相應函式會依次被呼叫(但呼叫順序和加載次序無關)。

QQBot 開始運行後,每收到一條 QQ 訊息,會將訊息來源、訊息內容以及一個 QQBot 物件傳遞給已註冊的訊息響應函式。其中:

bot     : QQBot 物件,提供 List/SendTo/Stop/Restart 等接口,詳見本文件第五節
contact : QContact 物件,訊息的發送者,具有 ctype/qq/uin/nick/mark/card/name 等屬性
member  : QContact 物件,僅當本訊息為 群訊息或討論組訊息 時有效,代表實際發訊息的成員
content : str 物件,訊息內容

contact 代表訊息發送者,其 ctype 屬性可以為 ‘buddy’/’group’/’discuss’ ,代表 好友/群/討論組 物件,表示本訊息是 好友訊息/群訊息/討論組訊息 。

member 僅當本訊息為 群訊息或討論組訊息 時有效,代表實際發訊息的成員,它的 ctype 屬性可以為 ‘group-member’/’discuss-member’ ,代表 群成員/討論組成員 物件。當本訊息為 好友訊息 時, member 等於 None 。

contact 和 member 都是 QContact 物件,不同型別的 QContact 物件所具有的屬性含義見: qcontact-attr 。註意所有 QContact 物件都是 只讀物件 ,只能讀取它的屬性,不能設置它的屬性,也不能向它添加額外的屬性。

可以呼叫 QQBot 物件的 SendTo 接口向 QContact 物件發送訊息,但要註意:只可以向 好友/群/討論組 發訊息, 不可以向 群成員/討論組成員 發送訊息 。也就是說,只可以呼叫 bot.SendTo(contact, ‘xxx’) , 不可以呼叫 bot.SendTo(member, ‘xxx’) 。

五、 QQBot 物件的公開接口和屬性

QQBot 物件提供 List/Update/SendTo/GroupSetAdmin/GroupSetCard/GroupShut/GroupKick/Plug/Unplug/Login/Stop/Restart/FreshRestart 共計 11 個公開接口,這些接口的第一個字母都是大寫的。另外,提供一個公開屬性 conf 儲存全域性的配置信息。

一般情況下,請勿 呼叫/存取 此物件的其他 方法/屬性 。特別的, 請勿在子執行緒中呼叫這些接口 。 以下介紹前 7 個接口和 conf 屬性。

如果需要在 IDE 或 python-shell 中運行或測試以上接口,需要先關閉 qqbot 行程,併在 IDE 或 python-shell 中運行以下代碼進行登錄:

>>> from qqbot import _bot as bot
>>> bot.Login(['-q', '1234'])

(1) bot.List(tinfo, [cinfo]) –> [contact0, contact1, …, ]/[]/None

對應本文件第三節的 list 命令。傳回聯繫人物件( QContact 物件)串列或者 None 。第一個引數 tinfo 是聯繫人串列的代號,第二個引數是可選的(和 list 命令的第三個引數格式一致)。

引數 tinfo 用來代表某個聯繫人串列,該引數在聯繫人的查詢中非常重要,請務必理解以下兩種情況 :

tinfo 的含義(情況1): tinfo 可以為 ‘buddy’/’group’/’discuss’ ,分別代表 好友串列/群串列/討論組串列 。示例:

# 傳回 好友串列:
>>> bot.List('buddy')

# 傳回名為 'jack' 的好友的串列:
>>> bot.List('buddy', 'jack')

# 傳回 群串列:
>>> bot.List('group')

# 傳回名為 “機器人測試” 的群的串列:
>>> bot.List('group', '機器人測試')

tinfo 的含義(情況2): tinfo 也可以是一個 ctype 等於 ‘group’/’discuss’ 的 QContact 物件,代表該 群/討論組 的成員串列。如以下第二句和第三句分別傳回 群“456班” 的成員串列和該群中名片為 “jack” 的成員串列:

>>> g = bot.List('group', "456班")[0]   # g 是一個 Group 物件(群“456班”)
>>> bot.List(g)                         # 傳回 群“456班” 的成員串列
>>> bot.List(g, 'card=jack')            # 傳回 群“456班” 中名片為 “jack” 的成員串列

註意上面第三句不允許是 bot.List(g, card=’jack’) 的格式。

List 接口的內部執行順序: 首先在 QQBot 的聯繫人資料庫內查找 tinfo 所代表的聯繫人串列;若資料庫內已有此串列,則在此串列內進行搜索,並傳回一個包含 “此串列中所有和 cinfo 匹配的聯繫人” 的串列;若資料庫內沒有此串列,則向 QQ 服務器請求資料獲取聯繫人串列,獲取成功後將聯繫人串列儲存到資料庫內,然後再進行搜索並傳回一個包含 “此串列中所有和 cinfo 匹配的聯繫人” 的串列;如果在向 QQ 服務器請求資料的過程中出錯了,則打印相關的失敗信息,並傳回 None 。

List 接口傳回值的含義: 傳回一個非空串列表示 tinfo 所指定的聯繫人串列內所有和 cinfo 匹配的聯繫人;傳回一個空串列表示該聯繫人串列內沒有和 cinfo 匹配的聯繫人;傳回 None 表示向 QQ 服務器請求聯繫人串列和資料失敗,不知道是否有相匹配的聯繫人。

呼叫 List 接口後, 務必 先根據以上三種情況對傳回值進行判斷,然後再執行後續代碼。

(2) bot.Update(tinfo) –> True/False

Update 接口的引數 tinfo 和 List 接口中的引數含義相同,呼叫此接口會立即向 QQ 服務器請求相應的聯繫人串列並更新聯繫人資料庫,並一直阻塞至更新成功。更新最慢的是好友串列,若好友較多可能會阻塞 5 ~ 10 秒。成員串列更新的較快,即便是 2000 人的大群,更新時間僅 1 ~ 2 秒。

若更新成功,傳回 True ,否則,傳回 False 。

示例:

# 更新 好友串列 :
>>> bot.Update('buddy')

# 更新 群串列 :
>>> bot.Update('group')

# 更新 某個群的成員串列 :
>>> gl = bot.List('group', "456班")
>>> if gl:
>>>     g = gl[0]
>>>     bot.Update(g)

(3) bot.SendTo(contact, content, resendOn1202=True) –> ‘向 xx 發訊息成功’/’錯誤:…’

向聯繫人發送訊息。第一個引數為 QContact 物件,第二個引數為訊息內容。再次提醒: 只可以向 好友/群/討論組 發訊息, 不允許向 群成員/討論組成員 發訊息 。

可以在訊息內容中嵌入“/微笑”等表情關鍵詞來向對方發送表情,詳見 facemap.py 。

若發送成功,傳回字串(’向 xx 發訊息成功’)。否則,傳回含錯誤原因的字串(’錯誤:…’)。

發訊息時可能會重覆發訊息,這是因為 QQ 服務器傳回代碼 1202 的原因。v2.1.17版已針對此問題在 bot.SendTo 接口中增加了一個引數: resendOn1202 ,若此引數為 True (預設值),則發訊息時如果 QQ 服務器傳回代碼 1202 (表明發訊息可能失敗),還會繼續發送 3 次,直至傳回代碼 0 , 若此引數為 False ,則不會嘗試重發。

設為 True 在絕大部分情況下能保證訊息一定能發出去,但缺點是有時一條訊息會重覆發送。設為 False 則相反,訊息不會重覆發送,但有時訊息發送不出去。

總之因為這個 1202 代碼的不確定性,沒有完美的解決辦法。請根據各自的實際情況選擇 resendOn1202 的值。

第一個引數 contact 必須是通過 bot.List 傳回的 QContact 物件、或回呼函式 onQQMessage 傳遞進來的第一個引數。示例:

# 向 QQ 為 12345 的好友發訊息
>>> bl = bot.List('buddy', '12345')
>>> if bl:
>>>     b = bl[0]
>>>     bot.SendTo(b, 'hello')

(4) bot.GroupXXX(group, membs[, arg]) –> [‘成功:…’, ‘成功:…’, ‘錯誤:…’]

對應第三節的群管理命令,共四個接口:

  • 設置/取消管理員: bot.GroupSetAdmin(group, membs, admin=True)

  • 設置/取消群成員名片: bot.GroupSetCard(group, membs, card)

  • 禁止群成員發言: bot.GroupShut(group, membs, t=60)

  • 踢除群成員: bot.GroupKick(group, membs)

其中第一個引數 group 為 群物件( ctype 等於 ‘group’ 的 QContact 物件),第二個引數 membs 為被操作的成員串列。傳回值為 membs 中各成員的操作信息。示例代碼:

# 禁止 群“456班” 中名稱為 jack 的成員發言(120秒)
gl = bot.List('group', '456班')
if gl:
    group = gl[0]
    membs = bot.List(group, 'jack')
    if membs:
        bot.GroupShut(group, membs, 120)

註意: 1) 第二個引數 membs 是一個 list 物件(如: [memb0,memb1,…] ),而不是一個 QContact 物件; 2) 若 membs 中的某個成員是管理員,則除 SetCard 外的其他接口可能對其無效,儘管此時傳回成功信息。 3) 使用這四個接口時,請自行保證登錄的用戶是該群的管理員,且 membs 中的各成員均屬於該群。

(5) bot.conf

bot.conf 中儲存全域性的配置信息,各項配置詳見本文件第七節。如 bot.conf.termServerPort 儲存 QQBot 命令列服務器的端口號, bot.conf.qq 儲存本次登錄的 QQ 號碼。

註意: bot.conf 中儲存的配置信息是只讀的,請勿修改這些配置信息。

 註冊回呼函式、被他人 @ 的通知、判斷是否是自己發的訊息、定製定時任務

註冊回呼函式

除了上面提到的 onQQMessage 響應函式,還可以註冊 onInit/onQrcode/onStartupComplete/onInterval/onUpdate/onPlug/onUnplug/onExit 共計九種事件的回呼函式,所有事件的回呼函式引數格式、含義及示例詳見 sampleslots.py 。

程式的運行流程以及各回呼函式的呼叫時機如下

再次提醒:註冊的回呼函式的函式名以及函式引數(數量和名稱)都不得更改 。

被群內其他成員 @ 的通知

QQBot 收到群訊息時,會先根據訊息內容判斷是否有人 @ 自己。如果是,則在訊息內容的開頭加一個 ‘[@ME] ‘ 的標記,再傳遞給 onQQMessage 函式;否則,將訊息內容中的所有 ‘@ME’ 替換成 ‘@Me’ 再傳給 onQQMessage 。因此,在 onQQMessage 函式內,只需要判斷 content 內是否含有 ‘@ME’ 就知道自己是否被訊息發送者 @ 了。例如:

def onQQMessage(bot, contact, member, content):
    if '@ME' in content:
        bot.SendTo(contact, member.name+',艾特我幹嘛呢?')

請註意,若群內有另一個成員的名字和自己的名字的開頭部分相同(如:自己的名字是 ab ,另一個成員的名字是 abc ),那麼當有人 @abc 時,也會誤報成 @ME ,在這種情況下,需要修改自己的群名片,以免誤報。

判斷是否是自己發的訊息

當本 QQ 在群內或討論組內發言時, QQBot 也會收到一條同樣的訊息,此時 onQQMessage 中的 contact 引數就是該 群/討論組 物件, member 引數就是自己在該 群/討論組 中的成員物件,此時 member.uin 就是本次登錄的 QQ 號碼,因此,在 onQQMessage 中,只要判斷 member 的 uin屬性 是否是本次登錄的 QQ 號碼就可以知道是否是自己的發的訊息了,例如:

from qqbot.utf8logger import INFO

def onQQMessage(bot, contact, member, content):
    if getattr(member, 'uin', None) == bot.conf.qq: # 註意:不要使用 member.uin
        INFO('你在 %s 內發言', contact)

定製定時任務

從 2.1.13 起, qqbot 提供一個功能強大的函式裝飾器 — qqbotsched 來定製定時任務,示例代碼:

from qqbot import qqbotsched

@qqbotsched(hour='11,17', minute='55')
def mytask(bot):
    gl = bot.List('group', '456班')
    if gl is not None:
        for group in gl:
            bot.SendTo(group, '同志們:開飯啦啦啦啦啦啦!!!')

以上代碼以插件形式加載後,每到 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:00, xx:05, xx:10, …, xx:55 執行任務, day_of_week=’mon-fri’ (或 ‘0-4’ ) 表示應在 星期一 ~ 星期五 執行任務。

qqbotsched 是對 Python 的定時任務框架 apscheduler 的簡單封裝,其各項引數應採用 Unix 系統中的 crontab 格式輸入。有關 crontab 以及 Python 的定時任務框架 apscheduler 的內容

註冊回呼函式和定製定時任務的註意事項

註冊回呼函式和定製定時任務是對 QQBot 進行擴展的唯一方式,在編寫這些函式時,請註意以下事項:

  • 回呼函式的函式名、引數名、引數數量、引數順序都不得更改

  • 定時任務的函式名可以自己定義,但引數有且只有一個,引數名必須為 bot ,為一個 QQBot 物件。

  • 所有回呼函式和定時任務都將在主執行緒中被依次呼叫,因此不必擔心全域性變數的執行緒安全問題。

  • 回呼函式和定時任務的運行時間應儘量短,儘量不要再這些函式中進行阻塞式的操作,否則會阻塞整個程式的運行。一般來說,每個函式的運行時間在 5 秒以內是可以接受的。

  • 絕對不要 在回呼函式、定時任務或 qqbot 主執行緒的內部呼叫 os.system 執行 本 QQ 號對應的 qq 命令 ( 如 os.system(‘qq send buddy jack hello’) )或請求 本 QQ 號對應的 HTTP-API 接口 ,否則整個程式會形成死鎖(因為 os.system 要等 qq 命令執行完成後才傳回、而 qq 命令要等 os.system 傳回後才會被執行)。請直接使用 bot 的 SendTo/List/GroupXXX 等接口。

二維碼管理器、QQBot 配置、命令列引數以及工作目錄

二維碼的顯示樣式

WebQQ 登錄時需要用手機 QQ 掃描二維碼圖片,在 QQBot 中,二維碼圖片可以通過以下四種樣式顯示:

  • GUI樣式: 在 GUI 界面中自動彈出二維碼圖片

  • 郵箱樣式: 將二維碼圖片發送到指定的郵箱

  • 服務器樣式: 在一個 HTTP 服務器中顯示二維碼圖片

  • 文本樣式: 在 Term 中以文本形式展示二維碼(需要自行安裝 pillow 和 wcwidth 庫)

GUI 樣式是預設的樣式,只適用於個人電腦。郵箱樣式可以適用於個人電腦和遠程服務器。服務器樣式一般只在有公網 ip 的系統中使用。如果使用 QQ 郵箱來接收二維碼,則發送二維碼圖片之後,手機 QQ 客戶端會立即收到通知,在手機 QQ 客戶端上打開郵件,再長按二維碼就可以掃描了。文本樣式方便在開發過程或者服務器部署時使用,為開發者提供快捷方式登陸 QQ 。

註意:當開啟了 郵箱樣式/服務器樣式/文本樣式 時, GUI 樣式是關閉的,登陸時不會自動彈出二維碼圖片。

每次登錄時會創建一個二維碼管理器 ( QrcodeManager 物件) ,二維碼管理器會根據配置檔案及命令列引數來選擇二維碼圖片的顯示方式。

配置檔案的使用方法

配置檔案為 ~/.qqbot-tmp/v2.x.conf ,第一次運行 QQBot 後就會自動創建這個配置檔案,其中內容如下:

{

    # QQBot 的配置檔案
    # 使用 qqbot -u somebody 啟動程式時,依次加載:
    #     根配置 -> 預設配置 -> 用戶 somebody 的配置 -> 命令列引數配置
    # 使用 qqbot 啟動程式時,依次加載:
    #     根配置 -> 預設配置 -> 命令列引數配置

    # 用戶 somebody 的配置
    "somebody" : {

        # QQBot-term (HTTP-API) 服務器端口號(該服務器監聽 IP 為 127.0.0.1 )
        # 設置為 0 則不會開啟本服務器(此時 qq 命令和 HTTP-API 接口都無法使用)。
        "termServerPort" : 8188,

        # 二維碼 http 服務器 ip,請設置為公網 ip 或空字串
        "httpServerIP" : "",

        # 二維碼 http 服務器端口號
        "httpServerPort" : 8189,

        # 自動登錄的 QQ 號
        "qq" : "3497303033",

        # 接收二維碼圖片的郵箱賬號
        "mailAccount" : "3497303033@qq.com",

        # 該郵箱的 IMAP/SMTP 服務授權碼
        "mailAuthCode" : "feregfgftrasdsew",

        # 是否以文本樣式顯示二維碼
        "cmdQrcode" : False,

        # 顯示/關閉除錯信息
        "debug" : False,

        # QQBot 掉線後自動重啟
        "restartOnOffline" : False,

        # 在後臺運行 qqbot ( daemon 樣式)
        "daemon": False,

        # 完成全部聯繫人串列獲取之後才啟動 QQBot 
        "startAfterFetch" : False,

        # 插件目錄
        "pluginPath" : ".",

        # 啟動時需加載的插件
        "plugins" : [],

        # 插件的配置(由用戶自定義)
        "pluginsConf" : {},

    },

    # 可以在 預設配置 中配置所有用戶都通用的設置
    "預設配置" : {
        "qq" : "",
        "pluginPath" : "",
        "plugins" : [
            'qqbot.plugins.sampleslots',
            'qqbot.plugins.schedrestart',
        ],
        "pluginsConf" : {
            'qqbot.plugins.schedrestart': '8:00',
        }
    },

    # # 註意:根配置是固定的,用戶無法修改(在本檔案中修改根配置不會生效)
    # "根配置" : {
    #     "termServerPort" : 8188,
    #     "httpServerIP" : "",
    #     "httpServerPort" : 8189,
    #     "qq" : "",
    #     "mailAccount" : "",
    #     "mailAuthCode" : "",
    #     "cmdQrcode" : False,
    #     "debug" : False,
    #     "restartOnOffline" : False,
    #     "daemon" : False,
    #     "startAfterFetch" : False,
    #     "pluginPath" : "",
    #     "plugins" : [],
    #     "pluginsConf" : {}
    # },

}

可以在配置檔案中添加自己的用戶配置(即在該檔案的字典中新增一個 item ,此 item 的 key 就代表一個用戶),例如,該檔案中已有的 somebody 專案就代表名為 somebody 的用戶,運行 QQBot 時,輸入 qqbot -u somebody ,則會加載 somebody 專案下的各項配置。

下麵介紹配置檔案中各項配置的功能,以下內容均假定已修改了 somebody 下的配置,且以 qqbot -u somebody 的方式運行。

郵箱樣式的配置( mailAccount 和 mailAuthCode )

如果需要使用郵箱樣式顯示二維碼,可以將 mailAccount 和 mailAuthCode 項中分別設置為郵箱帳號和授權碼,運行後,二維碼管理器會將二維碼圖片發送至該郵箱。

註意:授權碼不是郵箱的登錄密碼,而是郵箱服務商提供的開通 IMAP/SMTP 服務的授權碼(提醒:不是 POP3/SMTP 服務), QQ/網易 郵箱可以在網頁版的郵箱設置裡面開通此項服務,並得到授權碼。如果只定義了 mailAccount 而沒定義 mailAuthCode ,則程式運行的開始時會要求手工輸入此授權碼。

郵箱樣式已在 QQ 、 網易 和 Google 郵箱中測試過。

服務器樣式的配置( httpServerIP 和 httpServerPort )

如果需要使用服務器樣式,可以配置 httpServerIP 和 httpServerPort 項,一般來說應該設置為公網 ip 。服務器樣式開啟後,可以通過 http://{httpServerIP}:{httpServerPort}/{any} 來訪問二維碼圖片。其中 {any} 可以是任何非空的數字或字母串。

當郵箱樣式和服務器樣式同時開啟時,發郵件時不會發送真正的圖片,只會將圖片地址發到郵箱中去,而且只發送一次,二維碼過期時掃清一下郵件就可以了。如果只開啟郵箱樣式,則發郵件時會發送真正的圖片,當二維碼過期時,需要將郵件設置為已讀(用手機 QQ 點開郵件後該郵件就是已讀了),之後才會發送最新的二維碼圖片。

文本樣式顯示二維碼(cmdQrcode)

若 cmdQrcode 項設置為 True ,則會在 term 中以文本樣式顯示二維碼。註意:要使用文本樣式,需要自行安裝 pillow 和 wcwidth 庫,可使用 pip 安裝。

自動登錄的 QQ 號碼( qq )

配置檔案中每個用戶都有 qq 這一項,若此項已設置為某 QQ 號碼,則 QQBot 在啟動時會先使用此 QQ 號上次登錄儲存的登錄信息來自動登錄。

掉線後自動重啟( restartOnOffline )

如果配置檔案中將 restartOnOffline 項設置為 True ,則當 QQBot 掉線或出錯終止時,會自動重新啟動 QQBot 。

在後臺運行 qqbot ( daemon )

此選項僅在 UNIX 類系統中有效,將配置中的 daemon 選項設置為 True 則會以 daemon 樣式運行程式。此時,標準輸出和標準錯誤會重定向到 daemon-$qq.log 檔案(其中 $qq 是配置中 qq 選項的值)。

聯繫人串列獲取完成後再啟動( startAfterFetch )

一般情況下,掃碼登錄完成就立即啟動 QQBot,只有在需要的時候才會去獲取聯繫人串列並更新聯繫人資料庫。如果將配置檔案中的 startAfterFetch 設置為 True ,則 QQBot 會等待所有聯繫人串列獲取完成後才啟動 ,註意,如果聯繫人較多,會耗費較長的時間。

QQBot-term 服務器端口號( termServerPort )

QQBot 啟動後,會開啟一個 QQBot-term 服務器監聽用戶通過 qq 命令列工具發過來的操作命令以及通過 HTTP API 接口發過來的操作命令,此服務器的監聽 IP 永遠為 127.0.0.1 ,監聽端口號預設為 8188 ,可以通過修改 termServerPort 的值來修改此端口號。

如果配置的 QQBot-term 服務器端口號不是預設的 8188 ,那麼在運行 qq 命令時,需要在第一個引數中指定端口號,如:

$ qq 8100 send buddy jack hello
$ qq 8100 list group-member chatbot

同樣,HTTP API 接口的端口號也需要改變,如: http://127.0.0.1:8100/send/buddy/jack/hello 。

如果不需要使用 qq 命令和 HTTP-API 接口,可以將此端口號設置為 0 ,此時 QQBot-term 服務器不會開啟。

如果需要在同一臺機器上登錄多個 QQ 號碼,可以直接在不同的終端中開啟多個 qqbot 行程進行登錄,但是,每個 qqbot 行程必須設置專有的 termServerPort 和 httpServerPort (或者全部設置為 0 或 空值 ),否則會造成端口號衝突。

除錯樣式( debug )

若 debug 項設置為 True ,則運行過程中會打印除錯信息。

插件的配置( pluginPath 和 plugins )

一般情況下,插件需要存放在系統的 import 目錄下或 ~/.qqbot-tmp/plugins 目錄下,可以在 pluginPath 選項中配置其他的存放目錄。另外,在 plugins 選項中可以指定 QQBot 啟動時需要加載的插件。

命令列引數及配置的優先級

配置檔案中的所有選項都有對應的命令列引數,在命令列引數中輸入的選項優先級比配置檔案高。輸入 qqbot -h 可查看所有命令列引數格式。

程式一共有四個級別的配置,其優先級如下:

使用 qqbot -u somebody 啟動程式時,依次加載:
    根配置 -> 預設配置 -> 用戶 somebody 的配置 -> 命令列引數配置

使用 qqbot 啟動程式時,依次加載:
    根配置 -> 預設配置 -> 命令列引數配置

其中:根配置 是固定的,用戶無法修改; 預設配置 和 用戶配置 可由用戶在 v2.x.conf 檔案中進行修改;最後,還可以在 命令列引數 中輸入配置。

工作目錄

qqbot 運行時,會在 工作目錄 下 搜索/創建 以下 檔案/目錄 :

  • 配置檔案: v2.x.conf

  • 插件目錄: plugins/

  • 登錄檔案: v2.x-pyx-xxxx.pickle

  • 聯繫人資料庫檔案:xxxx-contact.db

  • 臨時二維碼圖片: xxxx.png

  • 儲存QQ的檔案: qq(pid9816)

  • 以 daemon 樣式運行時的 log 檔案: daemon-xxx.log

預設的工作目錄為 ~/.qqbot-tmp/ ,可以在啟動 qqbot 時通過命令列引數 -b|–bench 指定其他工作目錄,例如: qqbot -b bench 。

 插件

插件的存放位置

插件實際上是一個 python 模塊,因此可以是一個 python 檔案,也可以是一個 python package。 qqbot 會根據插件名在以下目錄中搜索插件:

  • 配置中的 pluginPath 選項(命令列引數 -pp|–pluginPath )指定的目錄

  • 工作目錄下的 plugins 目錄

  • python 的匯入目錄

插件的加載/卸載

hot-plug 方式

可以在 qqbot 的運行過程中動態的加載/卸載插件,有以下三種方法:

  • 利用 qq 命令列工具: qq plug pluginname 或 qq unplug pluginname

  • 利用 http-api 接口: http://127.0.0.1:8188/plug/pluginname 或 http://127.0.0.1:8188/unplug/pluginname

  • 利用 bot 物件的接口: bot.Plug(‘pluginname’) 或 bot.Unplug(‘pluginname’)

前面兩種方法是供 qqbot 行程的外部行程呼叫的,第三種方法是在 qqbot 行程內部使用的。請勿在 qqbot 行程的內部使用前面兩種方法。

註意:採用 hot-plug 方式加載的插件在 qqbot 重啟後會丟失。

auto-plug-at-start 方式

也可以在 qqbot 的啟動時自動加載插件,在配置中的 plugins 選項(命令列引數 -pl|–plugins )中指定需要加載的插件名就可以了。這些插件將在啟動時、登錄之前被加載。

另外,如果系統中(或插件目錄中)存在名為 qqbotdefault 的 package ,那麼該 package 下麵的所有子模塊都會被當成插件在啟動時自動加載(註意:qqbotdefault 本身不會作為插件加載)。

插件內的 onPlug 和 onUnplug 回呼函式

  • 插件被加載時,會執行 reload(pluginName) ,因此插件內的所有代碼都會被執行一次

  • 當採用 hot-plug 的方式加載時,插件內的 onPlug 函式會緊接在 reload 成功後被執行

  • 當採用 auto-plug-at-start 方式加載時,插件在啟動時、登錄之前被加載,但插件內的 onPlug 函式會延遲到登錄成功後才被執行

  • 插件被卸載時,插件內的 onUnplug 被執行

插件的編寫編寫插件主要就是編寫回呼函式或定時任務函式

插件串列

命令列樣式下使用 IRC 聊天

linux 系統下,由於無法使用 QQ 客戶端,可以使用插件 qqbot.plugins.miniirc 來實現用 IRC 聊天的功能。加載方式: qq plug qqbot.plugins.miniirc ,或啟動時加載: qqbot -pl qqbot.plugins.miniirc ,或者在配置檔案中的 plugins 選項中加入 ‘qqbot.plugins.miniirc’ 。

插件加載後將在 6667 端口開啟一個微型的 IRC 服務器,用戶可以使用 IRC 客戶端(如 weechat, irssi 等)連接此服務器來實現命令列樣式下的聊天。以下以 weechat 為例介紹使用方法:

啟動 weechat : weechat

連接本服務器: /connect localhost

進入 群聊天 會話: /join group-name

進入 討論組聊天 會話: /join !discuss-name

進入 好友聊天 會話: /query buddy-name

進入 聊天會話 後,直接敲入文本並回車就可以向對方發送訊息了。所有接收到的 QQ 訊息也會被轉發給相應的 聊天會話 。

在聊天會話之間切換: ctrl+P 或 ctrl+N

顯示所有 群和討論組 的名稱: /list

以上幾乎就是此微型 IRC 服務器所提供的所有功能了,但已經足夠用來和 QQ 好友/群/討論組 聊天了。

smartqq 協議支持及限制

本專案已實現絕大部分 smartqq 協議支持的功能,如下:

  • 訊息收/發

  • 聯繫人(包括 好友/群/討論組/群成員/討論組成員)資料獲取和查詢(包括 QQ號/昵稱/名稱/備註名/群成員名片)

  • 聯繫人資料根據需要動態更新

  • 被群內其他成員 @ 的通知

  • 群管理功能: 設置/取消管理員 、 設置/刪除群名片 、 群成員禁言 以及 踢除群成員

  • 發送、接收表情

其他功能:

  • 呼叫系統預設圖片瀏覽器顯示登錄二維碼、將登錄二維碼發送至郵箱、開啟一個 http 服務器用來顯示登錄二維碼、在命令列視窗使用文本樣式顯示二維碼

  • 用 qq 命令列工具發訊息、查詢|更新聯繫人、群管理

  • 提供 HTTP-API 接口發訊息、查詢|更新聯繫人、群管理

  • 提供 miniirc 插件,可以在命令列樣式下使用 IRC 客戶端聊天

  • 掉線後自動重啟功能(有時需要手工掃碼)

  • 定時執行任務(通過 qqbotsched 實現)

因 smartqq 協議的限制,以下問題沒有好的解決辦法:

  • 無法長時間保持在線狀態,每次登錄成功後的 cookie 會每在 1 ~ 2 天后失效,將被騰訊服務器強制下線,此時 必須 手工掃碼重新登錄。可以打開郵箱樣式和自動重啟樣式,並配合 qqbot.plugins.schedrestart 插件使用,每天在固定的時間掃碼登錄一次,基本上可以穩定的保持在線狀態。

  • 無法發送圖片、檔案、音頻、 xml 卡片訊息

  • 無法獲取到自己通過其他客戶端(手機 QQ 、PC-QQ)發送的 好友 訊息(提示:自己發送的 群/討論組 訊息可以獲取到)

  • 當 好友/群/群成員 存在同名現象或名稱中含特殊字符時,無法系結其實際 QQ

  • 無法在群內 @ 其他成員,即便用本程式在群里發送了 “@jack xxx” 這樣的訊息, jack 也只能收到這個純文本,收不到“有人@我”的提醒。

  • 無法向 群/討論組 內的其他非好友成員發訊息,也無法收到非好友成員發過來的臨時會話訊息

  • 在非常少的情況下,發訊息時會重覆發送多次,也可能對方已收到訊息但傳回發送失敗的結果

赞(0)

分享創造快樂