Python-wechaty能夠使用少量代碼即可完成一個機(jī)器人,使用起來非常簡單,基于OOP的設(shè)計(jì)思路能夠很好監(jiān)聽和處理微信內(nèi)部大量的事件,比如:自動回復(fù)消息,定時發(fā)送消息,拉人入群,好友申請同意等等。此外,目前的插件系統(tǒng)里面有很多拿來即用的工具,比如拉人入群等。當(dāng)然開發(fā)一個自己的插件也是非常簡單,無需很高深的概念,只需要你能夠理解事件和OOP即可。
python-wechaty項(xiàng)目源于wechaty,甚至說很大程度上代碼是直接從其翻譯過來的,然后加上一些python的特性,讓其更加pythonic。作為一個IM的入口工具,未來我們也將添加更多的Chatbot元素進(jìn)去,讓其能夠成為一個真正的聊天機(jī)器人。
在介紹python-wechaty之前,還是簡要介紹一下wechaty。
wechaty
或許有很多人會把wechaty和wechat聯(lián)系起來,畢竟在名稱上面只是一字之差。這個得從wechaty的起源開始說起,起初,此項(xiàng)目只是作為微信的一個工具庫,能夠進(jìn)行一些簡單的自動化操作過程,比如:定時發(fā)送消息,入群消息發(fā)送,好友申請接受等。
可隨著項(xiàng)目的逐步更新,wechaty已支持主流的IM軟件,比如:微信,釘釘,Telegram。
這個項(xiàng)目從2016年開始,到現(xiàn)在已經(jīng)獲取8k star,是一個非常穩(wěn)定且用戶量非常龐大的項(xiàng)目。官方對其給出的介紹是:
A Conversational AI RPA SDK for Chatbot
所以wechaty作為IM ChatBot的入口工具,是很多聊天機(jī)器人的基礎(chǔ)架構(gòu)組件,也將會逐步支持主流聊天機(jī)器人的功能。
python-wchaty的誕生
與Wechaty的結(jié)緣是在2019年底的一次技術(shù)沙龍會上,認(rèn)識到了原來6行代碼就能夠開發(fā)出一款足夠靈活的機(jī)器人,當(dāng)時給我一個很大的震撼。微信作為我們?nèi)粘A奶旃ぞ咧?,如果能夠?qū)ζ渥鲆恍┳詣踊倪^程,能夠很大程度上減少繁瑣過程的工作量,比如說:辦活動時的拉人入群,定時提醒用戶打卡,提醒女朋友姨媽快來了等等。而wechaty能夠很好的支持以上所有功能,只需要簡單的幾行代碼即可完成?;厝ブ缶土ⅠR著手相關(guān)資料的查閱,然后逐步進(jìn)入wechaty的社區(qū)。
一個很巧的機(jī)會群里面說可以開發(fā)一款go-wechaty的開發(fā),當(dāng)時我就在想,為什么不能夠有一款python-wechaty呢,然后就毛遂自薦,成為了python-wechaty的聯(lián)合作者之一。由于對開源軟件和DevOps不是很熟悉,起步階段遇到了很多的問題,不過經(jīng)過社區(qū)大佬的耐心指導(dǎo),目前已能夠完成對issue和feature的開發(fā)和管理。親身經(jīng)歷,建議大家有機(jī)會一定要參加開源項(xiàng)目,能夠讓你學(xué)習(xí)到很多知識點(diǎn)。
最簡單的Bot
使用python-wechaty能夠很簡單的開發(fā)一款Bot,特別是使用了一個插件系統(tǒng)之后,如下所示:
以上代碼中實(shí)現(xiàn)了兩個主要的功能:
當(dāng)Bot接受到一個#ding信號,就立馬回復(fù)一個dong消息,這就是一個基本的ding-dong-bot。
當(dāng)接受到查閱天氣的文本語句時,則返回對應(yīng)的天氣查詢結(jié)果,比如:今天天氣如何?
以上兩個插件是系統(tǒng)內(nèi)置的,后續(xù)也會增加更多的拿來即用的實(shí)用插件,當(dāng)然用戶也可創(chuàng)建自己的插件,方式很簡單。
如何開發(fā)插件系統(tǒng)
在了解如何開發(fā)插件系統(tǒng)之前,可先移駕Plug-in`,插件系統(tǒng)支持對插件的安裝,卸載,自定義配置等內(nèi)容 ,至于具體的實(shí)現(xiàn)形式我相信也是需要面對具體的應(yīng)用場景。而在Wechaty這個面相事件型且交互邏輯非常簡單的場景下,插件的設(shè)計(jì)與開發(fā)就非常簡單。
我們現(xiàn)在直接來看看,系統(tǒng)內(nèi)置的叮咚插件是如何實(shí)現(xiàn)的。
"""basic ding-dong bot for the wechaty plugin"""
from typing import Union
from wechaty import Message, Contact, Room, FileBox
from wechaty.plugin import WechatyPlugin
class DingDongPlugin(WechatyPlugin):
"""basic ding-dong plugin"""
@property
def name(self):
"""name of the plugin"""
return 'ding-dong'
async def on_message(self, msg: Message):
"""listen message event"""
from_contact = msg.talker()
text = msg.text()
room = msg.room()
if text == '#ding':
conversation: Union[
Room, Contact] = from_contact if room is None else room
await conversation.ready()
await conversation.say('dong')
代碼很簡單,不過也是需要氛圍一下幾個層面來介紹。
WechatyPlugin
on_[event_name]
init_plugin
WechatyPlugin
此類為一個抽象類,所有的插件必須要繼承此基類,并重寫其中的函數(shù)。
name 屬性函數(shù)為抽象函數(shù),必須重寫。主要是為了標(biāo)識插件的名稱,作為插件唯一性身份認(rèn)證。
init_plugin 初始化函數(shù)能夠支持插件的初始化過程,比如初始化定時器對象,數(shù)據(jù)庫延遲連接對象等。
on_[event_name]此類函數(shù)主要是為了監(jiān)聽系統(tǒng)中的不同事件,比如:on_message, on_login, on_friendship等事件的監(jiān)聽都只需要重寫一下函數(shù)即可完成。不同插件之間以及不同事件之間都是獨(dú)立的,能夠很好的專注于不同業(yè)務(wù)場景下的開發(fā)。
event_name
python-wechaty很大程度上是由事件驅(qū)動,畢竟很多操作都是基于消息接受觸發(fā),由此事件的監(jiān)聽是其基礎(chǔ)特性,可能第一感覺就是實(shí)用EventEmitter這種模式來監(jiān)聽事件,這樣每個事件我都可以注冊不同的函數(shù)來監(jiān)聽,每個函數(shù)中會有不同的邏輯處理。這也是傳統(tǒng)的事件監(jiān)聽方法,可這至少會給開發(fā)上帶來一些不方便:函數(shù)的參數(shù)需要查閱文檔才能夠獲知,標(biāo)準(zhǔn)的函數(shù)式編程。
我不是說函數(shù)式編程不好,只是在這種場景下對系統(tǒng)性能并不能提升多少,且python-wechaty 也并不能太注重性能。
由此將其擴(kuò)展了OOP的方式,用戶可繼承Wechaty或WechatyPlugin來監(jiān)聽不同的事件,且在常規(guī)的代碼編輯器里面重寫函數(shù)時就可以自動填充函數(shù)參數(shù),從而減少查閱事件函數(shù)參數(shù)的問題。
監(jiān)聽事件的類型有:error, friendship, heartbeat, login, logout, message, ready, room_invite, room_join, room_leave, room_topic, scan。
在上面已經(jīng)展示了WechatyPlugin如何開發(fā),需要注意的地方,那接下來我將給大家詳細(xì)介紹一下最基礎(chǔ)的每日一說的機(jī)器人如何開發(fā)。
每日一說機(jī)器人
每日一說,顧名思義每天每個固定時間段發(fā)送一個祝?;蛱嵝眩唧w內(nèi)容可自定義。這其中需要注意幾點(diǎn):
機(jī)器人內(nèi)部有一個調(diào)度器,用于調(diào)度時間事件的觸發(fā)。
機(jī)器人可給制定的人和群發(fā)送對應(yīng)的內(nèi)容。
以上的功能我封裝成一個插件,然后注入到python-wechaty中即可。
"""daily word plugin"""
from datetime import datetime
from apscheduler.schedulers.asyncio import AsyncIOScheduler
from wechaty import Wechaty
from wechaty.plugin import WechatyPlugin
class DailyPlugin(WechatyPlugin):
"""
say something everyday, like `Daily Words`
"""
@property
def name(self) -> str:
"""get the name of the plugin"""
return 'dayily'
async def tick(self):
"""time tick for the plugin scheduler"""
room_id = get_room_id()
room = self.bot.Room.load(room_id)
await room.ready()
await room.say(f'i love you -> {datetime.now()}')
async def init_plugin(self, wechaty: Wechaty):
"""init plugin"""
await super().init_plugin(wechaty)
scheduler = AsyncIOScheduler()
scheduler.add_job(self.tick, 'cron', hour=6, minute=16)
scheduler.start()
插件就開發(fā)完了,然后將其注入到Wechaty中即可跑起來。
async def main():
bot = Wechaty().use(DailyPlugin())
await bot.start()
asyncio.run(main())
是不是超級簡單,插件系統(tǒng)幫你隔離所有的業(yè)務(wù)場景,讓代碼非常易于開發(fā)和維護(hù)。
python-wechaty還可以做更多
現(xiàn)在python-wechaty只完成了基本的Chatbot入口工具,離真正的聊天機(jī)器人還距離很遠(yuǎn),所以未來還有很多工作量可以做。