<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>0x韭菜</title>
        <link>https://paragraph.com/@0x-9</link>
        <description>币圈小韭菜</description>
        <lastBuildDate>Wed, 29 Apr 2026 10:15:06 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <image>
            <title>0x韭菜</title>
            <url>https://storage.googleapis.com/papyrus_images/6cb20446e7c6f00c2f76a6c662681631375c929a5403dc816f370c186af13204.webp</url>
            <link>https://paragraph.com/@0x-9</link>
        </image>
        <copyright>All rights reserved</copyright>
        <item>
            <title><![CDATA[discord水群bot教程(2) 消息监控]]></title>
            <link>https://paragraph.com/@0x-9/discord-bot-2</link>
            <guid>juuIDrXM9PYitize53NJ</guid>
            <pubDate>Sun, 20 Feb 2022 06:54:45 GMT</pubDate>
            <description><![CDATA[前言上一篇文章介绍了机器人的话术抓取以及双号互聊功能的实现，其实如果只需要无脑水群上篇文章介绍的代码就可以实现这个功能了discord水群bot教程(1) 双号互聊 脚本但是在实际使用中我们会发现有些项目方不想让机器人获利,所以他们会对频道内聊天的用户进行bot检测，随着时间推移项目方检测的手段也越来越多，比如@全体成员在指定时间内不要发言，或者@你让你回答一些简单的问题，又或者玩什么123木头人的游戏，总之在这个过程中你如果被逮到那么这个账号基本上就要被送出这个服务器了 所以接下来文章介绍的就是如何利用消息监控,让你避开一些项目方的突击检测教程开始项目环境配置等一些基础问题,请参考上篇文章的介绍,这里就不多做说明了 首先我们要监控项目方的检测手段,自然先要获取频道内的聊天消息,然后通过对聊天消息分析来判断是否有人在检查机器人,我们还是F12打开浏览器控制台,然后在网页版discord进入我们需要监控的频道,在浏览器控制台network内找到messages请求请求参数的介绍可以参考上篇文章,这里我们主要是分析接口返回的数据,我们切换到Preview可以看到我在频道内分别发送了一...]]></description>
            <content:encoded><![CDATA[<h2 id="h-" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">前言</h2><p>上一篇文章介绍了机器人的话术抓取以及双号互聊功能的实现，其实如果只需要无脑水群上篇文章介绍的代码就可以实现这个功能了</p><blockquote><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://mirror.xyz/0x3595801c3bd933E1a97c5c679B77A4306739223f/X1E-WmxTxfqlybAV0hUbwBjISsG7THXlpaQhB9tcjhA">discord水群bot教程(1) 双号互聊 脚本</a></p></blockquote><p>但是在实际使用中我们会发现有些项目方不想让机器人获利,所以他们会对频道内聊天的用户进行bot检测，随着时间推移项目方检测的手段也越来越多，比如@全体成员在指定时间内不要发言，或者@你让你回答一些简单的问题，又或者玩什么123木头人的游戏，总之在这个过程中你如果被逮到那么这个账号基本上就要被送出这个服务器了</p><p>所以接下来文章介绍的就是如何利用消息监控,让你避开一些项目方的突击检测</p><h2 id="h-" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">教程开始</h2><p><em>项目环境配置等一些基础问题,请参考上篇文章的介绍,这里就不多做说明了</em></p><p>首先我们要监控项目方的检测手段,自然先要获取频道内的聊天消息,然后通过对聊天消息分析来判断是否有人在检查机器人,我们还是F12打开浏览器控制台,然后在网页版discord进入我们需要监控的频道,在浏览器控制台network内找到messages请求</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/bba9868bc89dade7745e976a0d694875fdf62a7df2aa0c23eadc3131e611deb5.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>请求参数的介绍可以参考上篇文章,这里我们主要是分析接口返回的数据,我们切换到Preview</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/a88f667ee25f9e0d758229ac5d13fe989e79e2253e15f3df71c768a4fe7b1fb0.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>可以看到我在频道内分别发送了一条普通消息,一条@指定用户的小,一条@所有人的消息,接下来我们就从请求返回值里来分析这3条消息的区别,首先先介绍下我们接下来需要用到的几个字段的含义</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/1020b110951d44f24b2259140f80e2d727a3ebcf70964ef8e2a9120e64385923.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>这是一条普通消息,它没有@所有人所以它的<code>mention_everyone</code>是<code>false</code>,它也没@某个用户,所以<code>mentions</code>是一个空数组,接着我们再看看@指定用户的消息返回体和@所有人的消息返回体</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/ec7ea96e8f770dd586973145b9511fcf95a5a907a21836983df7992114ea342e.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>这条@指定用户的消息大家可以发现,<code>mentions</code>数组里有一个用户对象,这个就是我们@的那个用户的信息,同时消息的内容<code>content</code>里我们@的用户那部分的文字转换成了&lt;@!用户id&gt;这样一个格式</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/59372e95ac49a28d9a173475fc8938e6bc48024c8b0ddf623c5b17e0b3fdf116.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>最后这条消息我们可以看到字段<code>mention_everyone</code>的值变成了<code>true</code>,这就代表这条消息是一个@所有人的消息</p><p>经过上面的分析,现在大家应该对区分消息类型有了一定了解,接下来我们就可以来实现我们监控脚本</p><pre data-type="codeBlock" text="const axios = require(&quot;axios&quot;);

const proxyHost = &apos;127.0.0.1&apos; // 代理ip
const proxyPort = &apos;7890&apos; // 代理端口号
const authorization = &apos;&apos; // 账号的authorization
const channel_id = &apos;&apos; //频道id
let monitorTime = new Date().getTime() // 监控时间,用于避免重新识别老消息
const monitor = () =&gt; {
    let header = {
        &quot;Authorization&quot;: authorization,
        &quot;Content-Type&quot;: &quot;application/json&quot;,
        &quot;User-Agent&quot;: &quot;Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.61 Safari/537.36&quot;
    }
    axios({
        method: &apos;GET&apos;,
        url: `https://discord.com/api/v9/channels/${channel_id}/messages?limit=50`,
        headers: header,
        proxy: (proxyHost &amp;&amp; proxyPort)?{
            host: proxyHost,
            port: proxyPort
        }: null,
    }).then(res =&gt; {
        // 对聊天消息进行分析
        messageParse(res.data)
        startTime = new Date().getTime()
    }).catch(e =&gt; {
        console.log(e.message)
    })
}

setInterval(function () {// 监听器,每60s执行一次
    monitor()
},60*1000);
"><code>const axios <span class="hljs-operator">=</span> <span class="hljs-built_in">require</span>(<span class="hljs-string">"axios"</span>);

const proxyHost <span class="hljs-operator">=</span> <span class="hljs-string">'127.0.0.1'</span> <span class="hljs-comment">// 代理ip</span>
const proxyPort <span class="hljs-operator">=</span> <span class="hljs-string">'7890'</span> <span class="hljs-comment">// 代理端口号</span>
const authorization <span class="hljs-operator">=</span> <span class="hljs-string">''</span> <span class="hljs-comment">// 账号的authorization</span>
const channel_id <span class="hljs-operator">=</span> <span class="hljs-string">''</span> <span class="hljs-comment">//频道id</span>
let monitorTime <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> Date().getTime() <span class="hljs-comment">// 监控时间,用于避免重新识别老消息</span>
const monitor <span class="hljs-operator">=</span> () <span class="hljs-operator">=</span><span class="hljs-operator">></span> {
    let header <span class="hljs-operator">=</span> {
        <span class="hljs-string">"Authorization"</span>: authorization,
        <span class="hljs-string">"Content-Type"</span>: <span class="hljs-string">"application/json"</span>,
        <span class="hljs-string">"User-Agent"</span>: <span class="hljs-string">"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.61 Safari/537.36"</span>
    }
    axios({
        method: <span class="hljs-string">'GET'</span>,
        url: `https:<span class="hljs-comment">//discord.com/api/v9/channels/${channel_id}/messages?limit=50`,</span>
        headers: header,
        proxy: (proxyHost <span class="hljs-operator">&#x26;</span><span class="hljs-operator">&#x26;</span> proxyPort)?{
            host: proxyHost,
            port: proxyPort
        }: null,
    }).then(res <span class="hljs-operator">=</span><span class="hljs-operator">></span> {
        <span class="hljs-comment">// 对聊天消息进行分析</span>
        messageParse(res.data)
        startTime <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> Date().getTime()
    }).catch(e <span class="hljs-operator">=</span><span class="hljs-operator">></span> {
        console.log(e.message)
    })
}

setInterval(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{<span class="hljs-comment">// 监听器,每60s执行一次</span>
    monitor()
},<span class="hljs-number">60</span><span class="hljs-operator">*</span><span class="hljs-number">1000</span>);
</code></pre><p>首先还是使用axios对messages接口进行调用,通过构建一个定时器来进行监听,当我们拿到聊天的数据也就是上面的<code>res.data</code>,我们把数据传给我们的分析函数<code>messageParse</code></p><p>我这里对消息进行了下面几个识别</p><ul><li><p>识别@全员和@自己</p></li><li><p>识别管理发言+发言内容包含关键字</p></li><li><p>仅识别发言内容包含关键字</p></li><li><p>仅识别管理发言</p></li></ul><pre data-type="codeBlock" text="// 管理员用户的id
const mods = [
    &apos;933625356789887006&apos;
]
// 关键字
const keywords = [
    &apos;停止说话&apos;,&apos;禁止发言&apos;,&apos;123木头人&apos;
]

/**
 * 判断消息是否含关键字
 */
const isIncludeKeywords = (message) =&gt; {
    let flag = false
    keywords.forEach(keyword =&gt; {
        if(message.includes(keyword)){// 含关键字的消息
            flag = true
        }
    })
    return flag
}

// 消息信息解析
const messageParse = (data) =&gt; {
    // 优先级 @全员 &gt; @自己 &gt; mod发言+含关键字 &gt; 含关键字 &gt; mod发言
    data.forEach(item =&gt; {
        if(new Date(item.timestamp).getTime() &lt; monitortTime){// 时间筛选,避免重新识别老消息
            return
        }
        if(item.mention_everyone){// @全体成员的消息
            console.log(`监听到一条@全员的消息:`)
            console.log(&apos;-------------------&apos;)
            console.log(`消息: ${item.content}`)
            console.log(&apos;-------------------&apos;)
            // 执行你自己的应对策略
        }else if(item.content.includes(account_id)){// @自己的消息
            console.log(`监听到一条@你的消息:`)
            console.log(&apos;-------------------&apos;)
            console.log(`消息: ${item.content}`)
            console.log(&apos;-------------------&apos;)
            // 执行你自己的应对策略
        }else if(mods.includes(item.author.id) &amp;&amp; isIncludeKeywords(item.content)){// mod发言+含关键字
            console.log(`监听到一条mod发言+含关键字的消息:`)
            console.log(&apos;-------------------&apos;)
            console.log(`消息: ${item.content}`)
            console.log(&apos;-------------------&apos;)
            // 执行你自己的应对策略
        }else if(isIncludeKeywords(item.content)){
            console.log(`监听到含关键字的消息:`)
            console.log(&apos;-------------------&apos;)
            console.log(`消息: ${item.content}`)
            console.log(&apos;-------------------&apos;)
            // 执行你自己的应对策略
        }else if(mods.includes(item.author.id)){
            console.log(`监听到一条mod发言的消息:`)
            console.log(&apos;-------------------&apos;)
            console.log(`消息: ${item.content}`)
            console.log(&apos;-------------------&apos;)
            // 执行你自己的应对策略
        }
    })

}
"><code><span class="hljs-comment">// 管理员用户的id</span>
const mods <span class="hljs-operator">=</span> [
    <span class="hljs-string">'933625356789887006'</span>
]
<span class="hljs-comment">// 关键字</span>
const keywords <span class="hljs-operator">=</span> [
    <span class="hljs-string">'停止说话'</span>,<span class="hljs-string">'禁止发言'</span>,<span class="hljs-string">'123木头人'</span>
]

<span class="hljs-comment">/**
 * 判断消息是否含关键字
 */</span>
const isIncludeKeywords <span class="hljs-operator">=</span> (message) <span class="hljs-operator">=</span><span class="hljs-operator">></span> {
    let flag <span class="hljs-operator">=</span> <span class="hljs-literal">false</span>
    keywords.forEach(keyword <span class="hljs-operator">=</span><span class="hljs-operator">></span> {
        <span class="hljs-keyword">if</span>(message.includes(keyword)){<span class="hljs-comment">// 含关键字的消息</span>
            flag <span class="hljs-operator">=</span> <span class="hljs-literal">true</span>
        }
    })
    <span class="hljs-keyword">return</span> flag
}

<span class="hljs-comment">// 消息信息解析</span>
const messageParse <span class="hljs-operator">=</span> (data) <span class="hljs-operator">=</span><span class="hljs-operator">></span> {
    <span class="hljs-comment">// 优先级 @全员 > @自己 > mod发言+含关键字 > 含关键字 > mod发言</span>
    data.forEach(item <span class="hljs-operator">=</span><span class="hljs-operator">></span> {
        <span class="hljs-keyword">if</span>(<span class="hljs-keyword">new</span> Date(item.timestamp).getTime() <span class="hljs-operator">&#x3C;</span> monitortTime){<span class="hljs-comment">// 时间筛选,避免重新识别老消息</span>
            <span class="hljs-keyword">return</span>
        }
        <span class="hljs-keyword">if</span>(item.mention_everyone){<span class="hljs-comment">// @全体成员的消息</span>
            console.log(`监听到一条@全员的消息:`)
            console.log(<span class="hljs-string">'-------------------'</span>)
            console.log(`消息: ${item.content}`)
            console.log(<span class="hljs-string">'-------------------'</span>)
            <span class="hljs-comment">// 执行你自己的应对策略</span>
        }<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>(item.content.includes(account_id)){<span class="hljs-comment">// @自己的消息</span>
            console.log(`监听到一条@你的消息:`)
            console.log(<span class="hljs-string">'-------------------'</span>)
            console.log(`消息: ${item.content}`)
            console.log(<span class="hljs-string">'-------------------'</span>)
            <span class="hljs-comment">// 执行你自己的应对策略</span>
        }<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>(mods.includes(item.author.id) <span class="hljs-operator">&#x26;</span><span class="hljs-operator">&#x26;</span> isIncludeKeywords(item.content)){<span class="hljs-comment">// mod发言+含关键字</span>
            console.log(`监听到一条mod发言<span class="hljs-operator">+</span>含关键字的消息:`)
            console.log(<span class="hljs-string">'-------------------'</span>)
            console.log(`消息: ${item.content}`)
            console.log(<span class="hljs-string">'-------------------'</span>)
            <span class="hljs-comment">// 执行你自己的应对策略</span>
        }<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>(isIncludeKeywords(item.content)){
            console.log(`监听到含关键字的消息:`)
            console.log(<span class="hljs-string">'-------------------'</span>)
            console.log(`消息: ${item.content}`)
            console.log(<span class="hljs-string">'-------------------'</span>)
            <span class="hljs-comment">// 执行你自己的应对策略</span>
        }<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>(mods.includes(item.author.id)){
            console.log(`监听到一条mod发言的消息:`)
            console.log(<span class="hljs-string">'-------------------'</span>)
            console.log(`消息: ${item.content}`)
            console.log(<span class="hljs-string">'-------------------'</span>)
            <span class="hljs-comment">// 执行你自己的应对策略</span>
        }
    })

}
</code></pre><p>可以看到我的消息处理中,首先对消息时间进行了筛选,我们只处理指定时间后的消息,<code>monitortTime</code>的值会随着每次请求结束而更新</p><p>然后我按照我的优先级进行消息的判断,如果符合判断条件就会执行你自己设置的应对策略,如:</p><ul><li><p>停止运行你的水群脚本</p></li><li><p>对接你的话术库进行自动回复又或者接入ai回复进行自动回复</p></li><li><p>接入你的消息推送,把消息推送到微信或者邮件,让你第一时间知道,然后亲自来进行处理</p></li></ul><p>你也可以针对不同情况的紧急程度进行分级应对,这些将由你自己来决定了,这篇教程就到这了,完整代码稍后会上传到github,将按照class1 class2分支来区分</p><blockquote><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/Tian508/discord-bot/tree/class2">课程2代码地址</a></p></blockquote><p>来自DFarm Club</p><p>-----------------------------------------分割线-----------------------------------------</p><p>答应大家的GUI版本已经上传github了,代码在main分支,打包好的exe放在Releases</p><p>功能基本上就是前两篇课程内介绍过的内容,不会使用可以参考课程内的代码实现</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/97366a6899eee75382e53d75e6aebfe6604d1d7d87e0fa753e8c18e0eca7ce09.png" alt="水群" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">水群</figcaption></figure><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/219d4ce77efc7260ac49001d2b8ff2817ee8bba6d91b606a9d5779a67c12efe3.png" alt="互聊" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">互聊</figcaption></figure><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/f2b1a0dd3184b6ddf95d45ebc5885dae2edbec85514aefe8c8ee740e6773097b.png" alt="监听" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">监听</figcaption></figure>]]></content:encoded>
            <author>0x-9@newsletter.paragraph.com (0x韭菜)</author>
        </item>
        <item>
            <title><![CDATA[discord水群bot教程(1)  双号互聊 ]]></title>
            <link>https://paragraph.com/@0x-9/discord-bot-1</link>
            <guid>fU5dBogiTNnyQbbYpXxW</guid>
            <pubDate>Fri, 11 Feb 2022 13:40:09 GMT</pubDate>
            <description><![CDATA[韭菜的第一篇文章，萌新写手，多多担待前言本篇文章主要是实现一个discord自动水群机器人 计划功能大概就是 话术抓取、双号互聊、关键词检测、mod发言检测等一些市面上discord bot比较常见的一些功能，最后会提供一个可以开箱即用的带GUI的成品程序(大概)，教程的代码会同步更新在Github上 教程有些许技术门槛，主要涉及node.js和一些依赖库的使用，基本上有入门的基础就可以看懂了，不会的小伙伴可以自学下node.js或者等后续成品exe教程开始第一篇主要是实现话术抓取以及双号互聊这两个功能,先来实现话术抓取 首先准备好node环境，在终端内输入以下命令 mkdir discord-bot cd discord-bot npm init-y npm install axios 新建一个getChatRecord.js，话术抓取需要使用http请求获取频道内的聊天记录然后将内容保存到本地，所以我们需要在js内引入http模块 axios 和 文件系统模块fsconst axios = require("axios"); const fs = require('fs');...]]></description>
            <content:encoded><![CDATA[<p>韭菜的第一篇文章，萌新写手，多多担待</p><h2 id="h-" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">前言</h2><p>本篇文章主要是实现一个discord自动水群机器人</p><p>计划功能大概就是 话术抓取、双号互聊、关键词检测、mod发言检测等一些市面上discord bot比较常见的一些功能，最后会提供一个可以开箱即用的带GUI的成品程序(大概)，教程的代码会同步更新在Github上</p><p>教程有些许技术门槛，主要涉及node.js和一些依赖库的使用，基本上有入门的基础就可以看懂了，不会的小伙伴可以自学下node.js或者等后续成品exe</p><h2 id="h-" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">教程开始</h2><p>第一篇主要是实现话术抓取以及双号互聊这两个功能,先来实现话术抓取</p><p>首先准备好node环境，在终端内输入以下命令</p><p><code>mkdir discord-bot</code></p><p><code>cd discord-bot</code></p><p><code>npm init-y</code></p><p><code>npm install axios</code></p><p>新建一个getChatRecord.js，话术抓取需要使用http请求获取频道内的聊天记录然后将内容保存到本地，所以我们需要在js内引入http模块 axios 和 文件系统模块fs</p><pre data-type="codeBlock" text="const axios = require(&quot;axios&quot;);
const fs = require(&apos;fs&apos;);
"><code>const <span class="hljs-attr">axios</span> = require(<span class="hljs-string">"axios"</span>)<span class="hljs-comment">;</span>
const <span class="hljs-attr">fs</span> = require(<span class="hljs-string">'fs'</span>)<span class="hljs-comment">;</span>
</code></pre><p>要使用http获取聊天记录我们需要知道具体请求的url</p><p>在浏览器内按F12打开控制台，找到network栏，然后点击clear图标清除历史请求记录</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/36a6463659d38d022e31ebdcc2daa584cddf738abafab41633288446039634fa.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>接着我们在discord进入想要抓取聊天记录的频道，然后在控制台找到一条name为message的请求，点击请求后可以查看Preview可以看到请求返回的内容就是频道内的聊天记录</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/f76f31068cd409e9a92e9f2c88d31f5c4fec3d96d7a6838b4b4323625f87e1ce.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>ok，那么这条请求就是获取聊天记录的请求，我们点击Headers可以看到这个请求是一个get请求，参数也在请求url内，这一串数字就是频道id，后面limit就是这次查询获取的数量，Request Headers中的authorization就是你的用户token，知道url，参数，鉴权我们就可以自己构建请求了</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/66b292e54d56a97541c302b235d1d900a37afa5fa62efa882165801f359cb9b3.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>具体实现</p><pre data-type="codeBlock" text="const axios = require(&quot;axios&quot;);
const fs = require(&apos;fs&apos;);
const authorization = ‘你的authorization’

const proxyHost = &apos;127.0.0.1&apos; // 代理ip
const proxyPort = &apos;7890&apos; // 代理端口号

/**
 * 爬取指定频道聊天记录（爬取话术）
 * @param {*} channel_id 频道id
 * @param {*} amount 抓取数量（50的倍数）
 */
 const getChatRecord = async (channel_id,amount=50,) =&gt; {
    return new Promise(async (resolve, reject) =&gt; {
        let recordList = []
        let beforeId = &apos;&apos;
        const getChatRecordLimit = () =&gt; {
            let beforeQuery = beforeId?`before=${beforeId}&amp;`:&apos;&apos;
            let header = {
                &quot;Authorization&quot;: authorization,
                &quot;Content-Type&quot;: &quot;application/json&quot;,
                &quot;User-Agent&quot;: &quot;Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.61 Safari/537.36&quot;
            }
            axios({
                method: &apos;GET&apos;,
                url: `https://discord.com/api/v9/channels/${channel_id}/messages?${beforeQuery}limit=50`,
                headers: header,
                proxy: (proxyHost &amp;&amp; proxyPort)?{
                    host: proxyHost,
                    port: proxyPort
                }: null,
            }).then(res =&gt; {
                let data = res.data
                data.forEach(v =&gt; {
                    recordList.push(v.content)
                })
                if(recordList.length&lt;amount){
                    beforeId = data[data.length-1].id
                    getChatRecordLimit()
                }else{
                    recordList.forEach(v =&gt; {
                        writeOutput(`${v}\n`);
                    })
                    console.log(&apos;话术抓取成功&apos;)
                    resolve()
                }
            }).catch(e =&gt; {
                reject(e)
                console.log(e.message)
            })
        }
        getChatRecordLimit()
    })
}

function writeOutput(data) {
    fs.appendFile(&apos;话术.txt&apos;, data, function (err) {
        if (err) throw err;
    });
}

getChatRecord(&apos;频道id&apos;,数量)
"><code>const axios <span class="hljs-operator">=</span> <span class="hljs-built_in">require</span>(<span class="hljs-string">"axios"</span>);
const fs <span class="hljs-operator">=</span> <span class="hljs-built_in">require</span>(<span class="hljs-string">'fs'</span>);
const authorization <span class="hljs-operator">=</span> ‘你的authorization’

const proxyHost <span class="hljs-operator">=</span> <span class="hljs-string">'127.0.0.1'</span> <span class="hljs-comment">// 代理ip</span>
const proxyPort <span class="hljs-operator">=</span> <span class="hljs-string">'7890'</span> <span class="hljs-comment">// 代理端口号</span>

<span class="hljs-comment">/**
 * 爬取指定频道聊天记录（爬取话术）
 * @param {*} channel_id 频道id
 * @param {*} amount 抓取数量（50的倍数）
 */</span>
 const getChatRecord <span class="hljs-operator">=</span> async (channel_id,amount<span class="hljs-operator">=</span><span class="hljs-number">50</span>,) <span class="hljs-operator">=</span><span class="hljs-operator">></span> {
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> Promise(async (resolve, reject) <span class="hljs-operator">=</span><span class="hljs-operator">></span> {
        let recordList <span class="hljs-operator">=</span> []
        let beforeId <span class="hljs-operator">=</span> <span class="hljs-string">''</span>
        const getChatRecordLimit <span class="hljs-operator">=</span> () <span class="hljs-operator">=</span><span class="hljs-operator">></span> {
            let beforeQuery <span class="hljs-operator">=</span> beforeId?`before<span class="hljs-operator">=</span>${beforeId}<span class="hljs-operator">&#x26;</span>`:<span class="hljs-string">''</span>
            let header <span class="hljs-operator">=</span> {
                <span class="hljs-string">"Authorization"</span>: authorization,
                <span class="hljs-string">"Content-Type"</span>: <span class="hljs-string">"application/json"</span>,
                <span class="hljs-string">"User-Agent"</span>: <span class="hljs-string">"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.61 Safari/537.36"</span>
            }
            axios({
                method: <span class="hljs-string">'GET'</span>,
                url: `https:<span class="hljs-comment">//discord.com/api/v9/channels/${channel_id}/messages?${beforeQuery}limit=50`,</span>
                headers: header,
                proxy: (proxyHost <span class="hljs-operator">&#x26;</span><span class="hljs-operator">&#x26;</span> proxyPort)?{
                    host: proxyHost,
                    port: proxyPort
                }: null,
            }).then(res <span class="hljs-operator">=</span><span class="hljs-operator">></span> {
                let data <span class="hljs-operator">=</span> res.data
                data.forEach(v <span class="hljs-operator">=</span><span class="hljs-operator">></span> {
                    recordList.<span class="hljs-built_in">push</span>(v.content)
                })
                <span class="hljs-keyword">if</span>(recordList.<span class="hljs-built_in">length</span>&#x3C;amount){
                    beforeId <span class="hljs-operator">=</span> data[data.<span class="hljs-built_in">length</span>-<span class="hljs-number">1</span>].id
                    getChatRecordLimit()
                }<span class="hljs-keyword">else</span>{
                    recordList.forEach(v <span class="hljs-operator">=</span><span class="hljs-operator">></span> {
                        writeOutput(`${v}\n`);
                    })
                    console.log(<span class="hljs-string">'话术抓取成功'</span>)
                    resolve()
                }
            }).catch(e <span class="hljs-operator">=</span><span class="hljs-operator">></span> {
                reject(e)
                console.log(e.message)
            })
        }
        getChatRecordLimit()
    })
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">writeOutput</span>(<span class="hljs-params">data</span>) </span>{
    fs.appendFile(<span class="hljs-string">'话术.txt'</span>, data, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">err</span>) </span>{
        <span class="hljs-keyword">if</span> (err) <span class="hljs-keyword">throw</span> err;
    });
}

getChatRecord(<span class="hljs-string">'频道id'</span>,数量)
</code></pre><p>因为discord默认请求查询数量是50，所以需要大量的聊天记录的话我就不篡改他的请求数量了，而是通过循环调用来实现查询指定数量的聊天记录</p><p>writeOutput函数是利用fs模块将获取到的聊天内容保存到当前目录的话术.txt内，这样我们的话术抓取功能就实现好了，我们再终端输入node getChatRecord.js就可以运行了</p><p>话术抓取完毕后我们继续看看互聊的实现</p><p>既然是互聊那肯定需要发送普通消息和发送回复消息，我们打开F12控制台，在频道内输入文字后还是找到一条name为messages的请求</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/c22ffa15c81c882372111ce159f69d41a461d084e02cf4dce7166adca1720963.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>这次我们可以看到是一个post请求，url内只包含了频道id，那么我们切换到Payload看下传参</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/ad81057d744d530ce53b7b5868b736b87aa3fc1735acd61acc601057d4940cc0.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>可以看到参数有3个，content就是你发送的内容，nonce是一个随机数，tts默认都是false我们可以不用管它</p><p>接着我们在频道内回复一条消息，然后继续查找控制台内的messages请求</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/9303f53ea1880e0c8601f379c4e8464eb3d14bf363676850716d474b0b98bcc9.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>这次请求参数多了一个message_reference的对象，这个对象内有三个参数，分别是频道id，群id，回复的那条消息的id，知道这些参数后我们就可以构建我们的聊天函数</p><p>首先准备两个discord账号，获取好账号的authorization，以及需要聊天的群id和频道id，新建一个txt_list.txt的文本文件，把之前抓取到的话术整理好放入其中，一行就是一条消息，比如第一行由账号1发送，第二天就是由账号2发送，第三条是账号1发送这样循环</p><p>我们新建一个chat.js 下面是具体代码实现</p><pre data-type="codeBlock" text="const fs = require(&apos;fs&apos;);
const axios = require(&quot;axios&quot;);

const proxyHost = &apos;127.0.0.1&apos; // 代理ip
const proxyPort = &apos;7890&apos; // 代理端口号

const guild_id = &apos;&apos; // 群id
const channel_id = &apos;&apos; // 频道id
let message_id = &apos;&apos; // 回复的消息id
const account1 = &apos;&apos; // 账号1的authorization
const account2 = &apos;&apos; // 账号2的authorization

const time = 10 // 聊天间隔 单位:秒
const responeAt = 0.5 // 1 开启对话@ 0关闭对话@ 0.1-0.9 概率@
let counter = 0 // 计数器

// 从txt读取话术
const text_list = fs.readFileSync(&apos;text_list.txt&apos;).toString().split(&apos;\n&apos;);


/**
 * 开聊
 */
const chat_star = () =&gt; {
    // 用计数器判断当前使用账号1还是账号2发送消息
    let authorization = counter % 2 === 0 ? account1 : account2
    
    let header = {
        &quot;Authorization&quot;: authorization,
        &quot;Content-Type&quot;: &quot;application/json&quot;,
        &quot;User-Agent&quot;: &quot;Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.61 Safari/537.36&quot;
    }
    let msg = {
        &quot;content&quot;: text_list[counter],
        &quot;nonce&quot;: `94158662701${Math.ceil(Math.random()*1000)}213056`,
        &quot;tts&quot;: false
    }
    if(isResponeAt() &amp;&amp; !!message_id){
        msg.message_reference = {
            channel_id: channel_id,
            guild_id: guild_id,
            message_id: message_id
        }
    }
    axios({
        method: &apos;POST&apos;,
        url: `https://discord.com/api/v9/channels/${channel_id}/messages`,
        headers: header,
        proxy: (proxyHost &amp;&amp; proxyPort)?{
            host: proxyHost,
            port: proxyPort
        }: null,
        data: msg
    }).then(res =&gt; {
        let data = res.data
        message_id = data.id
        console.log(`[${data.author.username}]发送成功: ${data.content}`)
        counter++
    })
}

/**
 * 是否为回复消息
 */
const isResponeAt = () =&gt; {
    if(responeAt === 1){
        return true
    }else if(responeAt === 0){
        return false
    }else{
        return Math.round(Math.random()*10) &lt; responeAt*10
    }
}

const sleep = (ms) =&gt; {
    return new Promise((resolve) =&gt; setTimeout(resolve, ms));
};

const main = async () =&gt; {
    while (counter&lt;text_list.length) {
        chat_star()
        await sleep(time*1000)
    }
}
main()
"><code>const fs <span class="hljs-operator">=</span> <span class="hljs-built_in">require</span>(<span class="hljs-string">'fs'</span>);
const axios <span class="hljs-operator">=</span> <span class="hljs-built_in">require</span>(<span class="hljs-string">"axios"</span>);

const proxyHost <span class="hljs-operator">=</span> <span class="hljs-string">'127.0.0.1'</span> <span class="hljs-comment">// 代理ip</span>
const proxyPort <span class="hljs-operator">=</span> <span class="hljs-string">'7890'</span> <span class="hljs-comment">// 代理端口号</span>

const guild_id <span class="hljs-operator">=</span> <span class="hljs-string">''</span> <span class="hljs-comment">// 群id</span>
const channel_id <span class="hljs-operator">=</span> <span class="hljs-string">''</span> <span class="hljs-comment">// 频道id</span>
let message_id <span class="hljs-operator">=</span> <span class="hljs-string">''</span> <span class="hljs-comment">// 回复的消息id</span>
const account1 <span class="hljs-operator">=</span> <span class="hljs-string">''</span> <span class="hljs-comment">// 账号1的authorization</span>
const account2 <span class="hljs-operator">=</span> <span class="hljs-string">''</span> <span class="hljs-comment">// 账号2的authorization</span>

const time <span class="hljs-operator">=</span> <span class="hljs-number">10</span> <span class="hljs-comment">// 聊天间隔 单位:秒</span>
const responeAt <span class="hljs-operator">=</span> <span class="hljs-number">0</span><span class="hljs-number">.5</span> <span class="hljs-comment">// 1 开启对话@ 0关闭对话@ 0.1-0.9 概率@</span>
let counter <span class="hljs-operator">=</span> <span class="hljs-number">0</span> <span class="hljs-comment">// 计数器</span>

<span class="hljs-comment">// 从txt读取话术</span>
const text_list <span class="hljs-operator">=</span> fs.readFileSync(<span class="hljs-string">'text_list.txt'</span>).toString().split(<span class="hljs-string">'\n'</span>);


<span class="hljs-comment">/**
 * 开聊
 */</span>
const chat_star <span class="hljs-operator">=</span> () <span class="hljs-operator">=</span><span class="hljs-operator">></span> {
    <span class="hljs-comment">// 用计数器判断当前使用账号1还是账号2发送消息</span>
    let authorization <span class="hljs-operator">=</span> counter <span class="hljs-operator">%</span> <span class="hljs-number">2</span> <span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-number">0</span> ? account1 : account2
    
    let header <span class="hljs-operator">=</span> {
        <span class="hljs-string">"Authorization"</span>: authorization,
        <span class="hljs-string">"Content-Type"</span>: <span class="hljs-string">"application/json"</span>,
        <span class="hljs-string">"User-Agent"</span>: <span class="hljs-string">"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.61 Safari/537.36"</span>
    }
    let <span class="hljs-built_in">msg</span> <span class="hljs-operator">=</span> {
        <span class="hljs-string">"content"</span>: text_list[counter],
        <span class="hljs-string">"nonce"</span>: `94158662701${Math.ceil(Math.random()<span class="hljs-operator">*</span><span class="hljs-number">1000</span>)}<span class="hljs-number">213056</span>`,
        <span class="hljs-string">"tts"</span>: <span class="hljs-literal">false</span>
    }
    <span class="hljs-keyword">if</span>(isResponeAt() <span class="hljs-operator">&#x26;</span><span class="hljs-operator">&#x26;</span> <span class="hljs-operator">!</span><span class="hljs-operator">!</span>message_id){
        <span class="hljs-built_in">msg</span>.message_reference <span class="hljs-operator">=</span> {
            channel_id: channel_id,
            guild_id: guild_id,
            message_id: message_id
        }
    }
    axios({
        method: <span class="hljs-string">'POST'</span>,
        url: `https:<span class="hljs-comment">//discord.com/api/v9/channels/${channel_id}/messages`,</span>
        headers: header,
        proxy: (proxyHost <span class="hljs-operator">&#x26;</span><span class="hljs-operator">&#x26;</span> proxyPort)?{
            host: proxyHost,
            port: proxyPort
        }: null,
        data: <span class="hljs-built_in">msg</span>
    }).then(res <span class="hljs-operator">=</span><span class="hljs-operator">></span> {
        let data <span class="hljs-operator">=</span> res.data
        message_id <span class="hljs-operator">=</span> data.id
        console.log(`[${data.author.username}]发送成功: ${data.content}`)
        counter<span class="hljs-operator">+</span><span class="hljs-operator">+</span>
    })
}

<span class="hljs-comment">/**
 * 是否为回复消息
 */</span>
const isResponeAt <span class="hljs-operator">=</span> () <span class="hljs-operator">=</span><span class="hljs-operator">></span> {
    <span class="hljs-keyword">if</span>(responeAt <span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-number">1</span>){
        <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>
    }<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>(responeAt <span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span> <span class="hljs-number">0</span>){
        <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>
    }<span class="hljs-keyword">else</span>{
        <span class="hljs-keyword">return</span> Math.round(Math.random()<span class="hljs-operator">*</span><span class="hljs-number">10</span>) <span class="hljs-operator">&#x3C;</span> responeAt<span class="hljs-operator">*</span><span class="hljs-number">10</span>
    }
}

const sleep <span class="hljs-operator">=</span> (ms) <span class="hljs-operator">=</span><span class="hljs-operator">></span> {
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> Promise((resolve) <span class="hljs-operator">=</span><span class="hljs-operator">></span> setTimeout(resolve, ms));
};

const main <span class="hljs-operator">=</span> async () <span class="hljs-operator">=</span><span class="hljs-operator">></span> {
    <span class="hljs-keyword">while</span> (counter<span class="hljs-operator">&#x3C;</span>text_list.<span class="hljs-built_in">length</span>) {
        chat_star()
        await sleep(time<span class="hljs-operator">*</span><span class="hljs-number">1000</span>)
    }
}
main()
</code></pre><p>为了避免全程相互回复聊天别人发现异常，封装了一个判断当前是否为回复消息的函数 isResponseAt，通过配置参数responseAt来控制(1: 全程回复聊天 0：全程普通聊天 0.1-0.9：概率是回复消息，比如0.5就是每次发送消息都是二分之一的可能是回复消息)</p><p>其他就没啥了，功能其实还是挺简单的，我们在终端输入node chat.js就可以运行了，目前代码是判断text_list内的话术聊完就停止了，如果需要无限循环聊下去或者聊够指定条就停可以自己稍微改改就行,下面是设置0.5概率的运行效果</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/4ce46b9e3f0ca9c2808c159e415c8e2f4ef88f58777acbf09158efde69fab868.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>第一篇就先写到这,项目代码稍后会打包到github</p><blockquote><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/Tian508/discord-bot/tree/class1">课程1地址</a></p></blockquote><p>github上的代码 运行所需配置项统一放到.env文件里了,下载后把项目内的.env.example改为.env,在其中配置即可</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/444f981b7593cc98289eaed946e58f2f6a7f9f4bc32d10b5b2050c21f513d715.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>来自DFarm Club</p>]]></content:encoded>
            <author>0x-9@newsletter.paragraph.com (0x韭菜)</author>
        </item>
    </channel>
</rss>