2019 前端自嗨 coolq 篇 -- 技術文章推送

lastSeries發表於2019-03-18

背景 (Background)

在我看來,再牛逼的技術不落到實處永遠是紙上談兵,秉承著 學以致用 的校訓。一個字 “幹” 就完事了 ?

2019 年了,如何將前端知識學以致用呢 ?️,前段時間 QQ 群裡大佬們突然玩起了 coolq 機器人,用機器人進行 線上陪聊、線上點歌 線上搜圖的功能 乃至。。。(你能想到的一切 ?)

突然腦子裡閃過一道光 ⚡️,臥槽牛逼呀,我也要玩

coolq what fuck

說實話,在 coolq 的官網看了半天,愣是不知道它是個什麼玩意!!!難道你都不介紹一下自己是幹哈的嘛,差評

以下是 百度百科coolq 的定義

酷 Q,是一款基於 Smart 協議功能強大的機器人軟體,它可以通過安裝外掛實現自動稽核他人申請入群、自動踢人、自動管理群等自動化操作,還能實現自動群聊、自動聊天,起到活躍群組氣氛的重要作用,節省您的寶貴時間。

突然發現 coolq 好牛逼,講道理 我只是使用了 cooql 訊息推送的功能 ?

技術文章來源

如果讓你來搞,你會怎麼辦呢?你可能會想到 爬蟲,可以爬頁面,也可以爬介面。。。我這裡選用的是 rss。你在說什麼? rss 什麼鬼,我怎麼沒聽說過,難道是一門新的技術?NO RSS 簡介

問題來了,不是所有的網站都提供 rss 服務,比如說 掘金 ,那麼問題來了,那我怎麼使用呢?在這裡給大家安利一波 RSSHub,它為我這種懶人提供了福利,如果裡面沒有找到你想要的內容,那麼很抱歉只能自己手撕程式碼了

在繼續閱讀之前,你最好能夠 瞭解一點 Mongodb 的相關知識,瞭解一點 Docker 的相關知識。如果你和和我一樣是個菜雞,問題也不是很大

實操 (Practical operation)

1. 安裝 coolq

這裡有一點不得不提,由於 coolq 官網 只提供 windows 版本的,因此 如果想要在 Linux / MacOS 系統上安裝 官方 推薦的是通過 Docker 安裝對應的映象檔案。(2019 年了,如果你還不會 Docker 你就 out 了,有些知識不深可以,但是廣一點是沒有任何毛病的 ?)

如果預設的功能不能滿足你的需求,想要自己開發一些好玩新奇的功能,則需要安裝 開發版

  1. 獲取映象
docker pull coolq/wine-coolq
複製程式碼
  1. 建立資料夾,用於存放 coolq 持久化資料
# 任意路徑均可
mkdir /root/coolq-data
複製程式碼
  1. 執行映象
docker run --name=coolq --rm -p 9000:9000 -v /root/coolq-data:/home/user/coolq coolq/wine-coolq
複製程式碼
  • --name 建立一個容器

  • --rm 這個引數是說容器退出之後隨之將其刪除。預設情況下,為了排障需求,退出的容器不會立即刪除,除非手動 docker rm

  • -p <宿主埠>:<容器埠> -p,是用來對映宿主埠和容器埠,換句話說,就是將容器的對應埠服務公開給外界訪問

  • -v指定掛載一個本地主機的目錄到容器中去

  1. 啟動 coolq

開啟瀏覽器 輸入 localhost:9000

2019 前端自嗨 coolq 篇 -- 技術文章推送

點選 connect 輸入 預設密碼 MAX8char

輸入 QQ 賬號 及 密碼 (推薦註冊小號,以防風險) 登入 coolq

2019 前端自嗨 coolq 篇 -- 技術文章推送

  1. 獲取映象
docker pull richardchien/cqhttp:latest
複製程式碼
  1. 建立資料夾,用於存放 coolq 持久化資料

  2. 執行映象

docker run -ti --rm --name cqhttp -p 9000:9000 -p 5700:5700 -v /root/coolq-data:/home/user/coolq richardchien/cqhttp
複製程式碼
  1. 啟動 coolq

2. 安裝 mongodb

此處省略。。。(相信這一定不會難道小天才的你 ?)

3. 擼程式碼

爬文章

async function crawl(url) {
  try {
    const feed = await parser.parseURL(url);
    const items = feed.items.map(({ title, link, guid = link }) => {
      title = title.trim();
      link = link.trim();
      guid = guid.trim();

      console.log(title, link);
      return { title, link, guid };
    });

    return items;
  } catch (err) {
    console.log(err);
  }
}
複製程式碼

資料庫插入資料

async function insert(db, { title, link, guid }) {
  const collection = db.collection(collectionName);
  // Insert some documents
  try {
    await collection.updateOne(
      {
        guid
      },
      {
        $set: { title, link, guid },
        $setOnInsert: { status: 0 }
      },
      {
        upsert: true
      }
    );
  } catch (err) {
    console.log(err);
  }
}
複製程式碼

