基于go-cqhttp实现QQ机器人

前言

本篇文章原文:http://www.7yue.top/rabbitbot/

本篇文章记录一下自己在编写QQ机器人的时候所遇到的一些问题和核心功能的实现。

QQ机器人RabbitBot采用python编写,由于是个人学习使用,故目前不会开源完整代码,只会放出核心代码供学习参考。

使用的go-cqhttp项目:https://github.com/Mrs4s/go-cqhttp
go-cqhttp是基于 Mirai 以及 MiraiGo 的 cqhttp golang 原生实现。
RabbitBot在读取、发送QQ信息时采用的是HTTP API和反向HTTP POST接口。

github项目地址:https://github.com/Yang9999999/Go-CQHTTP-YesBot

初期配置

go-cqhttp的安装和完整配置可自行查看文档,这里描述一下关键部分。

配置文件:

{
    uin: 0
    password: 0
    encrypt_password: false
    password_encrypted: ""
    enable_db: false
    access_token: ""
    relogin: {
        enabled: true
        relogin_delay: 3
        max_relogin_times: 0
    }
    _rate_limit: {
        enabled: false
        frequency: 1
        bucket_size: 1
    }
    ignore_invalid_cqcode: false
    force_fragmented: true
    fix_url: false
    proxy_rewrite: ""
    heartbeat_interval: -1
    http_config: {
        enabled: true
        host: 0.0.0.0
        port: 5700
        timeout: 0
        post_urls: 
        {
            "127.0.0.1:5710":secret
        }
    }
    ws_config: {
        enabled: false
        host: 0.0.0.0
        port: 6700
    }
    ws_reverse_servers: [
        {
            enabled: false
            reverse_url: ws://you_websocket_universal.server
            reverse_api_url: ws://you_websocket_api.server
            reverse_event_url: ws://you_websocket_event.server
            reverse_reconnect_interval: 3000
        }
    ]
    post_message_format: string
    use_sso_address: false
    debug: false
    log_level: ""
    web_ui: null
}

其中uin为机器人QQ号
password为密码
enable_db为是否使用数据库,由于个人学习使用,这里并不开启数据库功能
heartbeat_interval为心跳间隔时间,默认开启,值小于0则关闭。
http_config进行http接口设置,post_urls设置上传接收端口
ws_configws_reverse_servers是Websocket的正向和反向接口,由于RabbitBot采用http接口,故这里也全部设置了false

RabbitBot开启后的显示结果:
在这里插入图片描述

信息发送和接收

RabbitBot利用python的socket库来进行数据的发送和接收,socket库的使用方法请自行学习。

5700为go-cqhttp默认端口,设置http post上报器端口为5710。

常用的HTTP API:
发送私聊信息:/send_private_msg
发送群聊信息:/send_group_msg

服务端接收信息配置:

ListenSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
ListenSocket.bind(('127.0.0.1', 5710))
ListenSocket.listen(100)

HttpResponseHeader = '''HTTP/1.1 200 OK
Content-Type: text/html
'''

#定位有效信息
def request_to_json(msg):
	for i in range(len(msg)):
		if msg[i]=="{" and msg[-1]=="}":
			return json.loads(msg[i:])
	return None

#需要循环执行,返回值为json格式
def rev_msg():# json or None
	conn, Address = ListenSocket.accept()
	Request = conn.recv(1024).decode(encoding='utf-8')
	#print(Request)
	rev_json=request_to_json(Request)
	#print(rev_json)
	conn.sendall((HttpResponseHeader).encode(encoding='utf-8'))
	conn.close()
	return rev_json

接收到的群聊信息格式:

{‘anonymous’: None, ‘font’: 0, ‘group_id’: ×××××, ‘message’: ‘爱你’, ‘message_id’: 1425567994, ‘message_seq’: 2170, ‘message_type’: ‘group’, ‘post_type’: ‘message’, ‘raw_message’: ‘爱你’, ‘self_id’: ×××××, ‘sender’: {‘age’: 0, ‘area’: ‘’, ‘card’: ‘’, ‘level’: ‘’, ‘nickname’: ‘七月’, ‘role’: ‘owner’, ‘sex’: ‘unknown’, ‘title’: ‘’, ‘user_id’: ×××××}, ‘sub_type’: ‘normal’, ‘time’: 1611721421, ‘user_id’: ×××××}

group_id为群号,user_id为发送者QQ号,message为接收到的信息,message_id为信息编号,随机生成,message_type为信息类型。

接收到的私聊信息格式:

{‘font’: 0, ‘message’: ‘[CQ:face,id=107]’, ‘message_id’: -730420846, ‘message_type’: ‘private’, ‘post_type’: ‘message’, ‘raw_message’: ‘[CQ:face,id=107]’, ‘self_id’: ×××××, ‘sender’: {‘age’: 0, ‘nickname’: ‘七月’, ‘sex’: ‘unknown’, ‘user_id’: ×××××}, ‘sub_type’: ‘friend’, ‘time’: 1611726456, ‘user_id’: ×××××}

user_id为通话者QQ号,message为接收到的信息,**‘[CQ:face,id=107]’**为表情数据,message_id为信息编号,随机生成,message_type为信息类型。

