This article is participating in Python Theme Month. See the link to the event for more details

XDHJMM, I’m still that unwomanly cat

What can QQ robot do

QQ group is relatively large, can accommodate more people, the upper limit of 2000 people, is 4 times of the wechat group, QQ robot can be used to welcome new people, automatic reply and other functions, he can do almost what the wechat robot can do, reference this cat’s other two, there are various ideas, ideas:

  • Node front end welfare 】 【 WeChat robot latest available personal WeChat gathering | | support all WeChat ID
  • Python write a wechat robot, similar to gold mining paste automatic welcome, automatic invitation, etc

The cat doesn’t copy and copy

Prepare for

We are using Nonebot, install dependencies

pip3 install nonebot
Copy the code

Due to the official recommendation there is no qq emulation terminal available, see:

So we turned to another library instead: Go-CqHTTP, a GO language implementation of CQHTTP

First clone, please use the command of this cat, silently read milly milly coax ~ 3 seconds clone:

git clone depth=1 https://github.com.cnpmjs.org/Mrs4s/go-cqhttp
Copy the code

Windows, Linux can see the reference document, because this cat MAC test, can only compile themselves, need tizi is faster

go build -ldflags "-s -w -extldflags '-static'"
Copy the code

Compile party to generate./ go-cqHTTP, directly execute

./ go-cqHTTP did not find the configuration file, is generating a configuration file for you! Please select your communication mode:>1: HTTP communication
>2: forward communication with Websocket
>3: indicates reverse Websocket communication
>4: PProf performance analysis serverPlease enter the number you need, you can enter more than one number, the same number can also enter more than one (such as: 233) your choice is :123Copy the code

Enter 123 and press enter

The system prompts you to modify the configuration and restart

The default configuration file has been generated, please modify config.yml and restart!Copy the code

CTRL + C, modify config.yml

  uin: 1233456 # QQ account
  password: ' ' Use scan code to log in when the password is blank
Copy the code

Change to your robot, you can also not set, after scan can, see everyone XDJM

Change here:

  - ws-reverse:
      # reverse WS Universal address
      Note that the following two items are ignored when this address is set
      universal: Ws: / / 127.0.0.1:8080 / ws /
Copy the code

Ws ://127.0.0.1:8080/ws ://127.0.0.1:8080/ws ://127.0.0.1:8080/ws/

start

New/bot/main. Py

import nonebot

if __name__ == '__main__':
    nonebot.init()
    nonebot.load_builtin_plugins()
    nonebot.run(host='127.0.0.1', port=8080)
Copy the code

Note that the IP address and port are the same as the yML configuration above

Start the robot python3. /bot/main.py

python3 ./bot/main.py
ujson module not found, using json
msgpack not installed, MsgPackSerializer unavailable
[2021-07-27 11:41:28,298 nonebot] INFO: Succeeded to import "nonebot.plugins.base"
[2021-07-27 11:41:28,298 nonebot] INFO: Running on 127.0.0.1:8080
 * Serving Quart app ''
 * Environment: production
 * Please use an ASGI server (e.g. Hypercorn) directly in production
 * Debug mode: True
 * Running on http://127.0.0.1:8080 (CTRL + C to quit)
[2021-07-27 11:41:28,318 nonebot] INFO: Scheduler started
[2021-07-27 11:41:28,319] Running on http://127.0.0.1:8080 (CTRL + C to quit)
Copy the code

Ujson Module not found, using JSON

Start the CQHTTP

