用nodejs快速在Matataki發文

如何用nodejs快速在Matataki發文, 利用node爬蟲來獲取網頁的內容而後轉發到matataki上面html

這裏就本身的blog作一個簡單的example 這是可能須要用的接口文檔⬇️⬇️⬇️ (docsify真香)前端

開始

  1. 首先咱們先初始一個項目
mkdir matataki-post
   npm init -y
   touch index.js複製代碼

  1. 理清思路

就像怎麼把大象🐘裝進冰箱同樣 1.... 2... 3... 首先咱們須要在matataki上面註冊一個帳號, 我選擇了郵箱 由於很簡單也很方便 註冊也挺快的, 而後去發佈一篇文章 看看接口是如何調用的node

編輯ios

發佈git

分析Networgithub

編輯: 咱們在編輯文章的時候能夠看出上傳圖片調用接口是 /post/uploadImage, 因而咱們能夠忽略其餘接口調用web

發佈: 發佈的時候, 能夠看出咱們一共調用了兩個核心的接口, 一個是ipfs上傳, 一個是文章上傳npm


思路axios

// 一、獲取內容
       // 一、獲取html
       // 二、解析dom獲取內容
   // 二、發佈文章
       // 一、轉存文章封面 由於文章的圖片是外站的 咱們須要轉存到matataki上面才行
       // 二、上傳ipfs
       // 三、上傳文章複製代碼

  1. 獲取網頁內容並解析dom

由於個人blog是靜態頁面 因此用superagent就能夠抓取到內容了, 若是是客戶端渲染抓去內容可能有問題, 能夠考慮用puppetter作爬蟲, 而後用cheerio來解析dom 回味jq, 請求用axios由於作前端習慣了🍑api

npm i superagent cheerio axios複製代碼

const superagent = require("superagent");
   const cheerio = require("cheerio");
   const axios = require("axios");
   // ...
   // 獲取內容
   const getHtml = async url => {
     try {
       // 根據url獲取內容
       const res = await superagent.get(url);
       return res.text;
     } catch (err) {
       console.error(err);
       return false;
     }
   };
   
   // 拆dom 這塊根據本身頁面自定義
   const getDom = html => {
     if (!html) return false; // 沒html返回
     const $ = cheerio.load(html);
     // 個人標題
     let title = $("#main #posts .post-header .post-title");
     // 描述
     let desc = $("#main #posts .post-body").text();
     // 內容
     let content = $("#main #posts .post-body").html();
     // 文章封面
     let cover = $("#main #posts .post-body img");
       
     // 若是有標題
     let titleRes = title.length >= 1 ? $(title[0]).text() : "";
     // 若是有圖片
     let coverRes = cover.length >= 1 ? $(cover[0]).attr("src") : "";
       
     // 把數據返回出去
     return {
       title: titleRes,
       desc,
       content,
       cover: coverRes
     };
   };複製代碼

這塊仍是挺簡單的233~~~

# 而後咱們能夠調用方法 啓動
   node index
   
   # 若是不出意外的話, 數據就能正常返回了 懶得截圖了複製代碼

  1. 發佈文章

首先咱們須要一些平臺須要的信息,

  • TOKEN, 能夠去控制檯的Cookies裏面尋找, 找到一個keyACCESS_TOKEN 而後複製信息
  • URL 就是須要轉發的文章
  • AUTHOR是你這個帳號在平臺的用戶名
  • PLATFORM 是你這個帳號的類型, 好比我是郵箱帳號 我就是爲 email
const TOKEN = ""; // 身份證實
   const URL = ""; // 須要發的文章
   const AUTHOR = ""; // 用戶名
   const PLATFORM = "email"; // 帳號類型 郵箱帳號複製代碼

而後咱們須要一個config文件 我也這種作法對不對 反正能用🍑 若是你以爲直接寫在index.js要方便 能夠簡化這步

