前言
你想一夜暴富嗎?你想一夜成名嗎?你想開蘭博基尼泡妞嗎?你想拿鈔票點菸嗎?你想成為世界主宰嗎?不,我不想,我只想把我喜歡的教程轉成PDF檔案,放到我的手機或者閱讀器中,什麼?你也想,那來吧,本文將介紹:
- 通過命令列將某網站的內容轉成PDF檔案
- 通過NodeJS爬蟲將某網路教程(例如阮一峰的JavaScript教程和ES6教程等)轉成PDF檔案
- 通過NodeJS或者VScode外掛將Markdown檔案轉成PDF檔案
依賴模組
cheerio是nodejs的抓取頁面模組,為伺服器特別定製的,快速、靈活、實施的jQuery核心實現。適合各種Web爬蟲程式
Request是Node.js中的一個模組,目標是用最可能簡單的方式,在Node.js發起HTTP請求。此外也支援最新的HTTPS協議
一個通過網址將網頁轉成PDF的命令列工具,NodeJS版本要大於8.6.0,如果出現安裝失敗,請翻牆後再安裝
將markdown檔案轉成PDF檔案
命令列匯出PDF檔案
percollate
是一位外國友人做的一個命令列工具,是對puppeteer
做了一層封裝,暴露出常用的API, 我們來看下文件中的例子
一個頁面
percollate pdf --output some.pdf https://example.com
多個頁面
percollate pdf --output some.pdf https://example.com/page1 https://example.com/page2
操作很簡單是不是,哇哦,我們是不是可以美滋滋的將自己喜歡的文章轉成PDF在手機或者電腦上看了,嗯,沒錯是的,不過這也就能玩個文章,如果想拿下整個網站的所有文章就心有餘而力不足了,比如下面的這個
當然,不排除有些比較有毅力的同學,把所有url都拿到,然後拼到命令列中,就像我曾經在工作中見過某同事在專案做完後,一行一行的去刪console.log(),為的是線上版本的控制檯不出現列印的資訊,得說下我們使用webpack打包的,這在打包的時候新增一個配置就能解決的問題,我們幹嘛要費那老鼻子的勁,拒絕假努力,我們來點有效率的。NodeJs爬蟲將整個網站生成PDF檔案
首先我們來瞅一眼阮大神的Javascript教程的網站,地址為 wangdoc.com/javascript/…, 我們能看到網頁右邊為所有章節的導航,開啟Chrome開發者工具,我們能看到
紅框圈出的地方即為每個章節對應的地址,到此,你應該能想到接下里我們要幹什麼了吧,就是通過爬蟲拿到所有的章節地址,文章中的地址為相對路徑,我們再拼上域名,就成了可以訪問的地址了,至於怎麼去抓取所有的文章地址,在這裡略去,比較簡單,相信你看一眼就能懂,原始碼在下面喲。那麼我們想在NodeJs中使用percollate
,該如何操作呢?前面已經說了percollate
是個命令列工具,文件上並沒有告訴我們怎麼在Node環境中怎麼呼叫,難道我們要放棄,直接用puppeteer或者phantomjs去擼嗎?怎麼可能?秉著你是NodeJs的包,肯定能在NodeJs環境跑的宗旨,我把percollate列印出來瞅瞅
這下真的美滋滋了,當然這樣生成的PDF檔案使用的是預設配置,如果你想生成適配你手機或者閱讀器的PDF檔案,就需要新增你的自定義配置了,
percollate.pdf(urlList, {
output: "阮一峰JavaScript教程.pdf",
css: "@page { size: A6 landscape } html { font-size: 18pt } "
});
複製程式碼
關於css屬性的文件,點選檢視。
完整程式碼
新建一個util.js,增加一個用於傳送請求的方法:
const request = require("request");
function parseBody(url) {
return new Promise((resolve, reject) => {
request(url, (error, res, body) => {
if (!error && res.statusCode === 200) {
resolve(body);
} else {
reject("獲取頁面失敗" + error);
}
});
});
}
module.exports = {
parseBody
};
複製程式碼
新建config檔案,新增配置
// 阮一峰JS教程
const javaScriptCourse = {
url: "https://wangdoc.com/javascript", // 要爬取的網站地址
name: "阮一峰JavaScript教程.pdf", // 匯出的檔名字
wrapEle: ".menu-list", // 導航父元素的class
css: "@page { size: A6 landscape } html { font-size: 18pt } ", // 生成pdf的大小和字型
getUrlList(body, ele, url) {
// 從返回的html中獲取章節地址
let urlList = [];
$(body)
.find(ele)
.eq(0)
.find("li a")
.each((i, v) => {
const pathStr = $(v).attr("href");
const path = pathStr.slice(pathStr.indexOf("/"));
urlList.push(url + path);
});
return urlList;
}
};
複製程式碼
新建index.js為專案的入口檔案,引入相關依賴
const request = require("./util"),
percollate = require("percollate"),
markdownpdf = require("markdown-pdf"),
fs = require("fs"),
{ javaScriptCourse, es6Course, baseOpt } = require("./config");
const getHtml = url => {
return request.parseBody(url);
};
const getJSCourse = () => {
const { url, name, wrapEle, getUrlList, css } = javaScriptCourse;
getHtml(url).then(res => {
const urlList = getUrlList(res, wrapEle, url);
percollate.configure();
percollate.pdf(urlList, {
output: name,
css
});
});
};
// 生成pdf檔案
getJSCourse()
複製程式碼
以上是全部程式碼,總共不超過80行,執行之後,我們能看到終端列印的日誌
成功之後,在專案的目錄下就能看到生成的pdf檔案將Markdown檔案生成PDF
這個以阮一峰大神ES6教程為例,地址為:es6.ruanyifeng.com ,開啟網站後,我們發現,網站是通過介面動態生成內容的,網站請求返回的內容都為Markdown,
我們略過抓取文章地址的過程,詳情可在文章附上的原始碼中檢視,執行的轉化程式碼為percollate.configure();
percollate.pdf(urlList, {
output: name,
css: baseOpt.css,
sandbox: true // 設定為false,動態生成的內容抓取不到
});
複製程式碼
生成的PDF檔案如下,沒有轉成我們希望的樣子,內容為原始的Markdown語法
到此,我沒有再研究percollate
新增某個配置之後,是否就可以完美的將Markdown轉成PDF檔案,因為我知道Node有一個包markdown-pdf可以將Markdown轉成PDF檔案,還知道VScode有一個外掛也可以將Markdown轉成PDF檔案,這樣的話,我們首先要生成一個包含所有內容的Markdown檔案,Node的fs模組可以很容易的完成這件事情,生成Markdown檔案以後,再使用上面講述的兩種方法將Markdown轉成PDF即可,程式碼如下
const urlList = getUrlList(res, wrapEle, url);
const reqList = [];
urlList.forEach(v => {
console.log("請求地址---", v);
reqList.push(getHtml(v));
});
console.log("開始發出請求...");
Promise.all(reqList)
.then(arrRes => {
console.log("所有請求都成功了---");
const md = arrRes.join(" ");
// console.log(md);
const optPath =
"/Users/apple/Documents/my/LearningLog/NodeJs/網頁生成pdf/";
fs.writeFileSync(`${name}.md`, md, function(err) {
if (err) {
return console.error(err);
}
console.log("資料寫入成功!");
});
console.log("開始生成pdf檔案...");
markdownpdf({
paperFormat: "A6"
// paperOrientation: "landscape"
})
.from(`${optPath}${name}.md`)
.to(`${optPath}${name}.pdf`, function() {
console.log("生成pdf檔案成功");
});
})
.catch(err => {
console.log("請求報錯---", err);
});
複製程式碼
關於使用VScode將Markdown檔案轉為PDF的方法,我這裡就不贅述了,參考markdown-preview-enhanced 。
寫在最後
本文的所有程式碼以及生成的PDF檔案都在下面的地址,後續會更新更多的大佬免費教程的PDF檔案
已生成的免費網路教程PDF檔案:
如需調整大小、字型或者樣式,請fork原始碼自行生成。