背景

有个朋友需要将湖北碳排放权交易中心的成交概况数据总揽表.有将近2000页的数据, 如果考人工一个一个去复制粘贴, 估计她会砸电脑吧. 就是这个网页的表格内容: http://www.hbets.cn/index.php/index-show-tid-11.html

目标

把这个页面的所有页数据塞到一个excel里面

爬取原理

使用headless浏览器模拟人工将所有页面打开, 然后去抓取对应dom节点文本数据.支持这个操作的框架有很多, nightmare, phantomjs, puppeteer等, pyhon 环境下有 robot Framework. 这几个都有尝试过, 最后选用pupeteer. robot framework 简直就是反人类.前面三个都是nodejs环境运行的. 然, puppeteer 是google开源的, 同时, await async 加持, JS 开发者都知道这意味着什么.

核心代码

const puppeteer = require('puppeteer'),
  fs = require('fs'),
  $ = require('jquery'),
  path = require('path');
const XLSX = require("xlsx");
const WorkBook = require("./workbook");
let bigSheet = [
  ['试点地区', '成交价', '当日成交量( 吨)', '当日成交额( 元)', '日期']
];

(async () => {
  const browser = await puppeteer.launch({
    executablePath: 'D:/Users/steven.zhu/AppData/Local/Chromium/Application/chrome.exe',
    headless: true,
  });

  let getOnePage = async (url, maxPage) => {

    const page = await browser.newPage();
    await page.goto(url, {
      waitUntil: 'networkidle2'
    });

    await page.setJavaScriptEnabled(true);
    // await page.screenshot({
    //   path: 'hn.png',
    //   format: 'A4'
    // });
    await page.waitFor(1200);


    let oneSheet = await page.evaluate(() => {
      let sheet = [];
      let uls = $(".future_table ul.cont");
      uls.each((i, obj) => {
        console.log(i, obj)
        let one = [];
        one.push($(".future_table ul.cont").eq(i).find('.li1').html());
        one.push($(".future_table ul.cont").eq(i).find('.li2').html());
        one.push($(".future_table ul.cont").eq(i).find('.li3').html());
        one.push($(".future_table ul.cont").eq(i).find('.li4').html());
        one.push($(".future_table ul.cont").eq(i).find('.li5').html());
        sheet.push(one);
      });

      return sheet;;
    });

    bigSheet = [].concat(bigSheet, oneSheet)

    page.once('load', () => console.log('Page loaded!'));

    await page.close()
    url.match(/&p=(\w*)$/)
    if (RegExp.$1 == maxPage){
      await setTimeout(()=>{
         browser.close();
      },5000)
    }

  };
  (async () => {

    let getAllPage = (i, maxPage) => {
      console.log('抓取进度:', i + '/' + maxPage)
      getOnePage(
        "http://www.hbets.cn/index.php/index-show-tid-11.html?&p=" + i,
        maxPage
      );
      if (i <= maxPage) {
        setTimeout(() => {
          getAllPage(++i, maxPage)
        }, 1000)
      } else {
        console.log('>>>>', bigSheet)
        workbook = new WorkBook({
          Sheet1: bigSheet
        })
        workbook.writeFile('xxx.xlsx')
      }
    }
    getAllPage(1, 1000)
    console.log('hehe')

  })()
})()

结语

随手写的, 代码比较简单, 凑合看吧. 并不是多了几个文件夹名称就是架构好吗>_<

源代码

https://github.com/cnvoid/web-crawler