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

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)

分享創造快樂