这段时间公司在做chrome插件,灵机一动想用nodejs来做采集,所以自己写了一个nodejs采集项目,给大家分享一下使用puppeteer插件来采集时遇到的坑
一 、root权限问题
在服务器上终端root权限启动项目,puppeteer启动浏览器不会报错,但是在宝塔面板node项目中启动 项目, 此时以root权限运行..会报错不能以root权限运行谷歌,这不安全.他不让你启动
Error: Failed to launch the browser process! undefined
[383823:383823:0424/220835.990977:ERROR:zygote_host_impl_linux.cc(99)] Running as root without --no-sandbox is not supported. See https://crbug.com/638180.
解决方案:在puppeteer的配置上加入如下选项:
args: ['--no-sandbox', '--disable-setuid-sandbox']
//配置launch
const browser = await puppeteer.launch({
// 需要在无头模式下使用Puppeteer,需要在启动浏览器时设置headless选项为true
headless: true,
// 设置浏览器窗口大小
defaultViewport: {
width: 1200,
height: 1200,
},
+ args: ['--no-sandbox', '--disable-setuid-sandbox'],
// Puppeteer默认使用的是Chromium浏览器,如果你想使用Chrome浏览器,需要在启动浏览器时设置executablePath选项为Chrome浏览器的路径
// executablePath: '/Applications/Chromium.app/Contents/MacOS/Chromium',
//本地谷歌浏览器
// executablePath: '/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome',
//服务器谷歌浏览器地址
executablePath: '/usr/bin/google-chrome',
timeout: 40000, // 超时时间,单位为毫秒
});
然后再启动项目puppeteer不会运行沙箱..这样就可以成功启动了
二 、无法在ts文件中evaluate里面使用async await 函数
强行使用会报错:__awaiter is not defined
Evaluation failed: ReferenceError: __awaiter is not defined
这是因为puppeteer是运行在目标页面的浏览器上,evaluate这个参数里面打包的ts代码中没有__awaiter这个函数,所以自然就不能运行async await
解决方案:
1.不在evaluate里面使用async await(等于白说哈哈哈哈,本人目前无解,百度了N种方案都没有解决,包括直接引入__awaiter,和通过ts配置来解决等等都无效)
2.使用同步的延时方式来达到阻止程序向下执行的目的(因为页面操作需要时间)
const wait = (ms: number) => {
let start = Date.now(),
now = start;
while (now - start < ms) {
now = Date.now();
}
}
3.推荐方案:evaluate里面不做异步处理,而是通过返回一个信号或者html属性给外部 然后在外部处理你想要达成的效果,多次执行evaluate函数,就可以达到你的目的
注意点:evaluate函数内部使用xxx.click在一些网站会触发检测机制,比如京东,会提示你操作频繁,但是在正常打开浏览器京东页面各种暴力点击都不会触发(目前没有找到原因)
解决方案:通过递归机制检测点击是否成功,不会触发页面丢失之类的,经过本人测试可以正常运行
三、Page.goto或者Page.click访问页面或者跳转页面经常无效的问题
问题原因:goto打开界面,如果用延时来试图使他加载完成,经常出现找不到元素的情况,click也是
解决方案:
1.click通过Page.waitForSelector 函数解决:
await Page.click("#当前界面");
await Page.waitForSelector("#跳转之后界面按钮或者元素");
2.goto通过waitUntil 参数来解决:
await Page.goto("https://www.jd.com/", { waitUntil: 'networkidle2' })