
这是一篇基于Mirai框架使用Python通过Http协议开发
本系列使用所有的源码皆开源到Github,开源协议GPLv3
在学习之前需要您知道并了解一些基本的数学知识
一定要动手实践!一定要动手实践!一定要动手实践!光看是看不懂的!
上一篇专栏确实对新人不太友好,本篇将采用从0开始,包括但不限于从开始安装配置讲起
已经配置好环境的同学可以跳过学前准备
一切开发旨在学习,请勿用于非法用途
下载安装软件*Java SE 15.0.1:https://download.oracle.com/otn/java/jdk/15.0.1%2B9/51f4f36ad4ef43e39d0dfdbaf6549e32/jdk-15.0.1_windows-x64_bin.exe*Python 3.9.5:https://www.python.org/ftp/python/3.9.5/python-3.9.5-amd64.exe*Mirai-MCL开发框架:https://github.com/iTXTech/mirai-console-loader/archive/refs/heads/master.zip集成开发环境(PyCharm):https://www.jetbrains.com/zh-cn/pycharm/download/download-thanks.html?platform=windows&code=PCC带"*"的由于下载时间过长或有时无法访问,在这里已打成软件包(仅在以下地址下载)软件整合包:https://cowtransfer.com/s/e91a8c2aeda44e一定要下载完之后再往下看!!
安装Java开发环境*本次安装的是Java SE 15.0.1版本①打开“jdk-15.0.1_windows-x64_bin.exe”进行Java SE安装②一直点击“下一步”,等待进度条走完出现,关闭按钮③打开Cmd输入 “java -version"后查看是否出现 java version "15.0.1"字样④输入 “javac -version"后查看是否出现 javac 15.0.1字样且与上面版本号相同④安装PyThon开发环境
安装PyThon开发环境*本次安装的是PyThon 3.9.5版本①打开“python-3.9.5-amd64.exe”进行PyThon安装②选择在界面下面名为“Add Python 3.9 to PATH"前的复选框③点击上面第一个选项名为”Install Now“④等待进度条走完后,点击Clos选项退出⑤打开Cmd输入”python“后查看是否出现Python 3.9.5字样④安装Mirai开发框架
安装Mirai开发框架*①将压缩包解压后,打开点击名为”mcl-1.2.2“文件夹②双击运行”mcl.cmd“文件③弹出黑色Cmd窗口后等待后续安装完成最下面出现”>_“④关闭窗口将名为“mirai-api-http-v1.12.0.mirai.jar”文件移动到“mcl-1.2.2“文件夹中的“plugins”中⑤运行“mcl-1.2.2“文件夹中的"mcl.cmd"⑥配置Mirai
配置Mirai*①打开”mcl-1.2.2“文件夹中的”config“文件夹,打开”Console”文件夹②右键“AutoLogin.yml”选择编辑③将文本中的“account: 123456"的“123456”改为想要作为机器人账号的数字账号④将文本中的“value: pwd"的“pwd”改为想要作为机器人账号的数字密码⑤其他的暂时不用动,保存并关闭“AutoLogin.yml”⑥回到”config“文件夹,打开“net.mamoe.mirai-api-http”文件夹⑦右键“setting.yml”选择编辑⑧将“host: 0.0.0.0“中的”0.0.0.0”更改为“127.0.0.1“⑨记住”authKey“的值,之后的编写中要用到 ⑩其他保持默认,保存后关闭即可
安装&配置集成开发环境*⛆如果已经有适合开发Python程序的IDE可以跳过此步骤(本系列教程将使用PyCharm作为IDE)①下载IDE安装包,选择Communuty版本进行下载②双击打开安装程序,进行安装,一直”Next“完成安装更改成中文

打开之后的样子

点击New Project之后

创建完之后出现主界面

点击菜单栏的File

在Settings界面选择Plugins选项

在搜索栏中输入chinese

