使用puppeteer 上线到服务器填坑记录

背景:

一直想着在网上尝试爬虫服务,在去年的时候,由于自己服务器知识不足,导致自己对服务器运行puppeteer一直出错,后面也不了了之,这段时间又重新捡起来了,为了能够多学一些,多谁知一些.

排坑:

1.服务器无法正常启动无头chrome

await puppeteer.launch({headless:false});

哪怕把headless置为true,也一样无法正常启动

解决方案:

const browser = await puppeteer.launch({args: [‘–no-sandbox’, ‘–disable-setuid-sandbox’]});

方案可以去github的issues里面搜索一下

加上链接:https://github.com/puppeteer/puppeteer/issues/290

2.ubuntu安装无头浏览器需要各种插件

apt-get install -yq gconf-service libasound2 libatk1.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

要想正常使用puppeteer需要安装以上插件.可能在其它环境下也是需要安装相同插件.

3.开发中遇到的问题

由于自己想走全套流程,所以也有用到mysql,学习mysql 从不熟悉到慢慢会一点,成就感还是有的.下面就碰到了一个坑:

数据库里已经存在的更新,没有存在的则新加,开始用了on duplicate key update 这个语法,

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘”15414675859332.html”,”a”,”b”,”c”,”d” on duplicate key update href=values(href),’ at line 1

后面替换成 replace into

为什么替换,因为上面那个错误自己一直无法排查出来原因,不管在服务器上的mysql里输入同样的语法,还是在电脑端执行相同的语法均可以正常执行,但是一到服务上就不对了.

这个问题也是排查了很久,后面替换成 replace into后,才慢慢发现了问题:

‘replace into headList (imgId,src,alt,href,imgType) values ‘

后面的values后面是没有值的,为什么没有值?

最开始的时候以为是异步原因,以为是mysql删除了,后面经过排查是puppeteer上的坑,应该说是自己的经验不足,在服务器上拉取数据的时候,由于网络慢的原因,导致有时候数据没有出来 但是js代码已经执行完了,引起values为空的问题,所以在服务器上使用puppeteer也要充分考虑到网络的因素,具体代码如下:

while(true){
        await page.waitFor(1000);
        await page.waitFor('.m_txul>li .img');
        const ele = await page.$$eval('.m_txul>li .img',((eles,imgType) =>{
          const array = [];
          let str = '';
          for(let i = 0;i<eles.length;i++){
            const href = eles[i].href;
            const imgId = href.match(/.*?([\d]*.html)/);
            array.push({
              src:eles[i].children[0].src,
              alt:eles[i].children[0].alt,
              href:eles[i].href,
              imgId,
              id:i
            });
            if(i === eles.length - 1){
              str+= `("${imgId[1]}","${eles[i].children[0].src}","${eles[i].children[0].alt}","${eles[i].href}","${imgType}")`
            }else{
              str+= `("${imgId[1]}","${eles[i].children[0].src}","${eles[i].children[0].alt}","${eles[i].href}","${imgType}"),`     
            }
          }
          return str
        }),urlObj.imgType);
        await page.evaluate(() => {
          return new Promise(async (resolve, reject) => {
            const height = document.querySelector('html').scrollHeight;
            const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
            for (let i = 0; i < height; i+=100) {
              await delay(200)
              window.scroll(0, i);
            }
             resolve();
          })
        });
        if(ele){
          const sql = `replace into headList (imgId,src,alt,href,imgType) values ${ele}`
          // const sql = `insert into headList (imgId,src,alt,href,imgType) values ${ele} on duplicate key update href=values(href),src=values(src),alt=values(alt),imgType=values(imgType)`
          console.log(`更新次数:${num++}`);
          await exec(sql)
        }
        const bool = await page.$eval('.pagination>ul a:nth-last-child(2)',ele => {
          return ele.innerText === '下一页'
        });
        if(!bool){
          break;
        }else{
          await page.click('.pagination>ul a:nth-last-child(2)');
        }
        // num--
      }

总结:

功能不多,但是对我来说是一个新东西,并且是一个非常值得学习的技能,虽然有一定的坑,但是还是很开心能够入门这个技能

发表评论

您的电子邮箱地址不会被公开。