Google推出了无图形界面的headless Chrome之后,可以直接在远程服务器上直接跑一些测试脚本或者爬虫脚本了,猴开心!Google还附送了Puppeteer用于驱动没头的Chome。
阿里的Macaca也顺势写了Macaca-puppeteer,可以在Macaca上直接写通用的测试用例,在开发机上用图形界面看效果,上服务器走生产,岂不是美滋滋。
然鹅,可达鸭眉头一皱,发现事情并没有那么简单。
在阿里云的Centos 7.3上,安装puppeteer之后,会发现并不能启动官方的example:
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://example.com');
await page.screenshot({path: 'example.png'});
await browser.close();
})();
依赖安装
仔细看错误栈,核心的错误是如下一段:
…node_modules/puppeteer/.local-chromium/linux-496140/chrome-linux/chrome: error while loading shared libraries: libpangocairo-1.0.so.0: cannot open shared object file: No such file or directory
TROUBLESHOOTING: https://github.com/GoogleChro…
原来puppet虽然帮你下了一个Chromium,但并没有帮你把依赖都装好。于是你要自己把那些so都装好。
官方给的是Ubuntu版本的各个so包的apt-get安装方式,centos版本居然没有放!于是遍历了各个issue之后,终于发现还是有人给出了centos的库名,在一个看起来并不相关的issue里:
#依赖库
yum install pango.x86_64 libXcomposite.x86_64 libXcursor.x86_64 libXdamage.x86_64 libXext.x86_64 libXi.x86_64 libXtst.x86_64 cups-libs.x86_64 libXScrnSaver.x86_64 libXrandr.x86_64 GConf2.x86_64 alsa-lib.x86_64 atk.x86_64 gtk3.x86_64 -y
#字体
yum install ipa-gothic-fonts xorg-x11-fonts-100dpi xorg-x11-fonts-75dpi xorg-x11-utils xorg-x11-fonts-cyrillic xorg-x11-fonts-Type1 xorg-x11-fonts-misc -y
总算不用挨个去google了……
sandbox去沙箱
这时候你再去执行脚本,发现还是跑不起来。但是报错终于变了。这个时候变成了一个莫名其妙的错误:
(node:30559) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: Failed to connect to chrome!
(node:30559) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
要疯掉了有没有,这啥玩意啊!!!!关键是这时候另外一个看起来是解决上面问题的issue,对这个错误进行了详细的讨论,然而直到今天(2017年9月27日)并没有讨论出什么结果。
网上很多讨论是说,直接调试那个Chrome。按照并不能解决问题的说法:直接去puppeteer的目录找到.local-chrome里面的Chromium执行文件,直接执行
./chrome -v --no-sandbox --disable-setuid-sandbox
(chrome:5333): Gtk-WARNING **: cannot open display:
发现加上了--no-sanbox
其实是能启动的,但是提示没有Gtk图形界面,那干脆加上–headless是不是就行了嘞?确实没有报错了。
回到puppeteer示例脚本,修改启动浏览器的代码,加上args:
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch({args: ['--no-sandbox', '--disable-setuid-sandbox']});
const page = await browser.newPage();
await page.goto('https://example.com');
await page.screenshot({path: 'example.png'});
await browser.close();
})();
啊哈,终于执行成功了。下载下来了example.com的截图看了一眼,简直泪流满面。
回想一下,Puppet本身估计自带了–headless,所以如果直接去命令行执行chrome,还是要带上–headless。
终于搞定这一切发现Macaca顺便还提供了一个基于Ubuntu的Macaca-puppeteer的Docker,艾玛这方便太多了,早知道不自己折腾了。