使用 puppeteer 抓取页面

1 简介

Puppeteer 是由 Chrome 官方出品的无头浏览器,同类工具还有 PhantomJS 和 Selenium,不过均已停止维护,随着 Chrome 市场份额的提升,Puppeteer 已经可以能兼容绝大多数的页面,我们可以通过 Puppeteer 实现自动化表单提交、UI测试、键盘输入、诊断性能问题、测试 Chrome 扩展等。由于 Puppeteer 是由 Node 实现的,所以 PHP 需要使用 puphpeteer 包。

2 安装

由于我的开发环境使用的是 Laradock,因此安装过程以 Laradock 为例。

2.1 composer 引入包

在宿主机执行composer require nesk/puphpeteer

2.2 在容器中安装puphpeteer

首先,我们需要在容器中安装 node,但 laradock 同时启动了 workspace 和 php-fpm 容器,我们应该在哪个容器中安装 node 呢?在.env中,只有一个将node 安装至 workspace 中的配置。我一开始也认为会使用 workspace 环境,所以修改配置文件,重新构建镜像、运行容器,但在运行中发现竟然提示node: command not found,我以为是 www 用户无法读取到 node 命令,最后在代码中输出调试信息后发现,代码使用的是 php-fpm 环境,于是进入 php-fpm 环境进行手动安装。

2.2.1 修改源

在 node 安装前,建议修改为国内镜像源以加速,我使用的中科大源速度还不错

1
2
3
4
5
6
7
8
9
10
11
deb https://mirrors.ustc.edu.cn/debian/ buster main contrib non-free
deb-src https://mirrors.ustc.edu.cn/debian/ buster main contrib non-free

deb https://mirrors.ustc.edu.cn/debian/ buster-updates main contrib non-free
deb-src https://mirrors.ustc.edu.cn/debian/ buster-updates main contrib non-free

deb https://mirrors.ustc.edu.cn/debian/ buster-backports main contrib non-free
deb-src https://mirrors.ustc.edu.cn/debian/ buster-backports main contrib non-free

deb https://mirrors.ustc.edu.cn/debian-security/ buster/updates main contrib non-free
deb-src https://mirrors.ustc.edu.cn/debian-security/ buster/updates main contrib non-free

2.2.2 安装 node

通过cat /etc/issue确定容器系统为 Debian,因此手动执行apt update来更新软件库,否则无法找到 nodejs,然后执行apt install nodejs安装。

2.2.3 安装puphpeteer

执行npm install @nesk/puphpeteer

Chrome 版本地址在以下位置管理,可以在淘宝镜像中查找更新

2.2.3 安装 php-sockets 扩展

通过 pecl 无法安装 sockets 扩展,可以在php-src下载对应版本源码,解压后 ext/sockets中提取并打包扩展,然后通过docker cp命令将扩展包复制到容器中编译安装。

2.2.4 安装依赖环境

此时运行时还会有以下错误提示:

1
2
3
4
5
(node:25272) UnhandledPromiseRejectionWarning: Error: Failed to launch chrome!
/var/www/puppeteer/node_modules/puppeteer/.local-chromium/linux-594312/chrome-linux/chrome: error while loading shared libraries: libX11-xcb.so.1: cannot open shared object file: No such file or directory

Fix new Error with
gconf-service libasound2 libatk1.0-0 libatk-bridge2.0-0 libc6 libcairo2 libcups2 libdbus-1-3 libexpat1 libfontconfig1 libgcc1 libgconf-2-4 libgdk-pixbuf2.0-0 libglib2.0-0 libgtk-3-0 libnspr4 libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6 ca-certificates fonts-liberation libappindicator1 libnss3 lsb-release xdg-utils wget

这是因为我们系统中还缺少的运行所需的依赖,执行以下命令安装即可修复

1
sudo apt-get install gconf-service libasound2 libatk1.0-0 libatk-bridge2.0-0 libc6 libcairo2 libcups2 libdbus-1-3 libexpat1 libfontconfig1 libgcc1 libgconf-2-4 libgdk-pixbuf2.0-0 libglib2.0-0 libgtk-3-0 libnspr4 libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6 ca-certificates fonts-liberation libappindicator1 libnss3 lsb-release xdg-utils wget

解决方案来自:https://github.com/puppeteer/puppeteer/issues/3443

2.2.5 非沙箱环境运行

当我们以为万事大吉时,又弹出了这样的错误提示:

1
2
(node:28469) UnhandledPromiseRejectionWarning: Error: Failed to launch chrome!
[1025/150325.817887:ERROR:zygote_host_impl_linux.cc(89)] Running as root without --no-sandbox is not supported. See https://crbug.com/638180.

根据错误提示,我们来添加--no-sandbox来试一下

1
2
3
4
5
6
7
8
9
10
use Nesk\Puphpeteer\Puppeteer;

$puppeteer = new Puppeteer;
$browser = $puppeteer->launch(['args'=> ['--no-sandbox']]);

$page = $browser->newPage();
$page->goto('https://example.com');
$page->screenshot(['path' => 'example.png']);

$browser->close();

🥳 Bingo! It’s work!

因为热爱,所以执着。