以前我们说到爬取网页数据,你可能会第一时间想到scrapy,嗯,那个强大的python爬虫库,然而,有些时候,我们其实要爬取数据并非一定要使用这么强大【笨重】的库来实现,而且,某些时候,可能使用scrapy来爬取我们想到的数据,还比较困难。
举个例子:假如,我们想购买一台腾讯云CVM服务器,这时候你们团队肯定会有一个预算,这时候,可能你们PM想对比一下各种配置的价格,他发现去云官网上看会比较痛苦,需要点好多好多次,然后对比也没有那么直接,那么这时候,他可能会给你提一个需求。
比如,把各个Region的都爬出来,然后CPU的类型选择所有的类型,或者说还有一些杂七杂八的刷选条件,一言以蔽之,就是有些选项是默认,有些需要勾选指定项。
最终,需要将这么多分页数据都给爬出来。嗯,以上就是我们要做的事情。
那么,分析一下,有几个难点。
1、页面中有一些选项,需要我们选择,并非都是默认,所以,页面加载出来之后,我们需要选择。
2、其次,这个网页中的数据是异步加载的,可以使用curl一下网页,发现我们需要的数据并没有,是一个空架子而已。
3、这里面有分页数据,都爬取下来,举个例子,对于该页,我们需要从第1页点击到第
20页,然后把这些表格中的数据都捞下来。
所以,可以看下我们的任务,这对于选择scrapy来做的化,可能不是特别好实现,就拿页面中的一些form项中的勾选,选择,这点scrapy就并不是特别擅长。
所以,想一想,我们熟悉的什么库比较适合操作dom,然后拿dom中的内容呢?jQuery,很明显,jQuery就非常适合做这样的操作。
使用jQuery获取数据
使用jQuery爬取页面数据,主要要掌握以下几个基本的技能:
1、如何找到需要操作的form元素,然后利用click()方法,选中需要选择的项。
2、如何找到我们需要导出的数据。
3、如何在网页中导出json数据,(注意也可以是其他格式)。
然后我们分析一下,比如这个页面有10页,那其实就是写一个for循环。
代码语言:txt复制for (var i = 0; i < pageCount;i ){
nextPage.click()
collectData()
}
注意,这里的难点是,click选项之后,页面是需要一定的时间才能加载出数据的,所以,点击之后,我们并不能马上去拿数据,需要等页面加载数据成功,因此上面click之后,马上去搜索数据,很明显不对。
那么,该如何办呢?我们写一个等待函数?
代码语言:txt复制for (var i = 0; i < pageCount;i ){
nextPage.click()
wait(3000)
collectData()
}
function wait(ms){
var start = new Date().getTime();
var end = start;
while(end < start ms) {
end = new Date().getTime();
}
}
请注意,我一开始也是这么想的,但是,click()之后,页面卡死了,更本不是我们想象的效果,点击之后,刷新到下一页,让后,我们在这里等待个3s左右,让网络把数据加载好,但实际上这个点击之后的过程背后是需要执行js代码的,然而我们的wait函数没有给他那个机会,因此,你看到页面不会有任何变化。
所以,我们不能同步等待,需要异步等待。那么,如何异步等待呢?我想到了setTimeout
,
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
setInterval(travelPages,500)
function travelPages(){
if(!dataCollecteFinished) return
nextPage.click()
sleep(3000).then(collectData)
}
所以,这里for循环似乎并不好用了,为了异步,我使用了setInterval来代替循环,能执行循环中的条件是,我已经将上页加载的数据抓取完毕。
嗯,这个思路下来,我成功的完成了这个任务。
一些疑问
1、假如入目标页面没有jQuery怎么办,很简单,没有我们就给他注入jQuery,
代码语言:txt复制(function() {
var hm = document.createElement("script");
hm.src = "http://libs.baidu.com/jquery/2.0.0/jquery.min.js";
var s = document.getElementsByTagName("title")[0];
s.parentNode.insertBefore(hm, s);
})()
2、同样的道理,加入页面没有Promise啥的,都可以使用这种方式注入,但其实那里并没有必要使用Promise,直接写一个setTimeout也是可以的,但是注意全局污染(很可能同时多个搜集器在搜集数据,造成数据混乱,用Promise封装不仅仅是为了优雅,更多的是为了让垃圾回收器一起自动回收掉setTimeout)
3、如何在使用js导出json
代码语言:txt复制(function (console) {
console.save = function (data, filename) {
if (!data) {
console.error('Console.save: No data')
return;
}
if (!filename) filename = 'console.json'
if (typeof data === "object") {
data = JSON.stringify(data, undefined, 4)
}
var blob = new Blob([data], {
type: 'text/json'
}),
e = document.createEvent('MouseEvents'),
a = document.createElement('a')
a.download = filename
a.href = window.URL.createObjectURL(blob)
a.dataset.downloadurl = ['text/json', a.download, a.href].join(':')
e.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null)
a.dispatchEvent(e)
}
})(console)
4、如何把json文件转换为xsl,因为产品汪可能更喜欢看xsl
送你一个在线转的网址,https://json-csv.com/
总结
有时候,使用jQuery来爬取网页数据,也是很方便的,利用jQuery强大的查找dom元素,及操作dom元素的特性,实现起来可能要比scrapy简单的多。