等待进度条安装完成,重启IDE

重启后就可以看到已经修改成中文了
到这里已经完成了全部的学前准备
已经会一点基本操作的同学可以跳过IDE基本使用
首先我们先写一个简单的PyThon程序

输出你好!

*知识点print函数*

没有格式化文件
这里就可以使用快捷键”Ctrl+Alt+L“进行格式化
能看到这里已经超过了90%的人了!
先看最终效果

今天实现的效果
首先分析这个是怎么实现的?

分为四大步骤
初始化?为什么要初始化?我们要通过建立http协议建立通信,用来接收信息和返回信息

*Session*
首先使用Python来获取Session
这里我们将会用到Python中的request包
包?什么是包?

包是为了方便管理这些模块而产生的概念
那怎么调用包?
import requests # 以调用request包为例

那怎么用Python中的request包来获取Bot的Session呢?
import requests # 调用名为request的包
req = request.post()#使用request包中的post函数并将返回值写去变量req里 那怎么调用包中的函数呢?

调用的是request包中的post函数
那怎么用调用的函数实现HTTP请求呢?
import requests # 调用名为request的包
url = "http://127.0.0.1:8080/verify"# 创建一个名为url的变量,其中的ip地址是在学前准备里规定好的,/verify地址从官方文档中读取到的
data = {"verifyKey": "U9HSaDXl39ksd918273hU"}# 创建一个名为data的变量,其中的json是在官方文档中找到的,键名为verifyKey的值是在mirai-api-http中生成的
req = requests.post(url,data=data)#使用request包中的post函数并将返回值写去变量req里
print(req.text) # 输出经过post请求返回的值其中.text是表示输出请求后得到的文本

url组成
上面提到的ip地址和json的值都是在目录
mcl-1.2.2/config/net.mamoe.mirai-api-http/setting.yml
中设置好的

其中的host就是ip地址port就是冒号后面的数字authk就是键值
这样我们就完成了第一步获取Session的值
那如果在请求数据过程中出现错误怎么处理呢?
我们知道网页请求出现错误的时候会显示404网页请求成功时会产生一个200的状态码
所以我们判断请求是否成功就需要加一个判断条件
首先我们使用
import requests # 调用名为request的包
url = "http://127.0.0.1:8080/verify"# 创建一个名为url的变量,其中的ip地址是在学前准备里规定好的,/verify地址从官方文档中读取到的
data = {"verifyKey": "U9HSaDXl39ksd918273hU"}# 创建一个名为data的变量,其中的json是在官方文档中找到的,键名为verifyKey的值是在mirai-api-http中生成的
req = requests.post(url,data=data)#使用request包中的post函数并将返回值写去变量req里
print(req.text) # 输出经过post请求返回的值其中.text是表示输出请求后得到的文本
print(req.status_code)# 输出经过post请求返回的值其中.status_code是表示输出请求的状态码

可以看到在最后一行显示了状态码“200”
在此基础上添加if判断句

