Puppeteer入门初探

勿忘初心2018-09-27 10:33


本文来自网易云社区

作者:唐钊


最近在看 node 爬虫相关的一些东西,我记得还是很久以前常用的 node 爬虫工具还是 superagengt+cherrio,他们的思路是通过发起 http 请求然后截取 respone 的内容,但是随着前端mvvm等框架的盛行,现在更多的内容是异步加载了,所以通过这种传统的爬虫方式已经很难抓取到我们想要的内容了,那么Puppeteer又有什么亮点呢?接下来我们详细介绍一下这个由 google 官方团队维护的大杀器!

Puppeteer是一个Node库,由Chrome官方团队进行维护,提供接口来控制headless Chrome。Headless Chrome是一种不使用Chrome来运行Chrome浏览器的方式。简单的来说就是一个运行在命令行中的 chrome,我们可以通过代码来实现我们常规的浏览器浏览网页的功能。这样就能保证我们拿到的内容和正常通过浏览器查看的是一毛一样的!


Puppeteer 核心功能

  • 利用网页生成PDF、图片
  • 爬取SPA应用,并生成预渲染内容(即“SSR” 服务端渲染)
  • 可以从网站抓取内容
  • 自动化表单提交、UI测试、键盘输入等
  • 帮你创建一个最新的自动化测试环境(chrome),可以直接在此运行测试用例
  • 捕获站点的时间线,以便追踪你的网站,帮助分析网站性能问题

接下来我们通过一些简单的示例来看一下它的使用


安装

安装还是常规的流程,通过yarn或npm来完成。只需运行下面的命令:

yarn add pupeeter
//or
npm i -S puppeteer


DEMO

demo-截屏

const puppeteer = require("puppeteer");   //引入 puppeteer
(async() => {
    /*通过 launch 生成一个’浏览器‘实例,
    option 中的 headless 是个布尔值,如果是 false 的话你就会看到一个浏览器从打开,到完成你整个任务的全过程,
    默认是 true,也就是在后台自动完成你的任务
    */
    const browser = await puppeteer.launch({ headless: false });  
    //打开一个新的标签页
    const page = await browser.newPage();
    //跳转到我们想要的地址去
    await page.goto("http://www.hockor.com/");
    //默认打开的视口大小是800X600 ,我们可以通过如下代码来设置窗口的大小,
    await page.setViewport({
        width:1920,
        height:1080
    })
    //通过screenshot方法完成截屏,并且保存在指定的 path 中
    await page.screenshot({ path: "nba.png" });
    //最后关闭整个‘浏览器‘
    browser.close();
})();

过程如下:


demo-通过搜索引擎拉取图片

上面我们展示了 puppeteer一个基础的 demo 完整实例,但是它更强大的地方还有很多,不仅支持在网页上点击,还可以填写表单,读取数据。大家可以去官方 api 查看,传送链接

接下来开始我们下一个 demo,这个示例我们完成一个在搜索引擎中爬取我们想要的图片并保存到本地的功能。来更进一步的了解这个强大的工具。

  • 我们的任务是在搜狗图片中爬取关键词为“NBA”的图片,并且保存在我们当前的 imgs 目录下。

那么核心的关键点就在于输入我们的关键词并且跳转到对应的列表页面,然后爬取内容中所有的 img 标签,并将其保存在我们制定的目录中。接下来我们详细剖析。

通过查看Puppeteer API,可以找到定义点击的函数和聚焦的函数:

page.click(selector[, options])
page.focus(selector);

以上selector 一个选择器来指定要点击的元素。如果多个元素满足,那么默认选择第一个。 这不正好满足了我们前面的逻辑,输入框聚焦和点击,那么怎么输入关键词呢?

For finer control, you can use keyboard.down, 
keyboard.up, and keyboard.sendCharacter to manually 
fire events as if they were generated from a real keyboard.

可以看到我们可以通过 page.keyboard.sendCharacter 来输入我们自己的文字

正好,这样子我们就满足了我们前期的条件,那么完整的代码如下


const puppeteer = require("puppeteer");
(async ()=>{
    const brower = await puppeteer.launch();
    const page = await brower.newPage();
    await page.goto("http://pic.sogou.com/");
    await page.setViewport({
        width:1920,
        height:1080
    })

    //上面的代码和之前是一样的,不同是下面几句
    //
    await page.focus("#form_querytext");
    await page.keyboard.sendCharacter("nba");
    await page.click("#searchBtn")

    await page.waitFor(1000);

    //监听页面 load 完成
    page.on('load',async ()=>{
        console.log("page loaded");
        const srcs = await page.evaluate(()=> {
            const images = document.querySelectorAll("img.img-hover");
            return Array.prototype.map.call(images,img=>img.src)
        })

        //遍历图片并且保存
        srcs.forEach(async (src)=> {
            console.log(src)
            const ext = path.extname(src) ? path.extname(src):".jpg";
            const file = path.join('./imgs',`${Date.now()}${ext}`)
            http.get(src,res=>{
                res.pipe(fs.createWriteStream(file)).on('finish',(err)=>{
                    if(err){
                        console.log(err)
                    } else {
                        console.log("done")
                    }
                })
            })
        })
        await brower.close()
    })
})()

我们可以看到上面的流程就像我们正常浏览网页一样,而不是以前那种在 http response 中去抓取内容,这样子对于现在的很多懒加载页面或者前端渲染来讲我们都能成功的爬取到我们想要的内容。

更多的官方 demo 例子我们可以去https://try-puppeteer.appspot.com/编辑查看。

目前 puppeteer在爬虫和前端自动化测试上使用也日益增大,大家可以去官方 API 文档查看它的更多功能!大家也可以结合自己的需求/业务场景,充分挖掘Puppeteer功能。


网易云免费体验馆,0成本体验20+款云产品! 

更多网易研发、产品、运营经验分享请访问网易云社区