简单网络爬虫实现
背景
有个朋友需要将湖北碳排放权交易中心的成交概况数据总揽表.有将近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')
})()
})()
结语
随手写的, 代码比较简单, 凑合看吧. 并不是多了几个文件夹名称就是架构好吗>_<