if...esle...判断语句
由此就可以将上面的代码进行优化
import requests # 调用名为request的包
url = "http://127.0.0.1:8080/verify" # 创建一个名为url的变量,其中的ip地址是在学前准备里规定好的,/verify地址从官方文档中读取到的
data = '{"verifyKey": "INITKEYcokUrLe4"}' # 创建一个名为data的变量,其中的json是在官方文档中找到的,键名为verifyKey的值是在mirai-api-http中生成的
req = requests.post(url, data=data) # 使用request包中的post函数并将返回值写去变量req里
if req.status_code == 200: # 如果状态码等于200则执行代码块1
print(req.text)
else:
print("请求错误")#返回错误信息 运行程序,我们会得到这样一段json代码
{"code":0,"session":"Bk9YUZW6"} 虽然session键的值会和这里的值不同
那怎么去提取session键的值呢?
这就用到Python的两一个标准库“json”来解析json字符串
import json # 同样是使用import关键字导入json包 在json包里有一个名为"loads"的函数那他是干嘛用的?
json.loads 用于解码 JSON 数据。该函数返回 Python 字段的数据类型
现在我们就用json.loads函数解码JSON字符串
import requests # 调用名为request的包
import json # 同样是使用import关键字导入json包
url = "http://127.0.0.1:8080/verify" # 创建一个名为url的变量,其中的ip地址是在学前准备里规定好的,/verify地址从官方文档中读取到的
data = '{"verifyKey": "INITKEYcokUrLe4"}' # 创建一个名为data的变量,其中的json是在官方文档中找到的,键名为verifyKey的值是在mirai-api-http中生成的
req = requests.post(url, data=data) # 使用request包中的post函数并将返回值写去变量req里
if req.status_code == 200: # 如果状态码等于200则执行代码块1
req = json.loads(req.text)
authkey = req['session']
print(authkey)# 提取出键名为session的值
else:
print("请求错误")#返回错误信息 这样就得到了session的值,到这里认证会话就已经编写完成了
之后再进行Session绑定到Bot
和上面的方法相同
接着上面的代码继续编写
import requests
import json
# 获取session部分
url = "http://127.0.0.1:8080/verify"
data = '{"verifyKey": "INITKEYcokUrLe4"}'
req = requests.post(url, data=data)
if req.status_code == 200:
req = json.loads(req.text)
authkey = req['session']
print(authkey)
# 绑定session部分
url = "http://127.0.0.1:8080/bind"
data = '{"sessionKey": "' + authkey + '","qq": 123456789}' # 把QQ的值改为作为机器人的账号
req = requests.post(url, data=data)
if req.text == '{"code":0,"msg":"success"}': # 如果绑定成功
print(authkey) # 打印出session
else:
print("绑定session失败!")
else:
print("请求错误") # 返回错误信息
到这里session绑定也做完了
为了以后方便调用和维护方便,我们将它封装成函数
什么是函数?函数就像是加工厂,把材料&半成品建工程产品

函数的定义
那如何把上面的代码封装成一个函数呢?
import requests
import json
def key(): # 定义为key的函数
# 获取session部分
url = "http://127.0.0.1:8080/verify"
data = '{"verifyKey": "INITKEYcokUrLe4"}'
req = requests.post(url, data=data)
if req.status_code == 200:
req = json.loads(req.text)
authkey = req['session']
print(authkey)
# 绑定session部分
url = "http://127.0.0.1:8080/bind"
data = '{"sessionKey": "' + authkey + '","qq": 123456789}' # 把QQ的值改为作为机器人的账号
req = requests.post(url, data=data)
if req.text == '{"code":0,"msg":"success"}': # 如果绑定成功
return authkey # 使用return输出session的值
else:
print("绑定session失败!")
else:
print("请求错误") # 返回错误信息 封装成函数之后就可以轻松的调用并输出session了
import requests
import json
def key(): # 定义为key的函数
# 获取session部分
url = "http://127.0.0.1:8080/verify"
data = '{"verifyKey": "INITKEYcokUrLe4"}'
req = requests.post(url, data=data)
if req.status_code == 200:
req = json.loads(req.text)
authkey = req['session']
# print(authkey)
# 绑定session部分
url = "http://127.0.0.1:8080/bind"
data = '{"sessionKey": "' + authkey + '","qq": 123456789}' # 把QQ的值改为作为机器人的账号
req = requests.post(url, data=data)
if req.text == '{"code":0,"msg":"success"}': # 如果绑定成功
return authkey # 使用return输出session的值
else:
print("绑定session失败!")
else:
print("请求错误") # 返回错误信息
if __name__ == '__main__': # main可以当作任何程序的入口
key = key() # 将函数key()输出的值写入变量局部key
print(key) # 输出局部变量key的值
这样初始化的步骤就全部完成了!好耶!
接收信息?需要什么步骤才能接收到?

