我常用的puppeteer爬虫api

8,803 阅读4分钟

本文共1451字,阅读时间约4分钟

Puppeteer是Chrome团队出的nodejs库(无头浏览器),其中一个功能是网页抓取(可以作为爬虫使用)

详细介绍请看gayhub,更新周期大约是一个月,本文是基于 v1.4.0写的,大致api是通用的。 本文总结了Puppeteer爬虫的主要用法。我的目标是,有了这篇文章,日常的一般爬虫使用就不需要去看官方文档了。

一、安装和使用

1.1安装

cnpm i -S puppeteer 用cnpm安装没有试过报错,默认会下载puppeteer配套版本的Chromium。

1.2 使用

const puppeteer = require('puppeteer');

(async () => {
   const browser = await puppeteer.launch({
    headless: false, //默认为true(无头),不显示浏览器界面
    slowMo :200, //减速显示,有时会作为模拟人操作特意减速
    devtools: true //显示开发者工具。页面宽高默认800*600,把开发者工具显示再隐藏页面会占满屏幕,有没有大佬解释下?
  });
  //生成Page对象
  //const page = await browser.newPage();//官网写法:一打开浏览器会打开两个tab,第二个才是你正在操作的tab
  const page = (await browser.pages())[0]; //这是我的写法,只有一个tab
  await page.goto('https://www.juejin.com'); //跳转到掘金
 //请开始你的表演...

  await browser.close(); //关闭浏览器
})();

puppeteer基本上每个操作都会返回一个Promise,记得要用await接收下一步的操作。

puppeteer上也提供了一些第三方写的爬虫demo,不过感觉封装得有点多,先不玩。

二、基本用法

2.1 调整页面

页面宽高默认800*600,我觉得太小。我一般都会先初始化页面大小。

和上面说的一样,这只是初始化的时候的大小,当打开再隐藏开发者工具后,页面就会占满全屏了,不知道这是不是bug。

await page.setViewport({
    width: 1280,
    height: 800
  });

2.2 模拟输入和点击

目测底层是用document.querySelector()

await page.type(selector, 'Hello puppeteer'); //找到对应的选择器然后填充值。如果之前设置了slowMo会看到像人打字一样,值是一个一个填进<input/>
await page.click(selector); //模拟点击,这对传统异步分页(url没有分页参数)很有用,selector定在下一页的标签上

2.3 iframe处理

如果网页内有用iframe等标签,这时page对象是无法读取<iframe>里面的内容的,需要用到page.frames()。返回一个Frame对象数组。 通常iframe会有name属性,判断name属性可以快速获取单个Frame对象的内容。

let iframe = await page.frames();
iframe.find(f => f.name() === 'name')

2.4 waitFor函数

waitFor函数是简写,Page和Frame对象都有。我只会用以下两种方式,剩下了请大佬指点一下。

为了简化,Page和Frame对象都有的api,我不会再特意说明,会在代码中直接体现。

await iframe.waitFor('.contain .item') //在<iframe>中等待'.contain .item'的节点出现,阻塞结束(ps:优先使用,有时200ms我是等不起的)
await page.waitFor(200)//页面等待200ms

2.5 selector和emulate

为什么要合在一点写呢?因为确实有一个组合的api叫eval

先分开说说吧。

2.5.1 selector

目测底层是用document.querySelector()和document.querySelectorAll()。熟悉这两个api的人应该很容易上手。

//ps:较少用
page.$(selector) // document.querySelector()
iframe.?(selector) // document.querySelectorAll(), ?是All的意思

2.5.2 emulate

这里首先要有个概念,puppeteer爬虫解析dom在浏览器,这个api的实参在浏览器中。所以可以在这个函数内进行dom操作,同时本地的node api是无法在这里运行的,运行console.log(global)会报错。

举个栗子:在函数内有console.log('按f12,我出现在浏览器的console中,并不在node命令行')

你会发现node命令行看不到这句话,而在Chromium的console中看见。因此你应该理解他的运行环境是当前网站,而不是你本地的node。

//ps:更少用
await page.evaluate(el => {
    //喜闻乐见的dom操作
})
await iframe.evaluate(el => {
    //请开始你的表演
    console.log('按f12,我出现在浏览器的console中,并不在node命令行')
})

2.5.3 真正的主角 $eval?eval

上面的两个api一起用就变成了eval,我最常用的api之一。一个api顶上面两个,集中一起写,舒服。

const result = await page.$eval(selector, el => {
    //如果需要赋值要返回Promise
    return new Promise(resolve => {
        //...一波骚操作
        //可以用Dom api啦
        reslove(obj)
    })
});
await iframe.$$eval(selector, el => {...});

2.6 监听事件

上文说过在page.evaluate中用console是不能在node命令行打印出来的,不过有了监听事件就可以改变这个规则了。也可以在监听事件里面做容错处理。

page.on('console', msg => {
    console.log(msg);
});

个人觉得如果打印dom的话,还是看浏览器的console比较好,直观。

//监听浏览器报错
page.on('pageerror', pageErr => {
    console.log(pageErr);
});
//监听node报错
page.on('error', err => {
    console.log(err);
});

三、伪装移动端

const devices = require("puppeteer/DeviceDescriptors");
const iPhone = devices["iPhone 6"];
...
await page.emulate(iPhone);

更多设备可以查看这里

以上就是我要介绍的puppeteer爬虫api。


安利两本书,一本是老姚的正则表达式pdf版说得很详细,确实很有用,虽然我已经忘了一大半了(╯﹏╰);另一本是 Web 前端面试指南与高频考题解析小册子,内容基础又丰富,希望我可以找个机会实践一下。

下面我要说说正事

小弟不才,17年软件工程毕业生,熟悉vue写过两个公司项目。目前已离职,坐标广州,求大佬们收留。