./go-cqhttp [2021-07-27 11:42:52] [INFO]: Current version :(devel) [2021-07-27 11:42:52] [INFO]: User group: 721829413 [2021-07-27 11:42:52] [INFO]: Run Bot using device information in device.json. [2021-07-27 11:42:52] [INFO]: [2021-07-27 11:42:57] [INFO]: Start trying to log in and synchronize the message... [2021-07-27 11:42:57] [INFO]: Protocol: iPad [2021-07-27 11:42:58] : WARNING: [2021-07-27 11:42:58] [WARNING]: 1. [2021-07-27 11:42:58] [WARNING]: 2. [2021-07-27 11:42:58] [WARNING]: Select: [2021-07-27 11:43:03] [INFO]: Protocol -> connect to server: 113.96.12.27:8080 [2021-07-27 11:43:05] [INFO]: Login success Welcome to use: Ling Jing [2021-07-27 11:43:05] [INFO]: Start loading friend list... [2021-07-27 11:43:05] [INFO]: Start loading group list... [2021-07-27 11:43:05] : Start loading group list... [2021-07-27 11:43:06] [INFO]: 10 groups were loaded. [2021-07-27 11:43:06] [INFO]: Initialization of the information database was completed. [2021-07-27 11:43:06] [INFO]: Attract ト, start processing information. [2021-07-27 11:43:06] [INFO]: Attract ト, activation, high-performance 1906 cara! [2021-07-27 11:43:06] [INFO]: Start trying to connect to reverse WebSocket Universal server: ws://127.0.0.1:8080/ws/ [2021-07-27 11:43:06] [INFO]: CQ WebSocket server started: 127.0.0.1:6700 [2021-07-27 11:43:06] [INFO]: Checking for updates [2021-07-27 11:43:06] [WARNING]: Checking for updates failed: Actions beta or self-compiled version used. [2021-07-27 11:43:06] [INFO]: CQ HTTP server started: 127.0.0.1:5700Copy the code

Login succeeded

The end of the robot also had a heartbeat because the WS connection was successful

[2021-07-27 11:43:06,317] 127.0.0.1:50013 GET /ws/ 1.1 101-8366 [2021-07-27 11:43:06,321] INFO in __init__: Received event: meta_event.lifecycle. Connect [2021-07-27 11:43:11,307] INFO in __init__: received event: meta_event.lifecycle. Connect [2021-07-27 11:43:11,307] INFO in __init__: received event: meta_event.lifecycle. Meta_event. Heartbeat [2021-07-27 11:43:16,306] INFO in __init__: received event: Meta_event. Heartbeat [2021-07-27 11:43:21,306] INFO in __init__: received event: meta_event.Copy the code

The diagram below:

Messaging test

Send a message to the qq number of the robot: /echo Hello, world

CQHTTP terminal