Get json Massage!
首先获取信息
那怎么获取呢?
从文档里能找到名为“获取队列尾部”的查询地址
import requests
import json
def key(): # 定义为key的函数
#此处省略了key函数的内容实际操作的时候一定要加上!
def massage(keys):#定义一个新的函数,key为函数的输入值主要输入session的值
url = 'http://127.0.0.1:8080/fetchMessage?sessionKey=' + keys + '&count=1'#在这里使用了函数的输入值key
req = requests.get(url)# 使用requests包中的get函数进行获取信息字符串
print(req)
return req.text
if __name__ == '__main__': # main可以当作任何程序的入口
key = key() # 将函数key()输出的值写入变量局部key
print(key) # 输出局部变量key的值
massage = massage(key)
print(massage)
点击运行

运行完之后会出现以上内容
可以看到他返回了串json字符串
{"code":0,"msg":"","data":[]} 由于没有发送任何信息所以msg和data里面都是空白的
先使用json模块解析这串字符串
import requests
import json
def key(): # 定义为key的函数
#此处省略了key函数的内容实际操作的时候一定要加上!
def massage(keys): # 定义一个新的函数,key为函数的输入值主要输入session的值
url = 'http://127.0.0.1:8080/fetchMessage?sessionKey=' + keys + '&count=1' # 在这里使用了函数的输入值key
req = requests.get(url) # 使用requests包中的get函数进行获取信息字符串
print(req)
req = json.loads(req.text) # 使用json库解析这段请求回来的json代码
if len(req["data"]) != 0: # 这里使用len函数来读取字符串的长度,当req["data"]的长度不等于0时执行以下操作
return req #返回req的值
if __name__ == '__main__': # main可以当作任何程序的入口
key = key() # 将函数key()输出的值写入变量局部key
print(key) # 输出局部变量key的值
massage = massage(key) #将massage函数的值赋值到变量massage
print(massage) #输出变量massage的值
在这时我们要使程序循环运行用来获取新的信息

wile循环
和if有点类似 在条件那里如果为真(True)则循环执行代码块
import requests
import json
import time # 引入time包
def key(): # 定义为key的函数
#此处省略了key函数的内容实际操作的时候一定要加上!
def massage(keys): # 定义一个新的函数,key为函数的输入值主要输入session的值
url = 'http://127.0.0.1:8080/fetchMessage?sessionKey=' + keys + '&count=1' # 在这里使用了函数的输入值key
req = requests.get(url, headers={'Connection': 'close'}, stream=False) # 使用requests包中的get函数进行获取信息字符串
# print(req.text)
req = json.loads(req.text) # 使用json库解析这段请求回来的json代码
if len(req["data"]) != 0: # 这里使用len函数来读取字符串的长度,当req["data"]的长度不等于0时执行以下操作
print(req)
return req
if __name__ == '__main__': # main可以当作任何程序的入口
key = key() # 将函数key()输出的值写入变量局部key
# print(key) # 输出局部变量key的值
while True: # 使程序进入一个死循环状态用来循环获取聊天信息
massage = massage(key)# 调用massage函数进行获取
time.sleep(1)# 引入time包实现程序的延迟操作,防止请求过快消耗过多资源 运行程序并向Bot发送信息

