参考
- QQ群 - 萌萌老妹机器人后援群 - 基于IOTQQ的多功能工具型机器人
- QQ群 - Javascript高级爬虫 - Javascript开发者讨论群,欢迎加入!
- awesome-java-crawler - 作者收集的爬虫相关工具和资料
- IOTQQ项目主页
- IOTQQ-Docker - 作者为iotbot制作的Dockerfile,可实现免授权单服务器多账户
- 反垃圾QQ群机器人 - 基于IOTQQ和百度文本审核API编写的完整项目,对于头疼于垃圾太多的QQ群管理员有很强实用性
- 一个帮你自动创建阿里云抢占式实例并开启网络加速的脚本 - 自动创建阿里云抢占式节点
前言
现在WebQQ已经凉了,网上那些基于WebQQ协议的框架也随之而去。
现在想基于QQ做些自动化的可以考虑IOTQQ,这是一款基于MacQQ逆向的QQ机器人框架。
服务器部署
其实IOTQQ项目主页的步骤介绍已经很清晰,这里只说一些注意点吧:
- 可以使用docker实现单台服务器启动多个IOTQQ实例,参见文章开头的参考。
- 现在腾讯对这类基于逆向破解协议的野生机器人封杀的还是很厉害的,安全起见,建议注册新QQ号进行测试。
- 3.0.1以上的新版IOTQQ不再需要通过公网和Github交互,运行在本地也不再需要内网穿透,部署方式大大简化了。
- 部署在服务器建议尽量用固定的一台服务器IP,否则说不定腾讯会因为异地登录封杀你的QQ号。
- iotbot3.0.x的Gitter Token是跟QQ号绑定的,不能随意更换登录QQ,解绑请联系IOTQQ作者。
- 经过本人一段时间的验证,IOTQQ运行于CentOS坑有点多,建议使用Ubuntu。
- 64位系统应该下载iotbot_3.x.x_linux_arm64.tar.gz这个包。
-
用下面的命令后台启动IOTQQ:
nohup /path/to/iotbot >> /path/to/iotbot/log.txt 2>&1 &
- 首次启动iotbot会拉取部分脚本并有详细输出,当出现
Everything is ok!
说明服务就绪,即可开始登录流程 - 初始化成功以后请求
http://IP:PORT/v1/Login/GetQRcode
获取登录二维码,手机QQ扫码登陆即可。
WEB_API的调用
- IOTQQ提供Web API供外部调用,只要知道接口地址,可以用任何http工具或者编程语言调用
- IOTQQ项目中有个WebAPI.json,可以直接导入Chrome插件RestletClient,既可以直接调用测试,也可以作为文档参考,很方便
- 这个插件在Chrome商店里也能搜索到,新版本叫Talend API Tester
- 把WebAPI.json导入之前,可以找个文本编辑器修改一下,主要是把接口地址和QQ号批量替换一下,这样导入后可以直接用
-
下面是使用request调用Web API的例子:
const rp = require('request-promise').defaults({ json: true, gzip: true }) async function callApi (name, params) { const url = `${WEB_API}/LuaApiCaller?qq=${LOGIN_QQ}&funcname=${name}&timeout=10` if (params) return rp.post(url, { body: params }) return rp.get(url) }
WebSocket接口的使用
- WebAPI是用来发消息、发指令的,对应的收消息、收事件则需要使用IOTQQ的websocket接口
- IOTQQ的websocket是基于socket.io实现的,不能直接用
ws://...
方式访问,因此网上的一些websocket测试工具都无法使用,只能用兼容socket.io的客户端访问 - nodejs开发需要引入
socket.io-client
库 -
简单代码如下:
const io = require('socket.io-client') const socket = io(WS_API, { transports: ['websocket'] }) socket.on('connect', e => { console.log('WS已连接') socket.emit('GetWebConn', '' + LOGIN_QQ, (data) => console.log(data)) }) socket.on('disconnect', e => console.log('WS已断开', e)) socket.on('OnGroupMsgs', async data => { console.log('>>OnGroupMsgs', JSON.stringify(data, null, 2)) }) socket.on('OnFriendMsgs', async data => { console.log('>>OnFriendMsgs', JSON.stringify(data, null, 2)) const { FromUin, MsgType, Content } = data.CurrentPacket.Data if (MsgType !== 'TextMsg') return const reply = Content.replace(/你/g, '我').replace(/(?:么?|么\?|吗?|吗\?|?|\?)?$/, '!') const params = { toUser: FromUin, sendToType: 1, sendMsgType: 'TextMsg', content: reply, groupid: 0, atUser: 0, replayInfo: null } const resp = await callApi('SendMsg', params) console.log('callApi.result', resp) }) socket.on('OnEvents', async data => { console.log('>>OnEvents', JSON.stringify(data, null, 2)) })
比较关键的有两点:
- 调用io函数创建连接时需要提供
{ transports: ['websocket'] }
参数 - 连接上之后,需要先向服务器发送GetWebConn事件,否则收不到事件
- 调用io函数创建连接时需要提供
- 上面代码会打印输出收到的所有群消息、好友消息和事件,对于好友消息,会自动回复
- 从IOTQQ v2版开始,已经简化了ws部分,现在架构很清晰,只有上面代码里的OnGroupMsgs, OnFriendMsgs, OnEvents三种事件,其它功能都需通过调用web api实现
服务安全性考虑
- 大家应该注意到了,IOTQQ的Web API是赤裸裸的暴露在公网上的,这意味着,如果有人知道了你的API地址和当前登录的QQ号,他就可以用你的QQ来群发消息了,因此如果不只是玩玩的话,我们需要慎重考虑安全性问题
- 可以修改IOTQQ/CoreConf.conf里的Port配置项为
127.0.0.1:xxx
来仅允许本地访问,然后用nginx反向代理来控制外网访问权限 - 所有的Web api,加上Basic Auth验证,即需要客户端请求中包括Authorization请求头,可以自行设定用户名密码
-
综上,在nginx.conf中加上下面配置即可:
location /v1/Github/WebHook { proxy_pass http://localhost:8888; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } location /v1/ { proxy_http_version 1.1; if ($http_authorization != "Basic aW90cXE6MTIzNDU2Nzg=") { return 401; } proxy_pass http://localhost:8888; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } location / { proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_http_version 1.1; proxy_pass http://localhost:8888; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; }
说明:
if ($http_authorization != "Basic aW90cXE6MTIzNDU2Nzg=")
这一段进行用户名密码的比对,其中Basic后面的字符串的算法为BASE64(<用户名> + ':' + <密码>)
- 经过以上配置后,对于node.js端的Web API请求,只要给request的options参数中添加如下字段即可正常交互:
auth: { user: <用户名>, pass: <密码> }
- websocket接口可以同样通过nginx反向代理实现权限验证,见本文的续篇。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。