[2021-07-27 11:45:22] [INFO]: hello, world (1739668428) [2021-07-27 11:45:22] Send message to friend 123456(123456) : [{"type":... (926242495)Copy the code

Nonebot terminal

[2021-07-27 11:48:26,709] INFO in __init__: received event: Message. Private. Friend [2021-07-27 11:48:26,712 nonebot] INFO: Self: 654321, message-21468554 from 123456: '/ echo how are you, the world' [the 2021-07-27 11:48:26, 712 nonebot] the DEBUG: Parsing the command: [2021-07-27 11:48:26,713 nonebot] DEBUG: Matched command start: / [2021-07-27 11:48:26,713 nonebot] DEBUG: Split command name: ('echo',) [2021-07-27 11:48:26,713 nonebot] DEBUG: Command ('echo',) found, function: <function echo at 0x10d36c310> [2021-07-27 11:48:26,713 nonebot] DEBUG: New session of command ('echo',) created [2021-07-27 11:48:26,713 nonebot] DEBUG: Running command ('echo',) [2021-07-27 11:48:26,724 nonebot] DEBUG: Session of Command ('echo',) finished [2021-07-27 11:48:26,724 Nonebot] INFO: Message -21468554 is handled as a commandCopy the code

The effect is as follows:

The implementation of echo is simple:

@on_command('echo')
async def echo(session: CommandSession) :
    await session.send(session.state.get('message') or session.current_arg)
Copy the code

The basic configuration

Configuring the Superuser

The new config. Py

from nonebot.default_config import *

SUPERUSERS = {123456}
Copy the code

Change 123456 to the super user QQ number to be set

The main. Py instead:

import nonebot
import config

if __name__ == '__main__':
    nonebot.init(config)
    nonebot.load_builtin_plugins()
    nonebot.run(host='127.0.0.1', port=8080)
Copy the code

The nonebot terminal restarts, CQHTTP does not move, and ws will be automatically reconnected

Send: /say [CQ:music,type=qq,id=1663363]

Means to send a music share, as shown here:

More configuration

Start the config command and extract config config.py

from nonebot.default_config import *

# Set supertube QQ
SUPERUSERS = {123456}
Eg: echo hi
COMMAND_START = {' '}
Set IP and port
HOST = '0.0.0.0'
PORT = 8080
Copy the code

main.py

import nonebot
import config

if __name__ == '__main__':
    nonebot.init(config)
    nonebot.load_builtin_plugins()
    nonebot.run()
Copy the code

Restart the Nonebot terminal

Adding a default plug-in

Add: bot/awesome/plugins/default. Py

Change main.py and load the plugin directory

from os import path

import nonebot

import config

if __name__ == '__main__':
    nonebot.init(config)
    nonebot.load_plugins(
        path.join(path.dirname(__file__), 'awesome'.'plugins'),
        'awesome.plugins'
    )
    nonebot.run()
Copy the code

Here’s the weather:

default.py

from nonebot import on_command, CommandSession


The # on_command decorator declares a function as a command handler
The name of the command is "weather", "weather forecast" and "weather check".
@on_command('weather', aliases=('the weather'.'Weather forecast'.'Check the weather'))
async def weather(session: CommandSession) :
    Get the name (city) from the session state (session.state) and ask the user if it does not currently exist
    city = session.get('city', prompt='Which city do you want to check? ')
    Get the weather forecast for the city
    weather_report = await get_weather_of_city(city)
    Send the weather forecast to the user
    await session.send(weather_report)


The # weather.args_parser decorator declares a function as an argument parser to the weather command
The command parser is used to parse the arguments entered by the user into the actual data required by the command
@weather.args_parser
async def _(session: CommandSession) :
    Remove the whitespace at the beginning and end of the message
    stripped_arg = session.current_arg_text.strip()

    if session.is_first_run:
        # The first time the command is run (the first time you enter the command session)
        if stripped_arg:
            The first run parameter is not null, which means the user passes the city name directly after the command name
            For example, the user may send: Weather nanjing
            session.state['city'] = stripped_arg
        return

    if not stripped_arg:
        # User did not send a valid city name (instead sent a whitespace character), prompting for re-entry
        # Here session.pause() will send a message and pause the current session (the code after this line will not be run)
        session.pause('The name of the city you want to query cannot be empty, please re-enter')

    If the user is currently being asked for more information (such as the city to query in this case) and the user input is valid, put the session state in
    session.state[session.current_key] = stripped_arg


async def get_weather_of_city(city: str) - >str:
    This simply returns a string
    # In practice, this should call the weather API that returns real data and splice it into weather forecast content
    return f'{city}The weather is... '
Copy the code

Look at the effect:

It is important to note that we are using weather as an example here. For a separate function like weather, we can pull out a separate plug-in to implement it. The default.py, which can handle some default or a small number of bad classification, with very little code, can be concentrated here.

For the plugin this cat also gives several application scenarios, interested in digging friends can dig their own, also welcome to exchange in the comment area:

  • Search resources according to the corresponding information, such as @on_command(‘weather’, aliases=(‘ weather’, ‘weather forecast ‘, ‘check weather’)), and add multiple aliases to the alias to realize the requirement of default
  • Commands can use natural language analysis to determine which commands to use before docking, such as: What’s the weather in Beijing today?
  • You can chat with Turing bots

More ideas

  • Node front end welfare 】 【 WeChat robot latest available personal WeChat gathering | | support all WeChat ID
  • Python write a wechat robot, similar to gold mining paste automatic welcome, automatic invitation, etc

Automatic processing notification

Automatically agrees to add group request

New awesome/plugins/group_admin. Py

from nonebot import on_request, RequestSession


# Register functions as group request handlers
@on_request('group')
async def _(session: RequestSession) :
    # Determine whether the validation information meets the requirements
    if session.event.comment == 'code':
        # Verify that the information is correct and agree to join the group
        await session.approve()
        return
    # Validation error, reject group
    await session.reject('Say the code.')
Copy the code

Welcome new members

New awesome/plugins/notice. Py

from nonebot import on_notice, NoticeSession

Add notification handler to register functions as group members
@on_notice('group_increase')
async def _(session: NoticeSession) :
    # Send a welcome message
    await session.send('Welcome new friends ~')
Copy the code

Here we need to judge the group to reply, otherwise all groups will reply, session.event. Group_id judge

Note: When changing the py file, remember to restart the Nonebot terminal

reference

  • Nonebot document: docs. Nonebot. Dev/guide/getti…
  • Go-cqhttp is stable: docs.go-cqhttp.org/guide/
  • Go-cqhttp extension API: github.com/Mrs4s/go-cq…