資料庫查詢資料

status 0: 未推送 1: 已推送

async function find(db) {
  const collection = db.collection(collectionName);
  // Find some documents
  try {
    return await collection
      .find({
        status: 0
      })
      .toArray();
  } catch (err) {
    console.log(err);
  }
}
複製程式碼

推送訊息

group_id 群號

const request = require('superagent');

async function send(message) {
  return await request
    .post('http://0.0.0.0:5700/send_group_msg')
    .send({ group_id: XXX, message })
    .set('Accept', 'application/json');
}
複製程式碼

資料爬取及儲存程式碼整合

const MongoClient = require('mongodb').MongoClient;
const Parser = require('rss-parser');
const parser = new Parser();

const url = 'mongodb://localhost:27017';
const dbName = 'robot'; // 資料庫名
const collectionName = 'juejin'; // 集合名(表名)
const pullList = ['https://rsshub.app/juejin/category/frontend'];

// 插入
async function insert(db, { title, link, guid }) {
  const collection = db.collection(collectionName);
  // Insert some documents
  try {
    await collection.updateOne(
      {
        guid
      },
      {
        $set: { title, link, guid },
        $setOnInsert: { status: 0 }
      },
      {
        upsert: true
      }
    );
  } catch (err) {
    console.log(err);
  }
}

// 爬蟲
async function crawl(url) {
  try {
    const feed = await parser.parseURL(url);
    const items = feed.items.map(({ title, link, guid = link }) => {
      title = title.trim();
      link = link.trim();
      guid = guid.trim();

      console.log(title, link);
      return { title, link, guid };
    });

    return items;
  } catch (err) {
    console.log(err);
  }
}

(async () => {
  // Create a new MongoClient
  const client = new MongoClient(url);

  try {
    // Use connect method to connect to the Server
    await client.connect();

    console.log('Connected successfully to server');

    const db = client.db(dbName);

    const promises = pullList.map((value) => {
      return (async () => {
        const items = await crawl(value);
        const insertPromises = items.map((item) => {
          return insert(db, item);
        });

        await Promise.all(insertPromises);
      })();
    });

    await Promise.all(promises).then(() => {
      client.close();
    });
  } catch (err) {
    console.log(err.stack);
  }
})();
複製程式碼

資料推送及查詢程式碼整合

為了保障程式碼的執行記得修的修改為自己的 QQ 群號(以下僅以傳送群組訊息為例,具體的也可以是傳送私信,討論組訊息)

const MongoClient = require('mongodb').MongoClient;
const request = require('superagent');

const url = 'mongodb://localhost:27017';
const dbName = 'robot'; // 資料庫名
const collectionName = 'juejin'; // 集合名(表名)

// 查詢
async function find(db) {
  const collection = db.collection(collectionName);
  // Find some documents
  try {
    return await collection
      .find({
        status: 0
      })
      .toArray();
  } catch (err) {
    console.log(err);
  }
}

// 更新
async function update(db, { guid }) {
  const collection = db.collection(collectionName);
  // Update some documents
  try {
    await collection.updateOne(
      {
        guid
      },
      {
        $set: { status: 1 }
      }
    );
  } catch (err) {
    console.log(err);
  }
}

// 推送 群組
async function send(message) {
  return await request
    .post('http://0.0.0.0:5700/send_group_msg')
    .send({ group_id: XXX, message }) // 記得修改喲?
    .set('Accept', 'application/json');
}

(async () => {
  // Create a new MongoClient
  const client = new MongoClient(url);

  try {
    // Use connect method to connect to the Server
    await client.connect();

    console.log('Connected successfully to server');

    const db = client.db(dbName);

    const docs = await find(db);

    console.log(docs);

    let message = '';
    message = docs.reduce((acu, { title, link }, index) => {
      return `${acu}${title} ${link}${index === docs.length - 1 ? '' : '\n'}`;
    }, message);

    const { text } = await send(message);
    const { status, retcode } = JSON.parse(text);
    if (status === 'ok' && retcode === 0) {
      const promises = docs.map((value) => {
        return update(db, value);
      });

      await Promise.all(promises);
    } else {
      console.log(status, retcode);
    }

    client.close();
  } catch (err) {
    console.log(err.stack);
  }
})();
複製程式碼

2019 前端自嗨 coolq 篇 -- 技術文章推送

展望

以上只是對於 coolq 的簡單應用,最近還有一個 餓了麼外賣推送 的想法,就是根據商家的滿減優惠計算出 最優套餐,但是礙於演算法的問題 暫時卡在了這一塊。當然瞭如果你還有什麼其他想法歡迎一起交流

最後,送諸位一句 大膽假設,小心求證,人人都是科學家?,歡迎曬出你的 idea

相關文件 (Related documents)

相關文章