如何用nodejs快速在Matataki發文, 利用node爬蟲來獲取網頁的內容而後轉發到matataki上面html
這裏就本身的blog作一個簡單的example 這是可能須要用的接口文檔⬇️⬇️⬇️ (docsify真香)前端
mkdir matataki-post
npm init -y
touch index.js複製代碼
就像怎麼把大象🐘裝進冰箱同樣 1.... 2... 3... 首先咱們須要在matataki上面註冊一個帳號, 我選擇了郵箱 由於很簡單也很方便 註冊也挺快的, 而後去發佈一篇文章 看看接口是如何調用的node
編輯ios
發佈git
分析Networgithub
編輯: 咱們在編輯文章的時候能夠看出上傳圖片調用接口是 /post/uploadImage, 因而咱們能夠忽略其餘接口調用web
發佈: 發佈的時候, 能夠看出咱們一共調用了兩個核心的接口, 一個是ipfs上傳, 一個是文章上傳npm
思路axios
// 一、獲取內容
// 一、獲取html
// 二、解析dom獲取內容
// 二、發佈文章
// 一、轉存文章封面 由於文章的圖片是外站的 咱們須要轉存到matataki上面才行
// 二、上傳ipfs
// 三、上傳文章複製代碼
由於個人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
# 若是不出意外的話, 數據就能正常返回了 懶得截圖了複製代碼
首先咱們須要一些平臺須要的信息,
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 來區分 development 和 production
"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()複製代碼
調用結果 看起來還不錯🍑
因爲這是一個簡單的example 因此不會弄得太複雜 簡單的爬蟲加上調用接口便可。
由於不太會node 全完本身瞎鼓搗, 若是寫的不對或者很差的地方但願大佬們多多指點 指點
也歡迎加入QQ Group ID:718639024 來吐槽我🤮🤮🤮