草庐IT

使用go-cqhttp搭建QQ机器人

饭a 2023-07-10 原文

使用go-cqhttp搭建QQ机器人

使用go-cqhttp搭建QQ机器人

序言

go-cqhttp是基于 Mirai 以及 MiraiGo 的 OneBot Golang 原生实现(此句照搬文档)
个人使用(不知道是不是只能使用)Python语言进行编写,仅供教程,不做完全分享
官方文档地址
github项目地址

安装环境

Python语言环境配置下载Python

要勾选Add python.exe to PATH
点击Next

勾选Add Python to environment variables
Install
安装完毕后Win + R打开运行输入cmd
键入Python

如上图所示即为安装成功

配置项目

下载go-cqhttp.exe后,双击运行,无视弹窗内容直接确定(因为要用运行完exe生成的bat来启动exe才是正确启动),三次确定后出现go-cqhttp.bat,双击运行。

配置config.yml(客户端信息)

选择HTTP通信,提示退出,打开config.yml
账号密码可不配置,拉到最下面

修改为以下内容

//可将从server部分完全替换
servers:
  # 添加方式,同一连接方式可添加多个,具体配置说明请查看文档
  #- http: # http 通信
  #- ws:   # 正向 Websocket
  #- ws-reverse: # 反向 Websocket
  #- pprof: #性能分析服务器

  - http: # HTTP 通信设置
      address: 0.0.0.0:5700 # HTTP监听地址
      timeout: 5      # 反向 HTTP 超时时间, 单位秒,<5 时将被忽略
      long-polling:   # 长轮询拓展
        enabled: false       # 是否开启
        max-queue-size: 2000 # 消息队列大小,0 表示不限制队列大小,谨慎使用
      middlewares:
        <<: *default # 引用默认中间件
      post:           # 反向HTTP POST地址列表
      #- url: ''                # 地址
      #  secret: ''             # 密钥
      #  max-retries: 3         # 最大重试,0 时禁用
      #  retries-interval: 1500 # 重试时间,单位毫秒,0 时立即
      url: http://127.0.0.1:5701/ # 地址
      secret: ''                  # 密钥
      max-retries: 10             # 最大重试,0 时禁用
      retries-interval: 1000      # 重试时间,单位毫秒,0 时立即

这里要特别注意的是,http配置的address与下方post的url端口不能相同(可以修改)
保存后运行bat,尝试登录

[2023-01-07 00:23:26] [INFO]: 当前版本:v1.0.0-rc4
[2023-01-07 00:23:26] [INFO]: 将使用 device.json 内的设备信息运行Bot.
[2023-01-07 00:23:26] [INFO]: Bot将在5秒后登录并开始信息处理, 按 Ctrl+C 取消.
[2023-01-07 00:23:31] [INFO]: 开始尝试登录并同步消息...
[2023-01-07 00:23:31] [INFO]: 使用协议: Android Phone
[2023-01-07 00:23:32] [INFO]: Protocol -> connect to server: 36.155.206.145:8080
[2023-01-07 00:23:32] [WARNING]: Protocol -> device lock is disable. http api may fail.
[2023-01-07 00:23:35] [INFO]: 收到服务器地址更新通知, 将在下一次重连时应用.
[2023-01-07 00:23:35] [INFO]: 登录成功 欢迎使用: acao
[2023-01-07 00:23:35] [INFO]: 开始加载好友列表...
[2023-01-07 00:23:35] [INFO]: 共加载 23 个好友.
[2023-01-07 00:23:35] [INFO]: 开始加载群列表...
[2023-01-07 00:23:36] [INFO]: 共加载 7 个群.
[2023-01-07 00:23:36] [INFO]: 资源初始化完成, 开始处理信息.
[2023-01-07 00:23:36] [INFO]: アトリは、高性能ですから!
[2023-01-07 00:23:36] [INFO]: HTTP POST上报器已启动: http://127.0.0.1:5701/
[2023-01-07 00:23:36] [INFO]: 正在检查更新.
[2023-01-07 00:23:36] [INFO]: CQ HTTP 服务器已启动: [::]:5700
[2023-01-07 00:23:48] [INFO]: 检查更新完成. 当前已运行最新版本.
[2023-01-07 00:23:48] [INFO]: 开始诊断网络情况
[2023-01-07 00:23:51] [INFO]: 网络诊断完成. 未发现问题
[2023-01-07 00:23:58] [WARNING]: 上报 Event 数据到 http://127.0.0.1:5701/ 失败: Post "http://127.0.0.1:5701/": dial tcp 127.0.0.1:5701: connectex: No connection could be made because the target machine actively refused it. 将进行第 1 次重试
[2023-01-07 00:24:02] [WARNING]: 上报 Event 数据到 http://127.0.0.1:5701/ 失败: Post "http://127.0.0.1:5701/": dial tcp 127.0.0.1:5701: connectex: No connection could be made because the target machine actively refused it. 将进行第 2 次重试

