Node爬虫工具Puppeteer入门教程实践
作者:程序员Jeffre
Puppeteer是一个Node库,本文主要介绍了Node爬虫工具Puppeteer入门教程实践,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
【Puppeteer概要】
- Puppeteer 是一个 Node 库,它提供了一个高级 API 来通过 DevTools 协议控制 Chromium 或 Chrome。 Puppeteer API 是分层次的,反映了浏览器结构。
 - Puppeteer 使用 DevTools 协议 与浏览器进行通信。
 - Browser 实例可以拥有浏览器上下文。
 - BrowserContext 实例定义了一个浏览会话并可拥有多个页面。
 - Page 至少有一个框架:主框架。 可能还有其他框架由 iframe 或 框架标签 创建。
 - frame 至少有一个执行上下文 - 默认的执行上下文 - 框架的 JavaScript 被执行。 一个框架可能有额外的与 扩展 关联的执行上下文。
 - Worker 具有单一执行上下文,并且便于与 WebWorkers 进行交互。
 
【Puppeteer 错误处理】
Error handling
- 如果 
Puppeteer方法无法执行一个请求,就会抛出一个错误。例如,page.waitForSelector(selector[, options])选择器如果在给定的时间范围内无法匹配节点,就会失败。 对于某些类型的错误,Puppeteer使用特定的错误类处理。这些类可以通过require('puppeteer/Errors')获得。 支持的类列表: 
TimeoutError 一个处理超时错误的例子:
const {
    TimeoutError
} = require('puppeteer/Errors'); // ...
try {
    await page.waitForSelector('.foo');
} catch(e) {
    if (e instanceof TimeoutError) {  
    // 如果超时,做一些处理。 
    }
}Puppeteer Working with Chrome Extensions
Puppeteer可以用来测试Chrome扩展
注意
Chrome / Chromium扩展当前只能在非无头模式下使用。
下面的代码用来处理扩展的 background page,该扩展的代码在 ./my-extension:
const puppeteer = require('puppeteer'); (async() = > {
const pathToExtension = require('path').join(__dirname, 'my-extension');
const browser = puppeteer.launch({
    headless: false,
    args: [`--disable - extensions - except = $ {
        pathToExtension
    }`, `--load - extension = $ {
        pathToExtension
    }`]
});
const targets = await browser.targets();
const backgroundPageTarget = targets.find(target = >target.type() === 'background_page');
const backgroundPage = await backgroundPageTarget.page(); // 像处理任何其他页面一样测试背景页面。  await browser.close();})();【Puppeteer class:puppeteer】
Puppeteer模块提供了一种启动Chromium实例的方法。 下面就是使用Puppeteer进行自动化的一个典型示例:
const puppeteer = require('puppeteer');
puppeteer.launch().then(async browser = >{
const page = await browser.newPage();
await page.goto('https://www.google.com'); // 其他操作...  await browser.close();});Methods
- puppeteer.connect(options)v0.9.0
 - puppeteer.createBrowserFetcher([options])v0.9.0
 - puppeteer.defaultArgs([options])v0.9.0
 - puppeteer.executablePath()v0.9.0
 - puppeteer.launch([options])v0.9.0
 
Methods
puppeteer.connect(options)v0.9.0
options<Object>browserWSEndpoint<string>一个 浏览器 websocket 端点链接。ignoreHTTPSErrors<boolean>是否在导航期间忽略 HTTPS 错误. 默认是false。defaultViewport<?Object> 为每个页面设置一个默认视口大小。默认是800x600。如果为 null 的话就禁用视图口。width<number>页面宽度像素。height<number>页面高度像素。deviceScaleFactor<number>设置设备的缩放(可以认为是 dpr)。默认是1。isMobile<boolean>是否在页面中设置了meta viewport标签。默认是false。hasTouch``<boolean>指定viewport是否支持触摸事件。默认是false。isLandscape<boolean>指定视口是否处于横向模式。默认是false。slowMo<number>将 Puppeteer 操作减少指定的毫秒数。这样你就可以看清发生了什么,这很有用。returns:<Promise<Browser>>此方法将Puppeteer添加到已有的Chromium实例。
puppeteer.createBrowserFetcher([options])v0.9.0
options<Object>host<string>要使用的下载主机. 默认是https://storage.googleapis.com。path<string>下载文件夹的路径. 默认是<root>/.local-chromium,<root>是 puppeteer 的包根目录。platform<string>可能的值有:mac, win32, win64, linux。默认是当前平台。returns:<BrowserFetcher>
puppeteer.defaultArgs([options])v0.9.0
options<Object>设置浏览器可选项。有一下字段:headless<boolean>是否在 无头模式 下运行浏览器。默认是true除非devtools选项是true。args<Array<string>>传递给浏览器实例的其他参数。可以 在这 找到 Chromium 标志列表。userDataDir<string>用户数据目录 的路径。devtools<boolean>是否为每个选项卡自动打开DevTools面板。如果这个选项是true的话,headless选项将被设置为false。returns:<Array<string>>Chromium 启动时使用的默认参数。
puppeteer.executablePath()v0.9.0
returns:<string>Puppeteer 希望找到绑定的Chromium的路径。- 如果使用 
PUPPETEER_SKIP_CHROMIUM_DOWNLOAD跳过下载,则Chromium可能不存在。 
puppeteer.launch([options])v0.9.0
options<Object>在浏览器上设置的一组可配置选项。 有以下字段:ignoreHTTPSErrors<boolean>是否在导航期间忽略HTTPS错误. 默认是false。headless<boolean>是否以 无头模式 运行浏览器。默认是true,除非devtools选项是true。executablePath<string>可运行 Chromium 或 Chrome 可执行文件的路径,而不是绑定的Chromium。如果executablePath是一个相对路径,那么他相对于 当前工作路径 解析。slowMo<number>将 Puppeteer 操作减少指定的毫秒数。这样你就可以看清发生了什么,这很有用。defaultViewport<?Object>为每个页面设置一个默认视口大小。默认是800x600。如果为 null 的话就禁用视图口。width<number>页面宽度像素。height<number>页面高度像素。deviceScaleFactor<number>设置设备的缩放(可以认为是dpr)。默认是1。isMobile<boolean>是否在页面中设置了meta viewport标签。默认是false。hasTouch``<boolean>指定viewport是否支持触摸事件。默认是false。isLandscape<boolean>指定视口是否处于横向模式。默认是false。args<Array<string>>传递给浏览器实例的其他参数。 这些参数可以参考 这里。- ignoreDefaultArgs <(boolean|
<Array<string>>)> 如果是true,那就不要使用puppeteer.defaultArgs()。 如果给出了数组,则过滤掉给定的默认参数。这个选项请谨慎使用。默认为false。 handleSIGINT<boolean>Ctrl-C 关闭浏览器进程。默认是true。handleSIGTERM<boolean>关闭 SIGTERM 上的浏览器进程。默认是true。handleSIGHUP<boolean>关闭 SIGHUP 上的浏览器进程。默认是true.timeout<number>等待浏览器实例启动的最长时间(以毫秒为单位)。默认是30000 (30 秒). 通过 0 来禁用超时。dumpio<boolean>是否将浏览器进程标准输出和标准错误输入到process.stdout 和 process.stderr中。默认是false。userDataDir<string>用户数据目录 路径。env<Object>指定浏览器可见的环境变量。默认是process.env。devtools<boolean>是否为每个选项卡自动打开DevTools面板。如果这个选项是true,headless选项将会设置成false。pipe<boolean>通过管道而不是WebSocket连接到浏览器。默认是false。returns:<Promise<Browser>>浏览器实例支持Promise。
这个方法结合了下面3个步骤:
使用 puppeteer.defaultArgs() 作为一组默认值来启动 Chromium。
启动浏览器并根据 executablePath ,handleSIGINT,dumpio 和其他选项开始管理它的进程。 创建一个 Browser 类的实例,并根据 defaultViewport,slowMo 和 ignoreHTTPSErrors 初始化它。 ignoreDefaultArgs 选项可用于自定义(1)步骤的行为。 例如,要从参数中过滤掉 --mute-audio:
const browser = await puppeteer.launch({
    ignoreDefaultArgs: ['--mute-audio']
});
复制代码Puppeteer 浏览器
- extends: 
EventEmitter当Puppeteer连接到一个Chromium实例的时候会通过puppeteer.launch或puppeteer.connect创建一个Browser对象。 下面是使用Browser创建Page的例子 
const puppeteer = require('puppeteer');
puppeteer.launch().then(async browser = >{
const page = await browser.newPage();
await page.goto('https://example.com');
await browser.close();
});- 一个断开连接和重连到 Browser 的例子:
 
const puppeteer = require('puppeteer');
puppeteer.launch().then(async browser = >{ // 存储节点以便能重新连接到 Chromium  
const browserWSEndpoint = browser.wsEndpoint();  // 从 Chromium 断开和 puppeteer 的连接  browser.disconnect();  // 使用节点来重新建立连接  
const browser2 = await puppeteer.connect({browserWSEndpoint});  // 关闭 Chromium  
await browser2.close();});Puppeteer 页面
Page提供操作一个tab页或者extensionbackgroundpage的方法。一个Browser实例可以有多个Page实例。 下面的例子创建一个Page实例,导航到一个url,然后保存截图:
const puppeteer = require('puppeteer');
puppeteer.launch().then(async browser = >{
    const page = await browser.newPage();
    await page.goto('https://example.com');
    await page.screenshot({
        path: 'screenshot.png'
    });
    await browser.close();
});- Page会触发多种事件(下面描述的),可以用 node原生的方法 来捕获处理,比如 
on,once或者removeListener。下面的例子捕获了一个page实例的load事件,打印了一句话: 
page.once('load', () => console.log('Page loaded!'));- 可以用 
removeListener取消对事件的监听: 
function logRequest(interceptedRequest) {
    console.log('A request was made:', interceptedRequest.url());
}
page.on('request', logRequest); // 一段时间后...page.removeListener('request', logRequest);Methods
page.$(selector)v0.9.0
selector
<string>选择器 返回:<Promise<?ElementHandle>>此方法在页面内执行
document.querySelector。如果没有元素匹配指定选择器,返回值是 null。page.mainFrame().$(selector) 的简写。
page.$$(selector)v0.9.0
selector
<string>选择器返回:
<Promise<Array<ElementHandle>>>此方法在页面内执行
document.querySelectorAll。如果没有元素匹配指定选择器,返回值是 []。page.mainFrame().$$(selector)的简写。
page.waitForSelector(".index-content .click-zoom a")
- 等待页面元素加载完成
 
await page.waitForSelector(".index-content .click-zoom a")page.waitFor(1000)
- 等待1000毫秒执行
 
await page.waitFor(1000)
page.click('.btn')
await page.click('.btn')- 点击class 为btn元素
 
page.evaluate
- 执行原生js
 
await page.evaluate(() => {
      document.getElementById("HD_CheckIn").value = "2020-07-11";
})示例
- 代码执行
 
- 安装 puppeteer 依赖包
 - node xxx.js 运行js
 
/**
* 爬取游戏站数据 https://game.pipajam.com/
*/
const fs = require('fs')
const puppeteer = require('puppeteer');
(async () => {
    const browser = await puppeteer.launch({
        headless: false,
        args: ['--start-maximized', '--disable-infobars'],
        width: 1600,
        height: 900
    });
    // 1、 创建两个页面
    const page = await browser.newPage();
    const page2 = await browser.newPage();
    // 2、进入首页
    await page.goto(
        'https://game.pipajam.com/'
    );
    // 3、等待页面游戏数据元素加载完成
    await page.waitForSelector(".index-content .click-zoom a")
    // 4、获取所以游戏链接 游戏名称 
    const list = await page.$$eval(".index-content .click-zoom a", (el => el.map(el => ([el.href, el.getElementsByTagName('h6')[0].innerText]))));
    console.log(list);
    let len = list.length, index = 0, data = []
    // 5、调用函数 组装数据
    mainFun()
    async function mainFun () {
        try {
            // 6、开启page2 页面 获取游戏详情数据
            await page2.goto(
                list[index][0],{
                    timeout: 0
                }
            );
            // 7、等待详情卡片加载完成
            await page2.waitForSelector(".play-game-card .play-game-card-center")
            // 8、获取游戏链接地址 图片地址
            const item = await page2.$eval(".play-game-card .play-game-card-center", (el => [el.getElementsByTagName('p')[0].innerHTML, el.getElementsByTagName('img')[0].src]));
            await page2.click('.play-game-card .play-game-card-center a')
            const url = await page2.evaluate(param => window.location.href, "参数");
            // 9、组装数据
            data.push({
                description: item[0],
                img: item[1],
                instructton: "",
                keyfeatures: "",
                name: list[index][1],
                published: "Mon Oct 08 2018",
                tags: [],
                url,
                type: 'Children\'s intelligence',
            })
            console.log('以写入第' + (index+1) + '数据。');
            // 10、获取所以游戏数据 并写入指定json 文件
            ++index < len ? mainFun() : fs.writeFile('../../json/Game/pipajam.json', JSON.stringify(data), () => {})
        } catch (error) {
            console.log(error, 'err')
        }
    }
})();到此这篇关于Node爬虫工具Puppeteer入门教程实践的文章就介绍到这了,更多相关Node Puppeteer入门内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
