zoukankan      html  css  js  c++  java
  • Puppeteer爬取单页面网站的数据示例

    场景

    • 昨天试了一下爬取根据网页查询参数的不同而变化的页面,今天来试试爬取单页面应用,url不发生变化,只是页面内的按钮点击导致数据的重新请求。

    主要实现思路

    • 利用Puppeteer可以模拟用户点击操作,等待接口返回等各种优秀的API,可以保证在数据结束后完成页面数据提取。

    代码实现,以开源众包的页面为例

    • 开源众包这个页面挺适合用来做示例,因为通过下一页的按钮去调用ajax请求,当到达最后一页时,下一页按钮会自动有一个disabled属性,我们就可以根据这个disabled属性来判断是否还有下一页。
    const common = async (workFunc) => {
      const startTime = +new Date();
      console.log(`进入方法`);
      const browser = await puppeteer.launch();
      const page = await browser.newPage();
      typeof workFunc === 'function' && await workFunc(page);
      await page.close();
      await browser.close();
      console.log('方法结束,耗费时长:', +new Date() - startTime);
    };
    const crawler = async (url, selectors) => {
      const list = [];
      await common(async (page) => {
        await page.goto(url);
        async function runOnce() {
          const result = await page.evaluate((selectors) => {
            const res = [];
            selectors.forEach(selector => {
              const { key, value, field } = selector;
              const domList = document.querySelectorAll(value);
              Array.prototype.slice.apply(domList).forEach((dom, index) => {
                const newVal = dom[field] || dom.innerText;
                res[index] = res[index] || {};
                res[index][key] = newVal;
              })
            })
            return res;
          }, selectors);
          list.push(...result);
          const disabled = await page.$eval('.btn-next', el => el.disabled);
          console.log('一页数据已获取,当前下一页按钮状态:', result[0], disabled);
          if (!disabled) {
            // 触发按钮点击,使用page.click就是不能触发按钮的点击,只能用这个骚操作
            await page.$eval('.btn-next', el => el.click());
            // 等待接口完成
            await page.waitForResponse(response => {
              return response.url().includes('contractor-browse-project-and-reward') && response.status() === 200;
            })
            await runOnce();
          }
        }
        await runOnce();
      })
      return list;
    }
    
    // 使用
    const url = 'https://zb.oschina.net/projects/list.html';
    const selectors = [
      {
        key: 'title',
        value: '.el-row .title',
        field: 'innerText'
      },
      {
        key: 'tags',
        value: '.el-row .tags',
        field: 'innerText'
      },
      {
        key: 'money',
        value: '.el-row .money',
        field: 'innerText'
      },
      {
        key: 'skills',
        value: '.el-row .skills',
        field: 'innerText'
      },
      {
        key: 'bidding',
        value: '.el-row .bidding',
        field: 'innerText'
      },
      {
        key: 'pubtime',
        value: '.el-row .pubtime',
        field: 'innerText'
      }
    ];
    
    crawler(url, selectors).then(result => {
      console.log(result);
      fs.writeFile('项目.json', JSON.stringify(result), 'utf-8', err => {
        if(err) {
          console.log(err);
          return;
        }
      });
    })
    

    结果展示

    -

    小结

    • 不得不承认,Puppeteer对于爬取这种以前很难爬取的单页面应用来说,确实提供了不少便利。
  • 相关阅读:
    第0课
    学前班-怎么看原理图
    LCD-裸机韦东山
    学前班
    专题8-Linux系统调用
    专题4-嵌入式文件系统
    网络编程 之 软件开发架构,OSI七层协议
    反射、元类,和项目生命周期
    多态、魔法函数、和一些方法的实现原理
    封装,接口,抽象
  • 原文地址:https://www.cnblogs.com/aloneMing/p/13476744.html
Copyright © 2011-2022 走看看