这里上报出现了许多错误,是正常现象,因为我们没有监听程序,没地方上报
等我们接下来写完监听程序就不会这样了
注:第七行的[WARNING]: Protocol -> device lock is disable. http api may fail.属于正常现象,不需要找问题(不影响)

config.yml 中,还可以设置在线状态,参考在线状态

配置device.json(账号信息)

{
	"display": "MIRAI.619943.001",
	"product": "mirai",
	"device": "mirai",
	"board": "mirai",
	"model": "mirai",
	"finger_print": "mamoe/mirai/mirai:10/MIRAI.200122.001/0642953:user/release-keys",
	"boot_id": "8cfd480f-5acb-cb0f-0462-9dd269b378c3",
	"proc_version": "Linux version 3.0.31-MJXB114B (android-build@xxx.xxx.xxx.xxx.com)",
	"protocol": 1,
	"imei": "121268379926671",
	"brand": "mamoe",
	"bootloader": "unknown",
	"base_band": "",
	"version": {
		"incremental": "5891938",
		"release": "10",
		"codename": "REL",
		"sdk": 29
	},
	"sim_info": "T-Mobile",
	"os_type": "android",
	"mac_address": "00:50:56:C0:00:08",
	"ip_address": [10, 0, 1, 3],
	"wifi_bssid": "00:50:56:C0:00:08",
	"wifi_ssid": "\u003cunknown ssid\u003e",
	"imsi_md5": "90b7592b208260238577eb697e1f426b",
	"android_id": "49ebbf42888f6b36",
	"apn": "wifi",
	"vendor_name": "MIUI",
	"vendor_os_name": "mirai"
}

这是格式化过的!!!不是你的出了问题!!!
主要注意的是Protocol,这是你的登录状态,默认5位ipad协议,这里我改用了Android协议

Android协议:登录状态显示,前面config.yml有设置的,但是手机端无法再登录Bot的QQ
ipad协议优点:运行Bot后可在手机端登录,但是登录状态会显示为WiFi在线-2G

值得一提的是,在config.yml的38行,有一个是否上报自身消息,也就是所谓的自触发,以及40行的是否移除replay自带at效果,根据自身需要打开(False是关闭,True是打开

消息监听

消息上报内容

也就是我们要从go-cqhttp那里接收上报的消息了
先来了解一下监听上报的消息格式内容(普通消息)

{
	'post_type': 'message',
	'message_type': 'group',
	'time': 1672415467,
	'self_id': 3054770279,
	'sub_type': 'normal',
	'font': 0,
	'group_id': 594875964,
	'user_id': 423866219,
	'message_id': -731133797,
	'sender': {
		'age': 0,
		'area': '',
		'card': '',
		'level': '',
		'nickname': '福建第一深情',
		'role': 'owner',
		'sex': 'unknown',
		'title': '',
		'user_id': 423866219
	},
	'anonymous': None,
	'message': '6',
	'message_seq': 4452,
	'raw_message': '6'
}

这是一条消息(当然也是格式化之后的)
其中post_type是我们接收到的消息类型,即message
message_type是指我们接收到的是group(群聊消息)或是private(私聊消息)
group_id为群号,user_id为QQ号,self_id为Bot本身的QQ号

那我们开始写一个监听程序

监听程序

我们用的是Python的pip库中的FlaskWin+R打开运行输入cmd后点击确定,先更新一下pip

C:\User\afanm> python -m pip install --upgrade pip

更新完成后再安装Flask

C:\User\afanm> pip install flask

将flask替换成其它,再安装requests

打开一个.py文件随意命名(我这里叫main.py)
监听如下

from flask import Flask,request
import afan
app = Flask(__name__)

@app.route('/', methods=["POST"])
def post_data():
    data = request.get_json()
    print(data)
    if data['post_type'] == 'message':
        
        message = data['message']
        print(message)
        afan.messagex()
    elif data['post_type'] == 'notice':
        pass
    else:
        print("忽略上报")

    return "OK"


if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5701)

导入初始化Flask,我们将request得到的数据赋值给data,意思就是data这个变量就是我们收到上报的消息,并调用我们写在afan.py的回复,这里的port就是我们刚刚post设置的端口

(插入)go-cqhttp运行的原理