发送信息后可以看到json文字串
来分析一下json字符串
{
'code': 0, //code处理状态 0正常
'msg': '',
'data': [
{
'type': 'FriendMessage', //type是表示是什么类型的消息,FriendMseeage是好友普通消息
'messageChain': [
{
'type': 'Source',
'id': 15034,
'time': 1637152325
},
{
'type': 'Plain', //Plain代表这里是文字信息类型
'text': 'hello' //text的值是发来的信息内容
}
],
'sender': { //sender是发送者信息
'id': 3177045556, //id就是发送者的账号
'nickname': '𐂂阿⃠良⃠良⃠木⃠馨⃠', //nickname就是发送者的名字
'remark': '备注名' //remark是对你的备注名
}
}
]
} 这一大串的信息怎么去提取需要的嘞?
还是使用json库来实现
根据发来的json字符串按照所需的键逐条分析:
在请求获取成功之后其中code键会返回一个状态码,当这个状态码为”0”时证明请求成功继续执行下面的步骤(需要if来判断请求码的值)
data中第一个type中的值是代表消息类型,消息类型的值为FriendMessage根据文档可知这是来自好友的消息类型
data中messageChain储存的就是消息内容,在消息内容中'type': 'Plain'的组里储存的就是发来的信息内容
data中sender组中id的值时发送这的ID号
以上4条就是需要我们提取的信息
那怎么使用Python中的json库进行解析和提取?
和上面提到的提取session的值类似,来继续改写massage函数
def massage(keys): # 定义一个新的函数,key为函数的输入值主要输入session的值
url = 'http://127.0.0.1:8080/fetchMessage?sessionKey=' + keys + '&count=1' # 在这里使用了函数的输入值key
req = requests.get(url, headers={'Connection': 'close'}, stream=False) # 使用requests包中的get函数进行获取信息字符串
# print(req.text)
req = json.loads(req.text) # 使用json库解析这段请求回来的json代码
if len(req["data"]) != 0: # 这里使用len函数来读取字符串的长度,当req["data"]的长度不等于0时执行以下操作
if req['code'] == 0: # 判断code值是否为0
data = {'type': req['data'][0]['type']} # 定义一个新的json数组用来存储信息,同时将键“type”的值定义为在上面2中分析的消息类型
print(req)
return req
到这里就完成了组条分析的1、2步
问么判断是否是好友信息呢?
在上面的步骤中我们把消息类型“type”的值提取出来了,加个判断句:当变量"data"等于“FriendMessage”时继续向下读取发送者信息(id)
def massage(keys):
url = 'http://127.0.0.1:8080/fetchMessage?sessionKey=' + keys + '&count=1' # 在这里使用了函数的输入值key
req = requests.get(url, headers={'Connection': 'close'}, stream=False) # 使用requests包中的get函数进行获取信息字符串
# print(req.text)
req = json.loads(req.text) # 使用json库解析这段请求回来的json代码
if len(req["data"]) != 0: # 这里使用len函数来读取字符串的长度,当req["data"]的长度不等于0时执行以下操作
if req['code'] == 0: # 判断code值是否为0
data = {'type': req['data'][0]['type']} # 定义一个新的json数组用来存储信息,同时将键“type”的值定义为在上面2中分析的消息类型
if data['type'] == "FriendMessage": # 过滤数据类型
data['SenderQQ'] = str(req['data'][0]['sender']['id']) # 提取发送者ID号写入字典中名为SenderQQ的键中
data['SenderName'] = req['data'][0]['sender']['nickname'] # 提取发送者昵称写入字典中名为SenderName的键中
print(data)
return data
拆分效果如下:
{'type': 'FriendMessage', 'SenderQQ': '3177045556', 'SenderName': '𐂂阿⃠良⃠良⃠木⃠馨⃠'} 消息类型(type):FriendMessage,发送者账号(SenderQQ):3177045556,发送者昵称(SenderName):𐂂阿⃠良⃠良⃠木⃠馨⃠
经过以上的才分成功把发送者信息化简了,接下来解决信息内容怎么提取:
这里我们用到for...in...循环结构来实现将messageChain键中的数据进行拆分

