puppeteer
是谷歌官方出品的一个通过 DevTools 协议控制 headless Chrome 的 Node 库,它提供了一个高级 API 来通过 DevTools 协议控制 Chromium 或 Chrome,执行常见的操作,就像在真实的浏览器中一样,可以用来实现浏览器自动化测试或爬虫
puppeteer 是浏览器自动化的产品。安装后,它会下载一个版本的 Chromium,然后使用puppeteer-core
驱动工作
在浏览器中手动执行的绝大多数操作都可以使用 puppeteer 来完成:
(Nodejs 6.4以上版本环境下)安装 puppeteer 时,它会下载最新版本的 Chromium,以保证可以使用 API
使用 npm 安装
npm install puppeteer
使用 cnpm 安装
cnpm install puppeteer
注:使用 async、await,Nodejs 的版本不能低于 v7.6.0
puppeteer 默认以 headless 模式(无头模式,不显示浏览器界面)运行,但是可以通过修改配置文件运行 “有头” 模式(显示浏览器界面)
新建 puppeteer.js:
//引入puppeteer
const puppeteer = require("puppeteer");
//使用async/await处理异步
(async () => {
//创建一个Browser(浏览器)实例
const browser = await puppeteer.launch({
//设置有头模式(默认为true,无头模式)
headless: false
});
//在浏览器中创建一个新的页面
const page = await browser.newPage();
//打开指定页面
await page.goto("https://blog.csdn.net/weixin_45426836?spm=1011.2124.3001.5343");
//......(执行的操作)
//关闭浏览器实例
await browser.close();
})();
const puppeteer = require("puppeteer");
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
//设置页面的尺寸
await page.setViewport({
width: 1400,
height: 800,
});
await page.goto("https://blog.csdn.net/weixin_45426836?spm=1011.2124.3001.5343");
await browser.close();
})();
const puppeteer = require("puppeteer");
(async () => {
const browser = await puppeteer.launch({
//设置页面的尺寸
defaultViewport: {
width: 1400,
height: 800
}
});
const page = await browser.newPage();
await page.goto("https://blog.csdn.net/weixin_45426836?spm=1011.2124.3001.5343");
await browser.close();
})();
自适应尺寸:将 defaultViewport 设为 null,启动之后还是半屏显示,点击浏览器最大化按后,页面根据分辨率自适应大小(使用该设置进行页面截图仍是半屏显示的截图)Browser
:当 puppeteer 连接到一个 Chromium 实例的时候会通过 puppeteer.launch 或 puppeteer.connect 创建一个 Browser 对象:
Page
:提供操作一个 tab 页或者 extension background page(扩展背景页) 的方法。一个 Browser 实例可以有多个 Page 实例:
Keyboard
:提供一个接口来管理虚拟键盘
Mouse
:提供一个接口来管理虚拟鼠标
node puppeteer.js
//引入puppeteer
const puppeteer = require("puppeteer");
//使用async/await处理异步
(async () => {
//创建一个Browser(浏览器)实例
const browser = await puppeteer.launch();
//在浏览器中创建一个新的页面
const page = await browser.newPage();
//设置页面的尺寸
await page.setViewport({
width: 1400,
height: 800,
});
//打开页面
await page.goto("https://baidu.com/");
//页面截图(设置截图路径)
await page.screenshot({path: "example.png"});
//关闭浏览器实例
await browser.close();
})();
执行命令会在根目录下生成 example.png(页面截图)
//引入puppeteer
const puppeteer = require("puppeteer");
//使用async/await处理异步
(async () => {
//创建一个Browser(浏览器)实例
const browser = await puppeteer.launch();
//在浏览器中创建一个新的页面
const page = await browser.newPage();
//设置页面的尺寸
await page.setViewport({
width: 1400,
height: 800,
});
//打开页面
await page.goto("https://baidu.com/");
//生成页面PDF(设置PDF路径)
await page.pdf({path: "example.pdf", format: "A4"});
//关闭浏览器实例
await browser.close();
})();
执行命令会在根目录下生成 example.pdf(页面 PDF)
使用 puppeteer 爬取:百度新闻 => 国内 => 即时新闻列表(标题和链接地址)
//引入puppeteer
const puppeteer = require("puppeteer");
//引入node文件系统模块(fs)
const fs = require("fs");
//引入node文件路径模块(path)
const path = require("path");
//创建爬取数据的函数
let getNewList = async () => {
//创建一个Browser(浏览器)实例
const browser = await puppeteer.launch();
//在浏览器中创建一个新的页面
const page = await browser.newPage();
//打开百度新闻页面
await page.goto("http://news.baidu.com/");
//等待“国内”导航按钮出现
await page.waitForSelector("#channel-all > div > ul > li:nth-child(3) > a");
//点击“国内”导航按钮,进入国内新闻页面
await page.click("#channel-all > div > ul > li:nth-child(3) > a");
//等待“即时新闻列表”出现
await page.waitForSelector("#instant-news > ul");
//通过evaluate函数执行自定义的js代码获取要爬取的数据
const newList = await page.evaluate(() => {
//创建一个空数组接收爬取的数据
let data = [];
//获取所有即时新闻列表li元素
let elements = document.querySelectorAll("#instant-news > ul > li");
//利用循环将即时新闻列表的标题和链接地址添加到一个数组中
for (let i=0; i<elements.length; i++) {
//获取新闻的标签
let title = elements[i].innerText;
//获取新闻的链接地址
let url = elements[i].firstChild.getAttribute('href');
//将获取到的标题和链接地址添加到数组中
data.push({
title,
url
});
}
//返回数组
return data;
});
//关闭浏览器实例
await browser.close();
//返回爬取的数据
return newList;
}
//执行函数获取爬取的数据
getNewList().then(res => {
//将爬取的数据转为json格式
let list = JSON.stringify(res);
//指定存储数据的json文件
let file = path.join(__dirname, "newList.json");
//将爬取的数据写入json文件
fs.writeFile(file, list, err => {
if (err) {
console.log(err);
} else {
console.log("success");
}
})
})
执行命令会在根目录下生成 newList.json(爬取的百度新闻国内即时新闻列表)
[
{
title: '倡导清洁能源取暖,让环保与温暖同行!',
url: 'http://baijiahao.baidu.com/s?id=1685083001881996849'
},
{
title: '关于减塑环保必胜客做了件大事 而且还做得挺漂亮',
url: 'http://baijiahao.baidu.com/s?id=1685499582365297158'
},
{
title: '「我的脱贫故事」脱贫前我们也害怕“开学”丨剑河',
url: 'http://baijiahao.baidu.com/s?id=1685501813192308560'
},
{
title: '山西留美学子靳蕾被聘为“中华环保志愿者公益形象',
url: 'http://baijiahao.baidu.com/s?id=1685513310840028026'
},
{
title: '忻城县2020年公开选拔县属国有企业领导人员面',
url: 'http://baijiahao.baidu.com/s?id=1685544017875709933'
},
{
title: '107名长沙市五星级环保好少年集中受表彰',
url: 'http://baijiahao.baidu.com/s?id=1685597128244025396'
},
{
title: '《圭塘河岸》一书发行 谱写新的“长江之歌”',
url: 'http://baijiahao.baidu.com/s?id=1685606433440976520'
},
{
title: '莫再错过!山东高考补报名12月14日-15日进',
url: 'http://baijiahao.baidu.com/s?id=1685607182699503282'
}
]