go-cqhttp客户端将我们电脑配置成为微型服务器,开放了5700和5701端口进行通讯,通过访问我们自己电脑上的API接口进行发送,所以即使没有程序,我们访问接口依旧可以运行
例如发送消息接口终结点为send_msg,在运行客户端后,网址访问127.0.0.1/send_msg依旧可以发送消息(需要提交参数)

消息回复

那么我们封装一个接口,直接调用就可以发送消息,不需要反复写API
由官方API文档,我们能了解到:
消息的终结点为send_msg
需要的参数为群号,消息内容,发送类型,我们以群消息为例

class API:
	@staticmethod
	def send(message):
		url = "http://127.0.0.1:5700/send_msg"#这里要加上http://,不然会报错
		data = request.get_json()#获取上报消息
		params = {
			"message_type":data['message_type'],
			"group_id":data['group_id'],
			"message":message
		}
		requests.get(url,params=params)

这样,当我们在后方词库调用该函数时,只需传入消息内容便可以发送了,私聊的话只需要判断消息来源进行微调即可

接下来,创建文件afan.py,导入main.py以及一些其它库

我们前面写道,如果消息类型为message的话,调用afan.messagex(),导入afan后,定义一个函数messagex()
我的Bot名为阿草,我先写一个当我发送 阿草 时回复 阿草在哦 的词库

import requests
from flask import Flask,request
from main import API
def messagex():
	data = request.get_json()
	message = data['message']
	if "阿草" == message:
		API.send("阿草在哦")
	else:
		print("指令错误")#这里不是发送,是打印到我们后台监听程序

这样,当消息为阿草的时候,调用API发送阿草在哦

接下来我们只要运行main.py,然后启动go-cq客户端就可以了

至于其它东西,我们只需要根据上报收到的消息进行设置就行了,上报消息内容,我们依然可以在文档的 Event上报 处查看
实现其它内容,只需要封装其它接口进行调用即可

注意:封装接口时调用的端口是5700,客户端监听5700,消息post上报到5701,再有main.py进行监听5701调用词库回复,可根据需要自行修改,不要运行afan.py词库文件,会造成端口冲突的,我们只需要运行main.py和go-cq客户端即可

代码整合

最后送上上面整合的监听以及回复代码
main.py

from flask import Flask,request
import requests
import afan

app = Flask(__name__)

class API:
	@staticmethod
	def send(message):
		url = "http://127.0.0.1:5700/send_msg"#这里要加上http://,不然会报错
		data = request.get_json()#获取上报消息
		params = {
			"message_type":data['message_type'],
			"group_id":data['group_id'],
			"message":message
		}
		requests.get(url,params=params)

@app.route('/', methods=["POST"])
def post_data():
    data = request.get_json()
    print(data)
    if data['post_type'] == 'message':
        
        message = data['message']
        print(message)
        afan.messagex()
    else:
        print("忽略消息")

    return "OK"


if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5701)


afan.py

import requests
from flask import Flask,request
from main import API

def messagex():
	data = request.get_json()
	message = data['message']
	if "阿草" == message:
		API.send("阿草在哦")
	else:
		print("指令错误")#这里不是发送,是打印到我们后台监听程序

有关使用go-cqhttp搭建QQ机器人的更多相关文章

  1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

    我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

  2. ruby - 使用 RubyZip 生成 ZIP 文件时设置压缩级别 - 2

    我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看ruby​​zip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d

  3. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  4. ruby-on-rails - 使用 Ruby on Rails 进行自动化测试 - 最佳实践 - 2

    很好奇,就使用ruby​​onrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提

  5. ruby - 在 Ruby 中使用匿名模块 - 2

    假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于

  6. ruby - 使用 ruby​​ 和 savon 的 SOAP 服务 - 2

    我正在尝试使用ruby​​和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我

  7. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  8. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

    我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

  9. ruby - 使用 ruby​​ 将 HTML 转换为纯文本并维护结构/格式 - 2

    我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h

  10. ruby - 在 64 位 Snow Leopard 上使用 rvm、postgres 9.0、ruby 1.9.2-p136 安装 pg gem 时出现问题 - 2

    我想为Heroku构建一个Rails3应用程序。他们使用Postgres作为他们的数据库,所以我通过MacPorts安装了postgres9.0。现在我需要一个postgresgem并且共识是出于性能原因你想要pggem。但是我对我得到的错误感到非常困惑当我尝试在rvm下通过geminstall安装pg时。我已经非常明确地指定了所有postgres目录的位置可以找到但仍然无法完成安装:$envARCHFLAGS='-archx86_64'geminstallpg--\--with-pg-config=/opt/local/var/db/postgresql90/defaultdb/po

随机推荐