用 Puppeteer 实现简书文章备份
时间:2022-06-21
本文章向大家介绍用 Puppeteer 实现简书文章备份,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
读了篇文章 《前端使用 puppeteer 爬虫生成《React.js 小书》PDF并合并》。参照这个思路,可以用 Puppeteer 备份简书的文章。
呈现效果:
点击左侧的链接,可以看到每篇文章。每篇文章都存了一张截图,如下图所示:
实现思路
- 进入个人首页,抓取该用户所有的文章。
- 对每篇文章截图。
- 生成一个导航页面。该页面上的链接,可以看到每篇文章截图。
主要的实现代码
抓取该用户所有的文章。需要程序将页面滚动到底部,去拿所有文章。代码如下:
let articles = await page.evaluate(async () => {
// 将页面滚动到最底部
await new Promise((resolve, reject) => {
let totalHeight = 0
let distance = 200
let timer = setInterval(() => {
let scrollHeight = document.body.scrollHeight
window.scrollBy(0, distance)
totalHeight += distance
if(totalHeight >= scrollHeight){
clearInterval(timer)
resolve()
}
}, 100)
})
// 抓取所有文章
var res = Array.from(document.querySelectorAll('.note-list a.title'))
.map(link => {
return {
id: link.getAttribute('href').split('/').slice(-1),
title: link.textContent
}
})
return res
})
对每篇文章截屏。
for(var i = 0; i < articles.length; i++) {
await download(browser, articles[i].id)
}
加载文章中的图片,生成一个导航页面。该页面上的链接到每篇文章截图。
const imgs = Array.from(document.querySelectorAll('.show-content img'))
await Promise.all(imgs.filter(img => !img.complete).map(img => {
return new Promise((resolve, reject) => {
img.addEventListener('load', resolve);
img.addEventListener('error', resolve); // 也算成功吧
});
}))
下载某篇文章。
await page.screenshot({
fullPage: true,
path: resolve(outputConfig.path, `${pageInfo.title}.png`)
})
遇到的坑
图片懒加载
文章的图片是懒加载,因此直接截图,在页面不可见部分的图片会截不全。
解决方案: 程序将页面往下每过一段时间往下滚,滚动到不能滚动为止。
pfd 里插图片的问题
开始是想做一篇文章生成一个PDF,然后把所有的PDF再拼成一个PDF的。 但发现PDF插入图片,如果图片处于跨页位置或图片高度超过一页PDF的高度时,会自动裁切。效果不好,就放弃PDF了。
解决方案: 用图片来做截屏。
page.evaluate 不支持调用外部函数
解决方案:
用 page.evaluateHandle
添加方法。如果只是加外部的 consle.log
可以用
page.on('console', msg => console.log(msg.text()))
反爬虫
短时间内频繁访问简书的文章,会触发简书反爬虫机制,导致返回的页面超时。
解决方案: 如果页面访问超时,歇一段时间,多试几次。
try {
await page.goto(url)
} catch(e) {
// 请求超时,重试3次。 为了反爬虫。
await retry(3, async () => {
await page.goto(url)
})
}
async function retry(times, fn) {
if(times > 0) {
await timeout(1000) // 歇1秒再试
try {
await fn()
} catch(e) {
await retry(times--, fn)
}
}
}
- python爬取链家租房之获取北京所有区的网站分栏地址(第一次写,code太粗犷,欢迎提建议)
- Pandas-Series知识点总结
- Numpy基础知识点汇总
- P3388 【模板】割点(割顶)
- python爬取链家租房之获取房屋的链接和页面的详细信息
- 信用卡“坏账”客户分析(一)
- 一道简单的sql语句题
- python爬虫反爬取---设置User Agent自动变换header文件
- 一文读懂Python多线程
- 深入理解Python变量作用域与函数闭包
- TensorFlow从1到2 - 5 - 非专家莫入!TensorFlow实现CNN
- JetBrains Rider 破解 (ideaIU等等开发工具都通用)
- python中的小魔法(一)
- 由问题入手,步步爬出Python中赋值与拷贝的坑
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Excelize 2.3.1 发布,Go 语言 Excel 文档基础库,支持加密表格文档
- PUMA560机器人工具箱运动控制A:路径规划-运动学
- Android 3分钟带你入门开发测试
- Spring Boot 知识清单(一)SpringApplication
- Linux下的IO监控与分析
- pytorch+Unet图像分割:将图片中的盐体找出来
- html 用浏览器打开中文乱码解决方法
- SQLServer 数据库字符集、版本号sql语句查询语法
- chrome 浏览器自保留端口、安全端口有哪些?chrome不能访问某个端口的环境网址,但是其它的浏览器可以访问原因及解决办法。
- MySql 数据库 - 重置数据库、重置初始密码方法,数据库初始化方法,长时间不用忘记密码暴力解决方法
- MobaXterm工具连接Linux服务器入门使用手册,国产化泰山服务器连接工具使用演示
- Linux 服务器配置信息查询方法,国产化申威服务器配置信息查看演示
- 达梦数据库、oracle数据库如何判断指定表有没有建立索引?对应的表有没有索引查询方法
- Linux服务器运行sh文件提示权限不够解决方法?飞腾服务器Permission denied问题授权方法
- 不支持图形化界面的Linux系统如何显示图像化界面?飞腾服务器显示图像化界面方法,DISPLAY environment variable is undefined问题解决方法