历遍函数
for...in...可以将数组逐条读取,能逐条读取就可以逐条的筛选信息了
我们要逐条读取"messageChain"中的信息,所以我们要将"messageChain"放在”y“的位置
也就是这样:
for datalist in req['data'][0]['messageChain']: 将"messageChain"中的信息,逐条读取出来加以判断
def massage(keys):
url = 'http://127.0.0.1:8080/fetchMessage?sessionKey=' + keys + '&count=1' # 在这里使用了函数的输入值key
req = requests.get(url, headers={'Connection': 'close'}, stream=False) # 使用requests包中的get函数进行获取信息字符串
# print(req.text)
req = json.loads(req.text) # 使用json库解析这段请求回来的json代码
if len(req["data"]) != 0: # 这里使用len函数来读取字符串的长度,当req["data"]的长度不等于0时执行以下操作
if req['code'] == 0: # 判断code值是否为0
data = {'type': req['data'][0]['type']} # 定义一个新的json数组用来存储信息,同时将键“type”的值定义为在上面2中分析的消息类型
if data['type'] == "FriendMessage": # 过滤数据类型
data['SenderQQ'] = str(req['data'][0]['sender']['id']) # 提取发送者ID号写入字典中名为SenderQQ的键中
data['SenderName'] = req['data'][0]['sender']['nickname'] # 提取发送者昵称写入字典中名为SenderName的键中
for datalist in req['data'][0]['messageChain']:
if datalist['type'] == "Plain":
data['Plain'] = str(dataList['text'])
print(data)
return data
可以看到在Plain中就存有发来的信息了
{'type': 'FriendMessage', 'SenderQQ': '3177045556', 'SenderName': '𐂂阿⃠良⃠良⃠木⃠馨⃠', 'Plain': '测试'} 获取信息部分就完成了!
接下来就差处理&发送信息了
我们先做出发送信息部分
[POST] http://127.0.0.1:8080/sendFriendMessage 调用以上路径进行信息的发送
具体发送方法和上面大同小异,所以这里直接上代码,具体看注释
# key是session的值,Qid是要像谁发送的qq号,plain是要发送的内容
def send_message_person(key, Qid, plain):#型定义一个函数惊醒数据的发送
url = "http://127.0.0.1:8080/sendFriendMessage"#上面提到的请求地址
data = '{"sessionKey":"' + key + '","target":' + Qid + ',"messageChain":[{ "type":"Plain", "' + plain + '" },]}'# 请求信息
requests.post(url,data=data)#使用post函数进行通信
发送信息的部分就完成了
接下来是处理信息
在上面的最终效果里不难发现机器人的回复去掉了"吗","?"添加了"!"
那我们怎么去实现这个效果呢?
这就又要使用Python自带的方法了strip("data"),它是用来替换开头或结尾的字符
利用这个方法使原信息去掉"吗","?"
str(massage["Plain"][0]).strip("吗??") 大体就完成了:
import time
import requests
import json
def key():
#此处省略了key函数的内容实际操作的时候一定要加上!
def message(keys): # 定义一个新的函数,key为函数的输入值主要输入session的值
#此处省略了message函数的内容实际操作的时候一定要加上!
def send_message_person(key, Qid, plain):
#此处省略了send_message_person函数的内容实际操作的时候一定要加上!
if __name__ == '__main__': # main可以当作任何程序的入口
key = key() # 将函数key()输出的值写入变量局部key
# print(key) # 输出局部变量key的值
while True: # 使程序进入一个死循环状态用来循环获取json聊天信息
message = message(key)
if massage["Plain"][0] > 0: # 判断有没有信息
send_massage = str(massage["Plain"][0]).strip("吗??")
send_message_person(key, massage["SenderQQ"], send_massage)#调用函数进行发送
time.sleep(1) 源码放在这里 → https://github.com/ExMikuPro/Mirai-Learn-Episode-one
Mirai:https://github.com/mamoe/mirai
Mirai Console Loader(MCL):https://github.com/iTXTech/mirai-console-loader
Mirai-api-http:https://docs.mirai.mamoe.net/mirai-api-http/
gplv3:https://doc.yonyoucloud.com/doc/sfd-gpl/gplv3.html