目录
总述
puppeteer是Node库中的一个用来控制Chrome浏览器的API。功能强大到东西多到没时间一下学完,所以放个链接指路https://www.npmjs.com/package/puppeteer https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#browserbrowsercontexts
以下内容为本小白对npm上内容的看得懂的翻,看不懂的瞎讲结果。
先看看这个木偶可以干什么(O_O)
- 生成页面的屏幕截图和PDF。
- 抓取SPA(单页面应用程序)并生成预渲染内容(即“SSR”(服务器端渲染))。
- 自动化表单提交,UI测试,键盘输入等。
- 创建最新的自动化测试环境。使用最新的JavaScript和浏览器功能直接在最新版本的Chrome中运行测试。
- 捕获网站的时间线跟踪,以帮助诊断性能问题。
- 测试Chrome扩展程序。
为啥选puppeteer而不用cheerio呢?
一开始我用的是cheerio来进行爬取,但是cheerio只能爬静态的html,相当于一个帮你打开了html文件,然后也只能在里面读取信息,而那些用CSS渲染过的动态内容就读不出来了,下面是一段试图用cheerio爬豆瓣的代码:
const https = require('https');
const cheerio = require('cheerio');//下载cheerio依赖,命令行npm i cheerio
const fs = require('fs');
const request = require('request');
var isbn = '9787040238792';
var url = 'https://book.douban.com/subject_search?search_text='+isbn+'&cat=1001';
function fetchpage(x) {
startRequest(x);
}//程序封装
function startRequest(x) {
https.get(x,function(res){
//https访问请求,res返回已被解析的报文
var html = '';
res.setEncoding('utf8');//防止中文出现乱码
res.on('data', function(chunk){
//每接受一段流就进行一次回调函数
html += chunk;//把流拼接起来(buffer字符串在拼接的时候会自动转化为'utf8')
});//监听数据
res.on('end', function(){
console.log(html);
var $ = cheerio.load(html);//解析DOM字符串
var img = $('#root > div > div._p4fcggx3k > div._yib0bfn3n > div:nth-child(1) > div > div > a > img').attr('src');
console.log(img);
request.head(img,function(err,res,body){
if (err) {
console.log('---cover download error---');
}
request(img).pipe(fs.createWriteStream(__dirname + '/cover.png'));
})
});//监听结束
res.on('error',function(err){
console.log(err.message);//打印错误信息
})//监听错误
})
}
fetchpage(url);//运行爬取页面程序
运行这段代码发现豆瓣网站的html不能完全反映网站的显示,html中没有包含的显示部分其实是用CSS渲染的,其内容没有包含在html中,所以里面的图片是爬不出来的 ಥ_ಥ
puppeteer可以模拟用户登入浏览器时的操作,它比起cheerio的好处是它可以更方便的对动态网站进行操作,简单来说就是平时用浏览器可以怎么操作、看到什么,你就可以用puppeteer操作、读取。
puppeteer安装
终端输入:(注意⚠️要科学上网)
npm i puppeteer
puppeteer学习
截图
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch();//开启一个浏览器(返回一个浏览器)
const page = await browser.newPage();//开新页面
await page.goto('https://www.bilibili.com');//去往指定页面
await page.screenshot({path: 'bilibili.png'});//截屏
await browser.close();//关闭浏览器及所有页面
})();
爬取书籍信息
由于目标页面的url是动态变化的,所以需要从一个url不变的页面跳转过去。
const puppeteer = require('puppeteer');
async function main(){
const browser = await puppeteer.launch({headless:false});//开启一个浏览器(返回一个浏览器)
//在调用 Puppeteer 的 launch 方法的时候传入参数对象中带有 headless: false,即可启动其 GUI 界面,进行可视化调试。
const page = await browser.newPage();//开新页面
var isbn = '9787040225969';
var url1 = 'http://opac.nlc.cn/F/B2LYQVUJH7V1LX1Q879MVTBI6FSA3XR8QTFMLLTCE1I6DSNA8G-84640?func=file&file_name=login-session';
//{waitUtil: 'networkidle2'} 由于页面数据是异步的,等待异步请求完毕,页面渲染完毕
await page.goto(url1, {waitUtil: 'networkidle2'});//去往指定页面
//用isbn码搜索跳转页面
await page.select('select#find_code','ISB');//选择isbn码搜索
await page.type('#reqterm',isbn);//键入isbn码
await page.click('#indexpage > form > div.btn > input[type=submit]');//点击搜索
//等待元素加载完成
await page.waitForSelector('img#bigcover');
//爬取书籍信息
const bookData = await page.evaluate(()=>{
let title = document.querySelector("#td > tbody > tr:nth-child(4) > td:nth-child(2) > a").innerText;
let editon = document.querySelector("#td > tbody > tr:nth-child(5) > td:nth-child(2)").innerText;
let press = document.querySelector("#td > tbody > tr:nth-child(6) > td:nth-child(2) > a").innerText;
let size = document.querySelector("#td > tbody > tr:nth-child(7) > td:nth-child(2)").innerText;
let category = document.querySelector("#td > tbody > tr:nth-child(8) > td:nth-child(2) > a").innerText;
let content = document.querySelector("#td > tbody > tr:nth-child(10) > td:nth-child(2)").innerText;
let topic = document.querySelector("#td > tbody > tr:nth-child(11) > td:nth-child(2) > a").innerText;
let author = document.querySelector("#td > tbody > tr:nth-child(13) > td:nth-child(2) > a").innerText;
return {
title,
editon,
press,
size,
category,
content,
topic,
author
};
});
console.log(bookData);
//获取书籍封面图片
page.on('requestfinished',async(request) =>{
//监听到请求完成
if(request.url().indexOf('http://opac.nlc.cn/cgi-bin')){
//如果监听到的请求的url包含此段
const image = await page.waitForSelector('img#bigcover');
//对元素截图
await image.screenshot({
path: 'cover.png',
omitBackground: false
});
//await browser.close();//关闭浏览器及所有页面
}
})
//await browser.close();//关闭浏览器及所有页面
}
main();