这段时间公司在做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' })

 (未完待续)