用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 来吐槽我🤮🤮🤮

相关文章
相关标签/搜索