Puppeteer:使用总结(二) 如何使用Puppeteeer导出网页中选中的内容
前言
上回说道:我已经用Puppeteer把CSDN的文章导出成了PDF。上回请看这里: Puppeteer:使用总结(一) 如何使用Puppeteeer导出网页中选中的内容
那么接着上一次的最后一个问题,这真的是我想要的吗?不,这不是
要是这是一个项目或者产品,我早被产品经理,项目经理,老板,客户,QA KO无数回了。为啥?难道我每次使用都要去改动代码?去改URL,去改文件名?No,No,No
首先我自己这一关就过不了,花了这么多精力写出一个东西来,然后你给我讲每次使用还要修改代码。自己撞墙算了。
不会炒菜的程序员不是好的产品经理。(什么鬼,我也不知道)
总之技术问题解决了,我还得继续努力让他变得好用起来。
目录
前言
自动生成文件名
去掉多余的文件名
去掉特殊字符
配置URL输入源
设计命令输入格式
让生成PDF部分支持配置
见证奇迹的时刻
单独导出一篇文章
同时导出两或者多篇文章
使用文件作为输入
总结
自动生成文件名
既然每个CSDN博文都有标题,那么我们是不是可以把它作为PDF的文件名呢?答案当然是可以的。
先查看Puppeteer的API,找到这么个方法:
page.title()v0.9.0
- returns: <Promise> 返回页面标题.
page.mainFrame().title()的简写
很好,这就是我想要的。
接下来修改我们的代码如下:
首先获取title:
let title= await page.title();
然后修改PDF文件名:
await page.pdf({ path: title+'.pdf', format: 'A4'
走你:
npm csdntopdf.js
效果看起来不错哈,自动生成了文件名:
嗯,文件名是有了,但是总感觉哪里不对。哦哦,对了后面那个什么xxx的博客-CSDN博客就可以不要了吧。毕竟文章里面已经保留了版权信息,减少点文件名的长度也是好的。
去掉多余的文件名
先观察一下文件名组成:
标题+下划线+xxx的博客+中划线+CSDN博客.pdf
所以后半部分几乎是固定的下划线+xxx的博客+中划线+CSDN博客.pdf,只有博主名是变的,感觉应该可以用正则式去掉:
/[_](.+)的博客[-]CSDN博客$/gi
继续修改取title的代码:
let title = await page.title(); title = title.replace(/[_](.+)的博客[-]CSDN博客$/gi, '')
不出意外,去掉了后面的字符串。
去掉特殊字符
看文章表里里面还有“:”这样的特殊字符,这些字符在文件系统里是不被允许的,我这里虽然保存成功了,是因为那个字符不是ASCII码而是中文字符。所以为了将来少点bug,顺带就把这个处理了。
先找到文件名中不允许的特殊字符:
好说,再使用一个正则表达式把他们一一去掉:
/[\\\/\:\*\?\"\\|?:]/gi
继续修改获取title的方法:
let title = await page.title();title = title.replace(/[_](.+)的博客[-]CSDN博客$/gi, '')title = title.replace(/[\\\/\:\*\?\"\\|?:]/gi, '_')
OK现在文件名的问题解决了,那么下一个问题就是文章地址的输入问题。
配置URL输入源
其实要输入可以使用交互式输入,也可以使用命令行的方式输入。我更加喜欢命令行的方式输入,因为这样更方便,而且后续还可以和其它代码做集成。于是我暂时只是用两种数据来源作为输入:一是文件,二是直接在命令行里输入。
设计命令输入格式
按照以前惯用的命令行格式,设计如下的命令行:
Usage:node csdntopdf.js [-help] <[-inputfile ]|[-url ]>-help : Print command help information.-inputfile : Specify a filename which contains urls need to be exported.-url ] : Specify one or more URLs which need to be exported, each URL will be separated by ','. Examples:node csdntopdf.js -inputfile D:\\urls.txtnode csdntopdf.js -url D:\\urls.txt
效果如下:
然后在csdntopdf.js里解析用户输入,没有使用什么高级的方式,主要是没必要,用个简单的for循环搞定:
for (let j = 0; j < process.argv.length; j++) { if (process.argv[j] == '-help') { argError = true; break; } if (process.argv[j] == '-inputfile' || process.argv[j] == '-url') { if (j + 1 < process.argv.length) { if (process.argv[j] == '-inputfile') { let filename = process.argv[j + 1] if (fs.existsSync(filename)) { InputFile = filename; } else { console.error(filename + " not exists.") argError = true; break; } } else { URLS = URLS.concat(process.argv[j + 1].split(',')) } } else { argError = true; break; } }}
这里只是部分代码,完整代码会在后面给出。
让生成PDF部分支持配置
加入for循环,可以支持多个页面的导出。并添加一些输出提示。
for (let j = 0; j < URLS.length; j++) { const url = URLS[j]; console.log("[" + (j + 1) + "/" + total + "] Exporting: " + url) try { await page.goto(url, { waitUntil: 'networkidle2' }); let title = await page.title(); title = title.replace(/[_](.+)的博客[-]CSDN博客$/gi, '') title = title.replace(/[\\\/\:\*\?\"\\|?:]/gi, '_') await page.addStyleTag( { content: ` .recommend-box.insert-baidu-box, div.comment-box, .second-recommend-box.recommend-box, .first-recommend-box.recommend-box, div.blog-footer-bottom, #toolBarBox, div.csdn-side-toolbar, aside.blog_container_aside, #csdn-toolbar{ display:none !important; } .nodata .container main {width: 90% !important;} .nodata .container { width: 100% !important; display:flex; justify-content:center; padding:0; } ` }) await page.pdf({ path: title + '.pdf', format: 'A4' }); } catch (error) { console.error("[" + (j + 1) + "/" + total + "] Exporting:" + url + " failed") console.error(error) } }
见证奇迹的时刻
所有代码已经就绪下面就来试试吧,挑了两篇文章:
PowerShell:如何一行代码(脚本)刷抖音快手视频?老司机教你如何薅羊毛(二)【多线程版】_火星蛙的博客-CSDN博客
PowerShell:如何一行代码(脚本)刷抖音快手视频?老司机教你如何薅羊毛(一)(建议收藏)_火星蛙的博客-CSDN博客
单独导出一篇文章
node csdntopdf.js -url https://blog.csdn.net/gjmjack/article/details/120338321
生成成功,检查了一下pdf文件也没有任何问题。完美!
同时导出两或者多篇文章
多个URL之间用逗号分割,不能有空格
node csdntopdf.js -url https://blog.csdn.net/gjmjack/article/details/120338321,https://blog.csdn.net/gjmjack/article/details/118695137
依然成功,文件内容没有任何问题。
使用文件作为输入
新建一个文件input.txt 把下面的URL放入其中,然后保存。
PowerShell:如何一行代码(脚本)刷抖音快手视频?老司机教你如何薅羊毛(二)【多线程版】_火星蛙的博客-CSDN博客
PowerShell:如何一行代码(脚本)刷抖音快手视频?老司机教你如何薅羊毛(一)(建议收藏)_火星蛙的博客-CSDN博客
输入命令:
node csdntopdf.js -inputfile input.txt
检查输出文件也OK,一切已经搞定,一个初步的小tool就成功了,哈哈哈。
完整的代码:
const puppeteer = require('puppeteer');const fs = require('fs')let InputFile = nulllet URLS = []let argError = false;let usage = `Usage:node csdntopdf.js [-help] <[-inputfile ]|[-url ]>-help : Print command help information.-inputfile : Specify a filename which contains urls need to be exported.-url ] : Specify one or more URLs which need to be exported, each URL will be separated by ','. Examples:node csdntopdf.js -inputfile D:\\urls.txtnode csdntopdf.js -url D:\\urls.txt`for (let j = 0; j < process.argv.length; j++) { if (process.argv[j] == '-help') { argError = true; break; } if (process.argv[j] == '-inputfile' || process.argv[j] == '-url') { if (j + 1 { try { const browser = await puppeteer.launch(); console.log("Start to exporting PDF files [" + URLS.length + "]") const page = await browser.newPage(); const total = URLS.length; for (let j = 0; j < URLS.length; j++) { const url = URLS[j]; console.log("[" + (j + 1) + "/" + total + "] Exporting: " + url) try { await page.goto(url, { waitUntil: 'networkidle2' }); let title = await page.title(); title = title.replace(/[_](.+)的博客[-]CSDN博客$/gi, '') title = title.replace(/[\\\/\:\*\?\"\\|?:]/gi, '_') await page.addStyleTag( { content: ` .recommend-box.insert-baidu-box, div.comment-box, .second-recommend-box.recommend-box, .first-recommend-box.recommend-box, div.blog-footer-bottom, #toolBarBox, div.csdn-side-toolbar, aside.blog_container_aside, #csdn-toolbar{ display:none !important; } .nodata .container main {width: 90% !important;} .nodata .container { width: 100% !important; display:flex; justify-content:center; padding:0; } ` }) await page.pdf({ path: title + '.pdf', format: 'A4' }); } catch (error) { console.error("[" + (j + 1) + "/" + total + "] Exporting:" + url + " failed") console.error(error) } } await browser.close(); console.log("Exported all pages.") } catch (error) { }})();
我不禁又问自己:难道这就是我想要的吗?
未完待续
总结
- 使用pdf.title自动生成了输出的PDF文件名
- 使用正则表达式去掉了文件名中多余的字符和可能存在的特殊字符
- 增加了命令行参数用于URL输入
- 增加了Node中的文件操作