// config.js
   module.exports = {
     // 接口地址
     api: {
       development: "",
       production: "https://api.smartsignature.io"
     },
     // 頁面地址
     webUrl: {
       development: "",
       production: "https://www.matataki.io"
     }
   }
   
   // index.js
   const config = require('./config') // config
   const mode = process.env.NODE_ENV || 'production'; // 模式
   const API = config.api[mode]; // 接口
   const webUrl = config.webUrl[mode]; // 頁面地址複製代碼

增長兩個命令 dev start 來區分 developmentproduction

"scripts": {
       "test": "echo \"Error: no test specified\" && exit 1",
       "dev": "NODE_ENV=development node index",
       "start": "NODE_ENV=production node index"
     },複製代碼

把內容發佈到ipfs

const qs = require("qs");
   // ...
   
   console.log('開始獲取Html...');
   let resHtml = await getHtml(URL);
   console.log('獲取Dom...');
   let resDom = await getDom(resHtml);
   
   let data = {
       title: resDom.title.trim(),
       author: AUTHOR,
       desc: resDom.desc.trim(),
       content: resDom.content.trim()
     };
     data.desc = data.desc.replace(/[\r\n]/g, ""); // 去除回撤換行
     data.content = data.content.replace(/[\r\n]/g, ""); // 去除回撤換行
     let hash = await postIpfs(data);
     if (!hash) return console.log("not hash", hash);
   
   // 發佈到ipfs
   const postIpfs = async ({ title, author, desc, content }) => {
     try {
       if (!TOKEN) throw new Error("沒有token");
       const stringifyData = qs.stringify({
         "data[title]": title,
         "data[author]": author,
         "data[desc]": desc,
         "data[content]": content
       });
       let res = await axios({
         method: "post",
         url: `${API}/post/ipfs`,
         data: stringifyData,
         headers: { "x-access-token": TOKEN }
       });
       // console.log(res.data);
       if (res.status === 200 && res.data.code === 0) {
         return res.data.hash;
       } else return false;
     } catch (error) {
       console.log(error);
       return false;
     }
   };複製代碼

須要的 x-access-token 已經在前面定義過了, 成功請求後會返回hash地址

而後轉存圖片

下載圖片這塊, 按照search到的code沒有修改, 使用request請求圖片, 而且寫入文件, 固然我也發現一個不錯的第三方庫, image-downloader 這個能夠很輕鬆的下載圖片

const FormData = require('form-data');
   const fs = require('fs')
   const request = require('request')
   const path = require('path')
   // ...
   // 圖片轉存
   const downloadImage = async url => {
     if (!url) {
       console.log('沒有url地址')
       return false
     }
     // https://github.com/Kerminate/douban-movies/blob/9119c276b2785b329f62cca684bc6d6459a7c57e/server/tasks/smms.js
   
     // 下載圖片
     const downResources = (url, imgPath) => {
       return new Promise((resolve, reject) => {
         request
           .get(url)
           .pipe(fs.createWriteStream(imgPath))
           .on('finish', () => {
             resolve()
           })
       })
     }
   
     const fileName = 'photo.png'
     const imgPath = path.resolve(__dirname, './photo.jpg')
     try {
       await downResources(url, imgPath)
       // fix Callback must be a function
       const buffer = await fs.readFileSync(imgPath)
       const base64Image = Buffer.from(buffer).toString('base64')
   
       const form = new FormData()
       form.append('smfile', Buffer.from(base64Image, 'base64'), {
         filename: fileName
       })
       let headers = form.getHeaders()
       headers['x-access-token'] = TOKEN
       const res = await axios({
           method: 'POST',
           url: `${API}/post/uploadImage`,
           headers: headers,
           data: form
         })
       // console.log(res.data)
       if (res.status === 200 && res.data.code === 0) {
         return res.data.data.cover
       } else {
         console.log('fail, status: ', res.status)
         return false
       }
     } catch (err) {
       console.log('update error', err)
       return false
     }
   };複製代碼