客户端发送信息配置:

client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

#从客户端发送给服务端
def client_to_conn():
	label = get_message_type()
	number = get_number()
	msg = get_raw_message()
	if flag == 0:
		msg = txt_msg(get_raw_message())
	if label == 'group':
		payload = "GET /send_group_msg?group_id=" + str(number) + "&message=" + msg + " HTTP/1.1\r\nHost: 127.0.0.1:5700\r\nConnection: close\r\n\r\n"
	elif label == 'private':
		payload = "GET /send_private_msg?user_id=" + str(number) + "&message=××××" + " HTTP/1.1\r\nHost: 127.0.0.1:5700\r\nConnection: close\r\n\r\n"
	client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
	client.connect(('127.0.0.1',5700))
	client.send(payload.encode("utf-8"))
	client.close()

信息处理

RabbitBot的学习信息保存至一个txt文档中,个人学习问题不大,但做成项目的话不建议这么使用。

获取信息和处理信息的一些函数:

#获取信息类型 群聊/私聊 group/private
def get_message_type():
	return all_message['message_type']

#获取群号/私聊qq号
def get_number():
	if get_message_type() == 'group':
		return all_message['group_id']
	elif get_message_type() == 'private':
		return all_message['user_id']
	else:
		print('出错啦!找不到群号/QQ号')
		exit()
# 获取信息发送者的QQ号
def get_user_id():
	return all_message['user_id']

#获取发送的信息
def get_raw_message():
	return all_message['raw_message']

#查找txt文本数据库
def txt_msg(msg):
	fp = open("/机器人/txt.txt", "r",encoding='utf-8')
	while 1:
		s = fp.readline()
		if not s:
			fp.close()
			if flag == 2:
				return
			return error()
		s = s.strip('\n')
		s1 = s.split(' ')[0]
		s2 = s.split(' ')[1]
		if '[CQ:at,qq=×××××] ' + s1 == msg:
			fp.close()
			return s2

发送信息的一些函数:

#帮助界面
def help_interface():
	number = get_number()
	payload = "GET /send_group_msg?group_id=" + str(number) + "&message=学习方式:%0a私聊rabbit酱,发送学习信息。%0a学习格式:%27学习%27%20%2b%20发送信息%20%2b%20回复信息,以空格分开%0a例:学习%20我爱你%20我也爱你" + " HTTP/1.1\r\nHost: 127.0.0.1:5700\r\nConnection: close\r\n\r\n"
	client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
	client.connect(('127.0.0.1',5700))
	client.send(payload.encode("utf-8"))
	client.close()

#错误
def error():
	client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
	client.connect(('127.0.0.1',5700))
	rand = random.randint(1,4)
	number = get_number()
	if rand == 1:
		msg = "我听不懂你在说什么哦"
	elif rand == 2:
		msg = "我好笨,听不懂呜呜呜"
	elif rand == 3:
		msg = "啊?发生了什么"
	elif rand == 4:
		msg = "干啥呢干啥呢"
	payload = "GET /send_group_msg?group_id=" + str(number) + "&message=" + msg + " HTTP/1.1\r\nHost: 127.0.0.1:5700\r\nConnection: close\r\n\r\n"
	client.send(payload.encode("utf-8"))
	client.close()

#发送猫猫图
,图片保存在本地
def send_cat_pic():
	global flag
	flag = 1
	cat_list = os.listdir("/data/catpic")
	all_message['raw_message'] = "[CQ:image,file=file:///data/catpic/"+ random.choice(cat_list)+"]"
	client_to_conn()

#发送setu,图片从API内获取
def send_setu_pic():
	apikey = '×××××××××××××××'
	req_url="https://api.lolicon.app/setu/"
	params = {"apikey":apikey}
	res=requests.get(req_url,params=params)
	setu_url=res.json()['data'][0]['url']
	all_message['raw_message'] ="[CQ:image,file="+setu_url+"]"
	client_to_conn()

私聊机器人学习数据:

#调教机器人
#这块代码也有点bug,需要后期调整。
def training_message():
	s = get_raw_message()
	if s.split(' ')[0] != '学习':
		return
	s2 = s.split(' ')[1]
	s3 = s.split(' ')[2]
	s = s2 + ' ' + s3
	fp = open("/机器人/txt.txt", "a",encoding='utf-8')
	fp.write('\n')
	fp.write(s)
	fp.close()
	client_to_conn()

获取数据的第一时间判断信息内容:

#首次判断信息内容
def first_judgement():
	if get_message_type() == 'private':
		training_message()
	if get_raw_message() == '[CQ:at,qq=×××××××××] help':
		help_interface()
		return
	if get_raw_message() == '[CQ:at,qq=×××××××××] setu':
		send_setu()
		return
	elif get_raw_message() == '[CQ:at,qq=×××××××××] 猫猫图':
		send_cat_pic()
		return
	elif len(get_raw_message()) < 20:  #即使不@,也有15%概率回复信息
		rand = random.randint(1,20)
		if rand <= 3:
			global flag
			flag = 2
			all_message['raw_message'] = '[CQ:at,qq=×××××××××] ' + all_message['raw_message']
			client_to_conn()
		else:
			return
	elif get_raw_message()[0:20] != '[CQ:at,qq=×××××××××]':
		return
	client_to_conn()

