Node.js可能是最適合寫簡易小爬蟲的語言,速度極快、程式碼極少

Nothlu發表於2019-04-06

“凡是能用JS 寫出來的,最終都會用JS 寫”,這是一個非常著名的定律,用在爬蟲這裡再合適不過了。

一說到爬蟲很多人都會想到python,的確,python語法簡潔,還有scrapy這一類強大的工具可以使用。

但是如果只是想寫一個小爬蟲,爬取論壇裡的幾張帖子,帖子裡面的幾個樓層,然後合成一篇文章。這點小資料量使用scrapy就有點殺雞用牛刀了,而且還得設定一堆東西,非常麻煩,不夠靈活。

而JavaScript就非常適合這一類小爬蟲,首先是自帶非同步架構,能同時爬取多張網頁內容,效率上來說比python高多了,我用兩個語言寫過爬取代理ip的爬蟲,當JavaScript爬完時嚇了我一跳,這速度快極了。

當然,python也可以通過開啟多執行緒、多協程來實現同時爬取多張網頁,但是這就比預設就非同步的JavaScript麻煩多了。

所以,如果想簡單、高效地寫個小爬蟲,非JavaScript莫屬。

有多快多簡單呢?現在就來寫個豆瓣top250的爬蟲,爬取10張網頁,250部電影的名字、評分和封面地址;

1.如何安裝

要通過js寫爬蟲,需要用到三個模組,request、cheerio和fs,其中fs內建了,只需要安裝前兩個即可,安裝命令:

npm install request cheerio
複製程式碼

2.獲取網頁內容

request可以連結網頁,爬取內容,這裡我們只需要給它傳遞兩個引數就行,一個為url(網址),另一個為回撥函式; request會向回撥函式傳遞三個引數,分別是error(錯誤資訊),response(響應資訊),body(網頁內容):

var request = require('request')
var cheerio = require('cheerio')
var fs = require('fs')
var movies = []

var requstMovie = function(url){
	request('https://movie.douban.com/top250',function(error, response, body)){
		//res.statusCode 為200則表示連結成功
		if(error === null && response.statusCode === 200){
			console.log('連結成功')
			//使用cheerio來解析body(網頁內容),提取我們想要的資訊
			var e = cheerio.load(body)
			
			//通過分析網頁結構,我們發現豆瓣每部電影都通過item屬性隔開
			var movieDiv = e('.item')
	
			//通過for迴圈來提取每部電影裡的資訊
			for (let i = 0; i < movieDiv.length; i++) {
					//takeMovie函式能提取電影名稱、評分和封面
	                let movieInfo = takeMovie(movieDiv[i])
	                log('正在爬取' + movieInfo.name)
	                //將提取到的電影放入陣列
	                movies.push(movieInfo)
	            }
		}
	})
}
複製程式碼

3.提取電影資訊

通過建立一個類來包含我們想要的屬性,在每次呼叫takeMovie函式提取資訊時都會初始化這個類,然後賦值給相應的屬性; 之後放入movies陣列裡;

//電影的類
var movie = function(){
    this.id = 0
    this.name = ''
    this.score = 0
    this.pic = ''
}

var takeMovie = function(div){
    var e = cheerio.load(div)
    //將類初始化
    var m = new movie()
    m.name = e('.title').text()
    m.score = e('.rating_num').text()
    var pic = e('.pic')
    //cheerio如果要提取某個屬性的內容,可以通過attr()
    m.pic = pic.find('img').attr('src')
    m.id = pic.find('em').text()
    return m
}
複製程式碼

4.爬取所有top250

現在要爬取所有的top250資訊,總共有10張網頁,每張包含25部電影資訊,建立一個函式來生成每張網頁的網址,然後通過request進行爬取:

var top250Url = function(){
    let l = ['https://movie.douban.com/top250']
    var urlContinue = 'https://movie.douban.com/top250?start='
    let cont = 25
    for (let i = 0; i < 10; i++) {
        l.push(urlContinue+cont)
        cont += 25
    }
    return l
}

//爬取所有網頁
var __main = function(){
    var url = top250Url()
    for (let i = 0; i < url.length; i++) {
        requstMovie(url[i])
    }
}

__main()
複製程式碼

5.非同步架構的坑

當我們爬取完所有的網頁後就會發現,movies裡的電影資訊並不按我們爬取的順序,這也是非同步架構一個需要注意的大坑; 在爬取第一張網頁時,JavaScript不會等到處理結束才接著爬第二張,有時候各個網頁返回的速度有所差異,會造成先爬取的不一定會先出結果,因此在電影排序上會出現混亂; 所以我們還需要對爬取下來的內容重新進行排序,然後儲存:

//sortMovie回撥函式能比較兩個物件屬性大小
var sortMovie = function(id){
    return function(obj ,obj1){
        var value = obj[id]
        var value1 = obj1[id]
        return value - value1
    }
}

//儲存檔案
var saveMovie = function(movies){
    var path = 'movie.txt'
    var data = JSON.stringify(movies, null, 2)
    fs.appendFile(path, data, function(error){
        if(error == null){
            log('儲存成功!')
        } else {
            log('儲存失敗',error)
        }
    })
}
複製程式碼

我們需要等到所有網頁都爬取分析完才執行sortMovie和saveMovie函式,由於JavaScript是非同步,即使這兩個函式放在最底部也會在分析完之前執行; 一般會通過Promise來控制非同步,但是為了方便,這裡我們通過if來判斷,在每次爬取網頁後,都會判斷movies裡是否包含250條資訊,如果有則說明全部爬取到了:

var requstMovie = function(url){
    request(url, function(error, response, body){
        if (error === null && response.statusCode === 200){
            var e = cheerio.load(body)
            var movieDiv = e('.item')
            for (let i = 0; i < movieDiv.length; i++) {
                let movieInfo = takeMovie(movieDiv[i])
                log('正在爬取' + movieInfo.name)
                movies.push(movieInfo)
            }
            //判斷movies數量
            if (movies.length === 250){
            	//通過sort將陣列內每兩個元素放入比較函式
                var sortM = movies.sort(sortMovie('id'))
                //儲存檔案
                saveMovie(sortM)
            }
        } else {
            log('爬取失敗', error)
        }
    })
    
}
複製程式碼

到這裡,爬蟲已經寫完了,來執行一下:

Node.js可能是最適合寫簡易小爬蟲的語言,速度極快、程式碼極少

完整程式碼可以通過github檢視:DoubanMovies.JS

也可以訪問我的網站,獲取更多文章:Nothlu.com

相關文章