1.介绍
Puppeteer 翻译是操纵木偶的人,利用这个工具,我们能做一个操纵页面的人。通俗点儿说,你可以通过代码的方式模拟人在 Chrome 中的各种操作,打开网址、开启多个 Tab、填写输入框,模拟鼠标轨迹、滚动滚动条,甚至截屏某个元素都可以。Puppeteer是一个Nodejs的库,支持调用Chrome的API来操纵Web,相比较Selenium或是PhantomJs,它最大的特点就是它的操作Dom可以完全在内存中进行模拟既在V8引擎中处理而不打开浏览器,而且关键是这个是Chrome团队在维护,会拥有更好的兼容性和前景。
官方:https://github.com/GoogleChrome/puppeteer
API文档: https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md
2.用处
1.利用网页生成PDF、图片
2.高级爬虫,可以爬取大量异步渲染内容的网页
3.自动化表单提交、UI测试、键盘输入等
4.帮你创建一个最新的自动化测试环境(chrome),可以直接在此运行测试用例
5.捕获站点的时间线,以便追踪你的网站,帮助分析网站性能问题
3.安装nodejs
英文网址:https://nodejs.org/en/download/
中文网址:http://nodejs.cn/download/
通过 uname -a 命令查看到我的Linux系统位数是64位(备注:x86_64表示64位系统, i686 i386表示32位系统)
假定下载的文件放在/home/software/中
cd /home/software/
解压:tar -xvf node-v6.10.0-linux-x64.tar.xz
重命名 mv node-v6.10.0-linux-x64 nodejs
建立软连接,变为全局
ln -s /home/software/nodejs/bin/npm /usr/local/bin/
ln -s /home/software/nodejs/bin/node /usr/local/bin/
npm在中国的下载速度并不是很理想,我们可以安装淘宝提供的cnpm来代替其功能。
官方网址 : https://npm.taobao.org/
全局安装cnpm。之后可以直接使用cnpm代替npm,命令格式是一样的。
npm install -g cnpm --registry=https://registry.npm.taobao.org
如果全局安装之后无法直接使用全局安装命令,一般是npm的路径没有在系统变量中,可以通过以下方法解决
用 bash echo -e "export PATH=$(npm prefix -g)/bin:$PATH" >> ~/.bashrc && source ~/.bashrc
bash echo -e "export NODE_PATH=/home/software/nodejs/node_modules" >> ~/.bashrc && source ~/.bashrc
使用node -v 和 npm -v 如有版本号输出,代表安装成功
4.安装Puppeteer
cnpm i puppeteer --save
5.例子
1).截图
puppeteer.launch 启动浏览器实例
browser.newPage() 创建一个新页面
page.goto 进入指定网页
page.screenshot 截图
page.setViewport 设置视图大小
page.setUserAget 设置UserAgent
const puppeteer = require('puppeteer');
async function run () {
const browser = await puppeteer.launch({
//设置超时时间
timeout: 15000,
//如果是访问https页面 此属性会忽略https错误
ignoreHTTPSErrors: true,
// 打开开发者工具, 当此值为true时, headless总为false
devtools: false,
// false:关闭headless模式, 会打开浏览器,true:不打开浏览器
headless: false,
});
const page = await browser.newPage();
//设置视窗大小为 1920x1080
page.setViewport({width:1920, height:1080});
//设置UserAgent
page.setUserAgent('Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/48.0.2564.82 Chrome/48.0.2564.82 Safari/537.36');
//waitUntil:等待页面完全加载完,包含异步渲染
await page.goto('https://tianfang.cnblogs.com', {waitUntil: 'networkidle2'});
await page.screenshot({ path: 'screen.png',fullPage: true,});
await browser.close();
};
run();
2).采集数据
const puppeteer = require('puppeteer');
async function run () {
const browser = await puppeteer.launch({
headless: true,
args: ['--no-sandbox']
});
const page = await browser.newPage();
page.setUserAgent('Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/48.0.2564.82 Chrome/48.0.2564.82 Safari/537.36');
//进入页面
await page.goto('https://www.guazi.com/hz/buy/', {waitUntil: 'networkidle2'});
//获取页面标题
let title = await page.title();
console.log(title);
//注入jquery
await page.addScriptTag({
url: "https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"
});
//向页面注入我们的函数,在浏览器中执行函数,相当于在控制台中执行函数,返回一个 Promise
const result = await page.evaluate(() => {
//var $ = window.$; 如果页面已加载jquery,可以不用注入jquery,用此方法可以直接获取jquery
var arr = [];
let brand = $(".js-brand").find("ul li p a");
brand.each(function(){
let brandText = $(this).html();
arr.push({brandText});
});
return arr ;
});
console.log(result);
const car_list_select = ".carlist"
const carList = await page.evaluate((sel) => {
var arr1 = [];
let carA = $(sel).find("li a");
carA.each(function(){
let title = $(this).find("h2").html();
let price = $(this).find(".t-price p").text();
arr1.push({title:title,price,price});
});
return arr1 ;
},car_list_select);
console.log(carList);
//退出
process.exit(1);
};
run();
3).模拟输入
page本身提供原始的mouse和keyboard的模拟输入类。
page.mouse
page.keyboard
page.click(selector[, options]) 在被选择元素上模拟点击
page.type(selector, text[, options]) 在被选择的输入框中输入
page.hover(selector) 模拟鼠标移动到被选择元素上
page.select(selector, ...values) 在被选择元素上模拟选择select选项
page.tap(selector) 在被选择元素上模拟触摸
const puppeteer = require('puppeteer');
let timeout = function (delay) {
return new Promise((resolve, reject) => {
setTimeout(() => {
try {
resolve(1)
} catch (e) {
reject(0)
}
}, delay);
})
}
async function run () {
const browser = await puppeteer.launch({
headless: true,
args: ['--no-sandbox']
});
const page = await browser.newPage();
page.setUserAgent('User-Agent:Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/48.0.2564.82 Chrome/48.0.2564.82 Safari/537.36');
await page.goto('https://passport.jd.com/new/login.aspx', {waitUntil: 'networkidle2'});
const loginTab = await page.$('.login-tab-r');
await loginTab.click();
const name = await page.$eval('#loginname',el=>el.placeholder);
console.log(name);
//const loginFor = page.$('.login-form');
//await page.screenshot({path:"jd.png", fullPage:true});
const image = await page.waitForSelector('.login-form');
await image.screenshot({path:"jd_form.png"});
//await page.click("#loginname");
//await page.keyboard.type("wuxing164");
//await page.click("#nloginpwd");
//await page.keyboard.type("wuxing165");
await page.type('#loginname', "wuxing164");
await page.type('#nloginpwd', "wuxing165");
await page.click("#loginsubmit");
await timeout(3000);
await page.screenshot({
path: 'jd-index.png'
});
process.exit(1);
};
run();
---------------------------------------------------------------------------------------------------------------------------------------------------------
// 页面加载更多按钮出现(查找元素)
await page.waitForSelector('.more');
// 拿到页面上的jQuery
var $ = window.$;
面模拟设置相关函数有如下几个,
page.setViewport: 设置视图大小
page.setUserAget: 设置UserAgent
page.SetCookie: 设置Cookie
页面跳转相关函数有如下几个,
page.goto(url, options)
page.goBack(options)
page.goForward(options)
page.reload(options)
常用的元素函数选择有:
page.$(selector) 选一个元素
page.$$(selector) 选多个元素
模拟输入page本身提供原始的mouse和keyboard的模拟输入类。
page.mouse
page.keyboard
但同时也提供更方便快捷的模拟输入函数
page.click(selector[, options]) 在被选择元素上模拟点击
page.type(selector, text[, options]) 在被选择的输入框中输入
page.hover(selector) 模拟鼠标移动到被选择元素上
page.select(selector, ...values) 在被选择元素上模拟选择select选项
page.tap(selector) 在被选择元素上模拟触摸
当我们使用page.goto等跳转函数主动跳转页面时,本身该函数就是可以异步等待的,可以直接使用await等待跳转完成。
除此之外,系统也提供了如下等待函数
page.waitForNavigation(options)
page.waitFor(selectorOrFunctionOrTimeout[, options[, ...args]])
page.waitForSelector(selector[, options])
page.waitForXPath(xpath[, options])
page.waitForFunction(pageFunction[, options[, ...args]])
其中最常用的是page.waitForNavigation,常用于等待跳转结束,例如点击搜索按钮后,等待跳转至搜索结果页面。
const navigationPromise = page.waitForNavigation();
await page.click('a.my-link');
await navigationPromise;
另外,我们如果需要更细粒度的等待,可以使用其它几个wait函数,如如果我们要等待某图片的第一次加载。
执行脚本
执行脚本最常用的函数是page.evaluate,它类似于在控制台中执行指令。
console.log(await page.evaluate('1 + 2'));
var title = await page.evaluate('document.title')
它也可以用来执行写好的node函数,实际上该函数是在浏览器中执行的,但可以像本地函数一样编写,还支持参数传值。
var title = await page.evaluate(async (i) => {
return document.title + ' ' + i;
}, 'hello');
console.log(title);
另外,还有几个其它的执行脚本的函数,应用于不同的场合,也是非常有用的。
page.evaluateHandle(pageFunction, ...args)
page.evaluateOnNewDocument(pageFunction, ...args)
page.$$eval(selector, pageFunction[, ...args])
page.$eval(selector, pageFunction[, ...args])
例如:
const searchValue = await page.$eval('#search', el => el.value);
const preloadHref = await page.$eval('link[rel=preload]', el => el.href);
const html = await page.$eval('.main-container', e => e.outerHTML);
信息查看
puppeteer提供了一些查看页面信息的函数,
page.url()
page.content()
page.frames()
page.mainFrame()
page.metrics()
page.target()
page.title()
page.viewport()
page.$(selector) 选一个元素
page.$$(selector) 选多个元素
page.$(selector) 选一个元素
page.$$(selector) 选多个元素
page.$(selector) 选一个元素
page.$$(selector) 选多个元素
page.$(selector) 选一个元素
page.$$(selector) 选多个元素
一些参考文章
https://blog.csdn.net/xiatiancc/article/details/78872157https://cloud.tencent.com/developer/article/1006000
https://www.jianshu.com/p/4441d0241b6e
https://cnodejs.org/topic/5a238b818eab6ee92a694622
https://blog.csdn.net/u010142437/article/details/79136182
https://www.cnblogs.com/TianFang/p/9059978.html
http://csbun.github.io/blog/2017/09/puppeteer/
https://blog.csdn.net/u010142437/article/details/79136182
https://gitbook.cn/books/5aa4835a987ed32df6a2123c/index.html
https://www.cnblogs.com/imgss/p/headless.html