循环部分:

#flag为全局变量
#flag = 0 正常
#flag = 1 数据不通过数据库
#flag = 2 退出
#使用try、except语句保证程序不会因部分错误退出。
while 1:
	global flag
	flag = 0
	all_message = rev_msg()
	#print(all_message)
	try:
		first_judgement()
	except:
		continue

示例

在这里插入图片描述
在这里插入图片描述
支持收发文本、图片、表情等等。
在这里插入图片描述
利用api获取setu。

最终项目可搭载在服务器上不间断运行,目前只实现了基本功能,还有许多功能有待开发,欢迎大佬们来找我一起交流学习。

  • 37
    点赞
  • 162
    收藏
    觉得还不错? 一键收藏
  • 38
    评论
### 回答1: 要用 Python 写一个基于 go-cqhttp 的 QQ 机器人,你可以使用第三方库,如 CoolQ HTTP API 插件的 Python SDK,它封装了 go-cqhttp 提供的 HTTP API,使用起来更方便。 以下是一个简单的示例: ``` from cqhttp import CQHttp bot = CQHttp(api_root='http://127.0.0.1:5700/') @bot.on_message() def handle_msg(context): # 实现你的机器人逻辑 return {'reply': '你好,我是机器人!'} bot.run() ``` 这段代码中,我们定义了一个 handle_msg 函数来处理消息,并返回一个回复。运行这段代码后,你的机器人就会自动对收到的消息进行回复。 当然,你还可以根据需要添加更多的处理逻辑,例如:处理私聊消息,实现智能问答等。 ### 回答2: 基于go-cqhttp,使用Python编写QQ机器人可以通过与go-cqhttp插件的HTTP API进行交互来实现。 首先,将Python的requests库导入项目中,以便发送HTTP请求。 接下来,我们需要处理机器人收到的消息。通过模拟用户发送消息时,go-cqhttp发送的HTTP POST请求,我们可以使用Python的Flask框架来接收和处理这些消息。 在接收消息的路由上,我们可以使用Flask的`@app.route('/message')`来定义一个路由函数。在这个函数中,我们可以提取出消息中的关键信息,例如发送者QQ号码、发送的消息内容等。 接下来,我们可以使用条件语句对接收到的消息进行分类处理。例如,我们可以根据关键字回复不同的内容,或者调用外部API来进行一些其他操作。可以根据情况,编写不同的函数作为消息处理器。 在处理完消息后,我们需要将最终的回复发送给发送者。我们可以通过构造一个回复消息的字典,并将其转化为JSON格式,然后使用requests库发送POST请求到你自己的go-cqhttp插件上的HTTP API。 最后,我们可以利用go-cqhttp插件的事件上报功能,来处理一些其他的事件。例如好友申请、群聊消息等。 总结起来,基于go-cqhttp,用Python写一个QQ机器人可以通过与go-cqhttp插件的HTTP API进行交互,处理接收的消息和事件,并根据需要编写不同的函数作为消息处理器、事件处理器。最后,将回复消息发送给发送者。通过这些步骤,我们可以实现一个简单的QQ机器人。 ### 回答3: 基于go-cqhttp,我们可以使用Python来编写一个QQ机器人。首先,我们需要使用Python的 requests 库与go-cqhttp建立通信。 首先,我们需要在go-cqhttp的配置文件中开启HTTP、WS(WebSocket)接口。然后,我们可以使用python的requests库向go-cqhttp发送HTTP请求来完成一些操作,例如发送私聊消息: ```python import requests url = "http://127.0.0.1:5700/send_private_msg" data = { "user_id": 你的QQ号, "message": "Hello, World!" } response = requests.post(url, json=data) ``` 这将向你的QQ号发送私聊消息"Hello, World!"。 然后,我们可以使用Python来监听go-cqhttp发送给QQ机器人的消息,这里我们可以使用WebSocket连接进行实时通信。我们可以使用Python的websocket库来实现WebSocket通信: ```python import websocket def on_message(ws, message): print(message) def on_error(ws, error): print(error) def on_close(ws): print("连接已关闭") def on_open(ws): print("连接已打开") # 创建WebSocket连接对象 ws = websocket.WebSocketApp("ws://127.0.0.1:6700") # 绑定回调函数 ws.on_message = on_message ws.on_error = on_error ws.on_close = on_close ws.on_open = on_open # 开始监听消息 ws.run_forever() ``` 这将打开一个WebSocket连接,接收go-cqhttp发送给QQ机器人的消息,并将其打印出来。 当然,以上只是一个简单的例子,对于一个完整的QQ机器人,我们还可以做很多其他的操作,例如发送群聊消息、处理命令、响应事件等等。这些操作都可以通过向go-cqhttp发送HTTP请求来实现。 综上所述,使用Python编写一个基于go-cqhttpQQ机器人是十分可行的,我们可以利用Python提供的各种库与go-cqhttp进行通信,实现丰富的功能。
评论 38
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值