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对于爬取这种以前很难爬取的单页面应用来说,确实提供了不少便利。
  • 相关阅读:
    实验三 进程调度模拟程序
    实验二作业调度模拟程序
    最新广商小助手 项目进展 OpenGL ES 3D在我项目中引用 代码太多只好选重要部分出来
    最后冲刺 我的项目 广商小助手
    最新一课 老师指点用Listview适配器
    安卓小学生四则运算
    大三上学期安卓一边学一边开始做一个自己觉得可以的项目 广商小助手App 加油
    我要再接再力 学更多
    用场景来规划测试工作
    阅读第13,14,15,16,17章
  • 原文地址:https://www.cnblogs.com/aloneMing/p/13476744.html
Copyright © 2011-2022 走看看