圖片上傳的核心我是從github裏面search

// ...
   // 這裏的一些轉換我沒有弄明白, 前端通常直接一個file或者一個blob就上去了
   // 在node裏面這個Buffer我尚未理解 但願大佬們看到了能教我一手👋!!!
   const base64Image = Buffer.from(buffer).toString('base64')
   const form = new FormData()
   form.append('smfile', Buffer.from(base64Image, 'base64'), {
     filename: fileName
   })
   // ...複製代碼

上傳成功後會返回一個url地址, 若是是smms之類的圖牀上傳記得多寫一些判斷他會判斷重複的圖片

圖片也有了以後就是上傳文章了

// 發佈文章
   const post = async data => {
     try {
       let res = await axios({
         method: "post",
         url: `${API}/post/publish`,
         data: data,
         headers: { "x-access-token": TOKEN }
       });
       // console.log(data, res.data);
       if (res.status === 200 && res.data.code === 0) {
         return res.data;
       } else {
         console.log('fail', res.data)
         return false;
       }
     } catch (error) {
       console.log('error', error)
       return false;
     }
   };
   
     console.log('發送到Matataki...');
       // 大部分的參數按照我這個默認就行了
     let resPost = await post({
       author: AUTHOR,
       cover,
       fissionFactor: 2000,
       hash: hash,
       platform: PLATFORM,
       publickey: null,
       sign: null,
       msgParams: null,
       signId: null,
       title: resDom.title,
       is_original: 0,
       tags: "",
       cc_license: null,
       commentPayPoint: 1,
       shortContent: ""
     });
     if (resPost) {
       console.log(`發送成功, 您的文章地址: ${webUrl}/p/${resPost.data}`)
     } else {
       console.log('發送失敗!!!')
     }複製代碼

成功後會返回一個文章id而後咱們去訪問 console.log(發送成功, 您的文章地址: ${webUrl}/p/${resPost.data})

到此流程就徹底結束了!!! 概括調用

// 開始
const init = async () => {
  console.log('開始獲取Html...');
  let resHtml = await getHtml(URL);
  console.log('獲取Dom...');
  let resDom = await getDom(resHtml);

  console.log('開始發送到ipfs...');
  let data = {
    title: resDom.title.trim(),
    author: AUTHOR,
    desc: resDom.desc.trim(),
    content: resDom.content.trim()
  };
  data.desc = data.desc.replace(/[\r\n]/g, ""); // 去除回撤換行
  data.content = data.content.replace(/[\r\n]/g, ""); // 去除回撤換行
  let hash = await postIpfs(data);
  if (!hash) return console.log("not hash", hash);

  console.log('轉存下載圖片...');
  let cover = await downloadImage(resDom.cover);
  if (!cover) return console.log('下載圖片失敗')
  console.log('發送到Matataki...');
  let resPost = await post({
    author: AUTHOR,
    cover,
    fissionFactor: 2000,
    hash: hash,
    platform: PLATFORM,
    publickey: null,
    sign: null,
    msgParams: null,
    signId: null,
    title: resDom.title,
    is_original: 0,
    tags: "",
    cc_license: null,
    commentPayPoint: 1,
    shortContent: ""
  });
  if (resPost) {
    console.log(`發送成功, 您的文章地址: ${webUrl}/p/${resPost.data}`)
  } else {
    console.log('發送失敗!!!')
  }
};

init()複製代碼

調用結果 看起來還不錯🍑

預覽地址 1991

倉庫地址

個人Github

因爲這是一個簡單的example 因此不會弄得太複雜 簡單的爬蟲加上調用接口便可。

由於不太會node 全完本身瞎鼓搗, 若是寫的不對或者很差的地方但願大佬們多多指點 指點

也歡迎加入QQ Group ID:718639024 來吐槽我🤮🤮🤮

相關文章
相關標籤/搜索