目前實現方式:
- 微信Web端api封裝調用實現
- 基於Windows自動化技術,其實就是自動化Windows桌面版的微信,因為是客戶端,效率要比網頁端的快
- 網頁自動化技術,跟上一個技術有相似之處,這種方式就是對微信web端的自動化實現
- 微信Android端的自動化技術,這個需要一整套Android開發環境。
優缺點分析
這么多的方案,各有優缺點,目前來看基於web端api封裝的方案是最合適,因為定制化更強,直接接口的調用相當穩定,windows桌面端的自動化和網頁自動化看似也很好,但實現難度上和穩定性上已經輸給了前者,然而Android端的自動化是同樣的,但它有一個不可替代的優點,就是可以實現自動發送朋友圈,這點是前三者都實現不了的。
輪子的選擇
找到了方案,我們就要考慮有沒有輪子可以用,畢竟站在巨人的肩膀好乘涼,在github上找到如下幾種:
- ItChat - Python
- wxpy - Python wxpy 在 itchat 的基礎上提供更豐富的擴展
- wechat - PHP 官方: 它可能是開發微信App的世界上最好的SDK
- wechaty - TypeScript Wechaty是一個用於微信個人賬戶的Bot SDK,可以幫助您在6行javascript中創建機器人,跨平台支持包括Linux,Windows,Darwin(OSX / Mac)和Docker。
- WeChatAssist - JAVA
目前找到各個語言里面最合適的幾個,選擇你最喜歡的一個,我選了wechaty - TypeScript ,因為它是目前為止最為活躍的一個,而且問題又是最少的一個。
輪子的部署
wechaty 是一個服務端,通過NodeJs實現,那我們只需要一個ubuntu服務器,就可以完成部署
具體環境如下:
- node 環境
- pm2 對node服務管理
開發工具如下:
- webStorm 編碼工具
- express 用於接口的實現
輪子的升華
wechaty官方給的例子只適合在服務終端直接使用,我們要實現的是在手機客戶端通過接口調用獲取登錄二維碼,登錄后獲取所有群組。下面是通過express框架寫的兩個接口。
如何通過接口獲取二維碼
router.get('/getScan', function (req, res, next) { const userKey = req.query.key; if (userKey) { const wechaty = new Wechaty(name: userKey}); Data.pushWechaty(userKey, wechaty); //緩存Wechaty對象 wechaty.on('scan', (qrcode, status) => { const scanUrl = `https://api.qrserver.com/v1/create-qr-code/? data=${encodeURIComponent(qrcode)}`; console.log(`${userKey} Scan QR Code to login: ${status}\n ${scanUrl}`); try { res.send({ success: true, msg: "請掃描二維碼登錄", data: { url: url } }) } catch (e) { } wechaty.start(); } }else { res.send({ success: false, msg: "用戶信息不能為空" }) } }
如何獲取所有群組
router.get('/getRoomList', async function (req, res, next) { const userKey = req.query.key; if (userKey) { if (!Data.getWechatyStatus(userKey)) { res.send({ success: false, msg: "用戶未登錄" }); return; } const wechaty = Data.getWechaty(userKey); if (!wechaty) { res.send({ success: false, msg: "用戶信息緩存異常,請重新登錄" }); return; } const isOff = wechaty.logonoff(); console.log(JSON.stringify(isOff)); if (!isOff) { res.send({ success: false, msg: "用戶已退出,請重新登錄" }); return; } const roomList = await wechaty.Room.findAll(); const topicList = await Promise.all( roomList.map(async room => await room.topic()), ); log.info('Bot', topicList); res.send({ success: true, data: roomList, msg: "獲取所有組信息" }); } else { res.send({ success: false, msg: "用戶信息不能為空" }) } });
這樣就實現了我們剛開始的需求,群組有了,發個消息簡直不能再簡單了,只需要一句話:
const keyroom = await bot.Room.find({topic: '群名'}) keyroom.say("內容")