如何利用 Puppeteer 爬取数据?

作为一个程序员,我跟大多数人一样,都不善言辞,以前也尝试过录制视频,很不理想,无意中发现了GitChat 这个功能,对我们这些不太会录视频的人简直是福音,在这个人人自媒体的时代,大家都可以发光发热,把自己所了解的跟大家共同分享,真是一件大好事儿。

引言

今天给大家分享下 Puppeteer 的部分功能——抓取网页内容。本文所演示的环境是在 MacOS,其他平台类似,如有问题,请提出,大家共同讨论解决。

介绍 Puppeteer

Puppeteer 是一个提供强大的 API 用来控制操作 Chrome 的类库。通俗点儿说,你可以通过代码的方式模拟人在 Chrome 中的各种操作,打开网址、开启多个 Tab、填写输入框,模拟鼠标轨迹、滚动滚动条,甚至截屏某个元素都可以。具体详细的内容可以参看 Puppeteer 官方和 API 文档。

安装

安装 Node.js 和 npm

npm 是和 Node.js 一起发布的,所以下载安装 Node.js 之后,就可以使用 npm 了,可以点击这里下载安装对应的版本。执行下面的内容,显示出版本信息就证明安装成功了。

/tmp# node -vv9.3.0/tmp# npm -v5.6.0

初始化项目

(1)新建文件夹 xxx。

(2)初始化 npm 项目。

会生成一个配置文件 package.json,这个文件记录了我们项目的依赖,移植起来会很方便。

安装 Puppeteer

因为要下载 Chrome 内核,直接用上面的代码,国内大部分时候会失败,原因你懂得。如果安装的时候出现类似的字样,这意味着你被无情的挡在了墙里面。

安装失败,就需要手动去下载了,墙再高也挡不住大家热爱知识的热情。分两步,第一步安装 Puppeteer 代码,第二部手动下载他所依赖的 Chromuim 内核。

(1)安装 Puppeteer 代码。

(2)手动下载 Chromuim。

点击这里下载,点进去之后就是对应平台的版本,直接下载就行。下载成功后解压到我们的项目目录 spider-puppeteer 下面,Chromium 文件夹需要创建。

基本使用

小试牛刀

如果是自己手动下载的 Chromuim,需要在 puppeteer.launch 的时候手动配置 executablePath 参数,对应可执行文件位置。

参数 headless 表示是否显示界面,false 显示界面。

参数 args 用来设置启动浏览器时候的一些参数,其中--window-size=1360,768 表示设置参浏览器启动的时候,浏览器窗口的大小,还有很多类似的参数,详细内容请看传送门,我们这里只讲用到的,因为参数实在太多了。

效果如下所示,为了让图片减小,截取了一部分,但还是有好几MB。

进阶使用

注入 JavaScript

注入 JavaScript,就是向目标页面注入我们自己的 JavaScript,方便我们操作、处理页面元素。比如我们这里想要获取到微博用户主页的用户名,习惯用 jQuery 的话就可以主动注入,提高自己的效率。

这里面又有了下面几个概念:

waitFor,顾名思义,就是等待的意思,用它可以做很多操作,比如等待页面元素,页面中某个元素不确定什么时候加载出来,但是我们要在元素存在的时候处理,就可以使用这个方法。还可以用它来 sleep,在开启的页签中等待。

evaluate,向页面中注入代码执行,并返回结果。

返回结果如下所示:

未注入 jQuery 之前的结果:$ is not defined。

注入 jQuery 之后的结果:燕睿涛Liam。

获取 Google 翻译结果

目前为止,我们对 Puppeteer 的基本使用算是有个了解了,接下来我们来做个小工具,抓取 Google 翻译的结果(Tips:需要翻过高高的围墙)。

为了让工具体验更好我们需要另外一个类库 commander,用来处理命令行参数。

通过安装参数处理类库,下面我们会用到。

获取谷歌翻译,我们主要用到了 Puppeteer 的下面几个知识点儿:

等待页面元素

模拟聚焦页面元素输入框

模拟键盘输入内容

模拟点击页面按钮

获取页面元素内容

代码如下:

执行结果如下所示:

登录微博

未登录状态只可以看部分微博,所以,获取微博内容之前,需要我们模拟登陆微博。

使用 Puppeteer 模拟登录微博的时候,跟我们抓取静态页面的模拟登录不太一样,我们这里完全模拟人机交互登录微博。

登陆的时候 page.waitForNavigation(options) 很重要,一定要等到页面完全加载完毕,再输入用户名密码,不然会出现输入中失去焦点的情况,导致登录失败。

下面的代码只是部分代码,拿出来介绍登录流程。

爬取微博用户微博

爬取微博用户微博,用到了 querystringify 组件,用来解析 query 参数。

安装过程如下:

爬取用户微博截图整体流程:

由于微博是 Lazy Load 模式,不会一次将分页的所有内容展示出来,需要通过用户滚动鼠标滑轮触发加载事件,我们这里通过 Puppeteer 发送 JavaScript 命令给页面,让页面滚动加载,详情见下面的 scrollToPageBar。

抓取微博内容是通过 elementHandle.screenshot([options]) 函数来截取元素快照的。但到目前为止,还有些瑕疵,比如抓取微博内容的时候要对微博列表做各种处理,先隐藏所有,再显示要截屏的,不然会出现文字被背景覆盖的情况,不知道是不是 Puppeteer 的 Bug。另外还有它的 Headless 模式,也就是不显示浏览器的模式,抓取内容抓取几页之后,可能会随机的出现“假死”的情况,就卡在截屏操作那里,也不报错,这个问题目前还没找到原因。因此我们这里一般都将“headless”设置为 false,显示浏览器。请看下面的代码。

下面是命令行的输出情况,大家可以试试效果,我这边抓取了李小璐的所有原创微博,一共970多条,图片命名方式是 [_.png]。

命令行会记录脚本的状态,抓取到第几页,每抓取一个就显示一个"."。

如果你想要抓取自己感兴趣的用户,需要将 weiboSpider.js 中的91、145行代码替换为自己感兴趣的微博用户对应链接。

总结

听我说了这么多,你可能早已经跃跃欲试了,这里把本文相关的源代码放出来,感兴趣的可以自己试下。另外,这里面需要使用用户名密码的地方需要替换为你自己的。如果微博出现让输入验证码的情况,可以等一等再试,验证码这里目前还没有完全自动化。

对 Puppeteer,我个人的愚见是:网页中只要你能看到的地方,它几乎都可以帮你处理,对于爬取某些加密的地方太有用了。它也不用我们去模拟登陆收集各种 Cookie 信息了。还有让输入验证码的地方也会有相对更友好的方式处理了,做成半自动化的形式,这个后面有机会了再尝试。

源代码地址:https://pan.baidu.com/s/1fBfhbXtLRxZbfUUYEWzJog,密码:759k。

下载下来解压之后,执行 npm install 就可以了,如果安装失败,看看是不是下载 Chromuim 失败,如果失败,可以执行 npm install --ignore-scripts,然后按照上面的步骤手动下载就可以了。

谢谢大家的支持。

如果你对本文有疑问,

或者想和作者进行技术交流,

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20180329B1SYGF00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券