使用puppeteer 进行批量网页截图
时间:2022-07-22
本文章向大家介绍使用puppeteer 进行批量网页截图,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
数据来源为一个txt文件
每一行用t分割后 前面是域名后面是url 域名用来md5后作为截图名
pageSize控制一次最多打开多少个页面 防止网页过多占用内存过多
配置里的'--proxy-server=socks5://127.0.0.1:1080' 是用来走本地小飞机代理的
const puppeteer = require('puppeteer');
var fs = require('fs');
var readline = require('readline');
const crypto = require('crypto');
var file = '/test/snap.txt';
//最多多少个页面
const pageSize = 50;
var date = new Date();
var startTime = date.getTime();
readFileToArr(file ,async function (data){
console.log('本次需要截图[' + data.length+']条')
console.log('开始执行:'+startTime);
if(data.length>0){
snp(data).then(() => {
console.log('执行清空文件操作');
fs.access(file, fs.constants.F_OK, (err) => {
console.log(`${file} ${err ? '不存在' : '存在'}`);
var ws1 = fs.createWriteStream(file, 'utf-8');
ws1.write('');
ws1.end();
console.log(`${file}` +' 已清空');
});
}).catch(function (err) {
console.log(err);
});;
}
});
async function snp(arr){
const config = {
ignoreHTTPSErrors:true,
defaultViewport:{width:1920,height:1080},
args: [
'--no-sandbox','--proxy-server=socks5://127.0.0.1:1080'
],
headless: true
}
const browser = await puppeteer.launch(config);
var that = this;
while(arr.length>0){
var some;
if(arr.length >pageSize){
some = arr.splice(0,pageSize);
}else{
some = arr.splice(0,arr.length);
}
var length = some.length;
var a = [];
for (let j = 0; j < length; j++) {
if(some[j] === '') continue;
var line = some[j].split('t');
if(line.length !==2 ){console.log('数据不全:' + some[j]);continue;}
var domain = line[0];
var url = line[1];
var page = await browser.newPage();
//默认30S超时
//page.setDefaultNavigationTimeout(3000);
try{
await page.goto(url);
console.log('已打开:'+url);
page.on('dialog', async dialog => {
await dialog.accept();
});
}catch(err){
console.log('打开网页出错:'+err);
}
a.push(page);
}
//等待时间 可调整
//await a[0].waitFor(1 * 1000);
for (i = 0; i < length; i++) {
if(some[i] === '') continue;
var line = some[i].split('t');
if(line.length !==2 ){console.log('数据不全:' + some[i]);continue;}
var domain = line[0];
var url = line[1];
var fileName = getMD5(domain) + '.png';
try {
await a[i].screenshot({ path: '/test/snapshot/'+fileName });
console.log('截图成功: '+domain);
await a[i].close();
} catch (e) {
console.log('截图出错: '+e)
}
}
}
await browser.close();
var endTime = new Date().getTime();
console.log('执行结束:'+endTime);
console.log('本次执行时间:' + (endTime-startTime)/1000 + 's');
}
//读取文件
function readFileToArr(fReadName,callback){
var fRead = fs.createReadStream(fReadName);
var objReadline = readline.createInterface({
input:fRead
});
var arr = new Array();
objReadline.on('line',function (line) {
arr.push(line);
//console.log('line:'+ line);
});
objReadline.on('close',function () {
// console.log(arr);
callback(arr);
});
}
//获取md5值
function getMD5(data) {
// 加入字符编码
var md5 = crypto.createHash('md5').update(data, 'utf-8').digest('hex');
return md5;
}
目前还可以优化的地方:
当前流程是依次打开网页,等待当前网页加载完成后再去打开下一个网页,若某一个网页打开较慢或打不开,则会一直等待到超时。
可以改为调用goto后不等待,并行的打开网页,大大减少打开网页过程中花费的时间。
第二版
由于第一版 虽说是一次打开多个标签页了,但是实质上还是和串行一个个打开没有区别,我在page的load事件上也没有找到能保存当前页面上下文并使其在后面可选择使用的好办法。
所以不如直接使用串行 由于截图任务要的是准确第一 速度第二 所以改为串行也未尝不可
主要改动的地方就是snp()方法 并且删掉了pageSize这个常量
async function snp(arr){
const config = {
ignoreHTTPSErrors:true,
defaultViewport:{width:1920,height:1080},
args: [
'--no-sandbox','--start-maximized'
],
headless: false
}
const browser = await puppeteer.launch(config);
var page = await browser.newPage();
for(let i=0;i<arr.length;i++){
if(arr[i] === '') continue;
var line = arr[i].split('t');
if(line.length !==2 ){console.log('数据不全:' + arr[i]);continue;}
var domain = line[0];
var url = line[1];
var fileName = getMD5(domain) + '.png';
await page.goto(url,{waitUntil: ['networkidle0']}).then(()=>{
console.log('已打开:'+url);
}).catch( err =>{
console.log('打开网页出错:' + url);
});
page.on('dialog', async dialog => {
await dialog.accept();
});
await page.screenshot({path: '/Users/rzx/Desktop/snapshot/'+fileName});
console.log('截图成功: '+domain);
}
await page.close();
await browser.close();
var endTime = new Date().getTime();
console.log('本次执行时间:' + (endTime-startTime)/1000 + 's');
}
- 为什么使用--start-maximized这个参数:有些网页在最大化下和它默认大小下 截出来的图片不一样 默认尺寸下可能会出现拼接的情况
- await page.goto(url,{waitUntil: ['networkidle0']}) 此处waitUntil的作用:有些网页 打开后会继续请求js 做出动画或改变样式 添加此参数的意思是直到没有任何网络连接 视为跳转成功。可以有效避免部分网页刚打开 load事件触发了就截图 截出的图不完整
- Uva 11300 Spreading the Wealth(递推,中位数)
- Uva 11729 Commando War (简单贪心)
- UVA 11292 Dragon of Loowater(简单贪心)
- Codeforces Beta Round #2 A,B,C
- 牛顿迭代法(Newton's Method)
- 最长递减子序列(nlogn)(个人模版)
- Selenium2+python自动化26-js处理内嵌div滚动条
- Selenium2+python自动化25-js处理日历控件
- 转负二进制(个人模版)
- Selenium2+python自动化24-js处理富文本
- 【干货】对抗自编码器PyTorch手把手实战系列——PyTorch实现对抗自编码器
- Selenium2+python自动化23-富文本(自动发帖)
- 2-Sat+输出可行解(个人模版)
- 协同过滤原理及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 数组属性和方法