demo截圖:
本demo爬瓜子二手車北京區的數據 (注:需要略懂 node.js / mongodb 不懂也沒關系 因為我也不懂啊~~~)
之所以選擇爬瓜子二手車網站有兩點:
一、網站無需登錄,少做模擬登錄;
二、數據鏈接沒有加密,直接可以用;
網上很多node.js爬蟲的栗子
但大多是一個頁面的栗子,很少跟數據庫結合的 所以我這個栗子是糖炒的
我的基本思路是這樣的
1、先在mongodb里存所有頁的鏈接地址的集合
2、在根據這些鏈接地址 一個一個的把詳細信息爬下來
第一步在搜索頁找到翻頁的規律
像搜索頁北京區第一頁就是
https://www.guazi.com/bj/buy/o1/
第二頁
https://www.guazi.com/bj/buy/o2/
規律就是
https://www.guazi.com/bj/buy/o + number
然后第一頁的時候你就可以知道最多50頁
這樣你就可以循環這些鏈接在把每個頁面的車的詳情鏈接存到mongodb的集合里
第二步讀mongodb的集合找出所有的鏈接 循環鏈接爬詳情頁數據
項目目錄:
目錄講解:
reptile.js //爬所有鏈接的;
carinfo.js //爬車輛詳情頁;
package.json //配置文件
package.json:
1 { 2 "name": "sell-car", 3 "version": "1.0.0", 4 "description": "", 5 "main": "index.js", 6 "scripts": { 7 "test": "echo \"Error: no test specified\" && exit 1" 8 }, 9 "author": "", 10 "license": "ISC", 11 "devDependencies": { 12 "cheerio": "^0.22.0", 13 "mongoose": "^4.7.1" 14 } 15 }
reptile.js 存mongodb集合 在cmd執行的 node reptile.js
1 'use strict'; 2 var http = require('https'); //node https 模塊; 3 var cheerio = require('cheerio'); //解析html模塊; 4 var mongoose = require('mongoose'); //操作mongodb數據庫模塊; 5 mongoose.connect('mongodb://localhost/car'); //鏈接數據庫; 6 7 var num = 0; //當前第幾頁; 8 var maxNum = 0; //最大頁數; 9 10 var url = 'https://www.guazi.com/bj/buy/o'; //瓜子二手車搜索頁北京區; 11 12 var PersonSchema = new mongoose.Schema({ //json的結構; 13 address:String //定義一個屬性name,類型為String 14 }); 15 16 var sellCar = mongoose.model('sell_car', PersonSchema ); //創建model 17 18 19 fetchPage(url+1); //主程序開始運行 20 21 function fetchPage(x) { //封裝了一層函數 22 startRequest(x); 23 } 24 25 function startRequest(x) { 26 //采用http模塊向服務器發起一次get請求 27 http.get(x, function (res) { 28 29 var html = ''; //用來存儲請求網頁的整個html內容 30 var titles = []; 31 res.setEncoding('utf-8'); //防止中文亂碼 32 //監聽data事件,每次取一塊數據 33 res.on('data', function (chunk) { 34 35 html += chunk; 36 37 }); 38 39 //監聽end事件,如果整個網頁內容的html都獲取完畢,就執行回調函數 40 res.on('end', function () { 41 42 var $ = cheerio.load(html); //采用cheerio模塊解析html 43 44 var $a_src = $('.imgtype'); //讀取出當前搜索頁每輛車詳情的地址; 45 46 $a_src.each(function(i,obj){ //循環每地址鏈接存入數據庫; 47 48 var _src = $(obj).attr('href'); 49 50 51 var carHref = new sellCar({ address: _src }); //存入mongodb; 52 carHref.save(function (err) { 53 if (err) { 54 console.log(err); 55 } 56 }); 57 58 }) 59 60 num++; //頁碼增加; 61 62 if( num == 1 ){ //判斷是第一次,給最大頁數賦值; 63 maxNum = $('.pageLink li').eq($('.pageLink li').length-2).find('span').text(); 64 } 65 66 if( num == maxNum ){ //頁數等於最大頁數等值程序; 67 return ; 68 } 69 70 fetchPage(url+num); 71 72 }); 73 74 }); 75 }
carinfo.js 車輛詳情 在cmd執行 node carinfo.js
1 'use strict'; 2 var http = require('https'); //node https 模塊; 3 var cheerio = require('cheerio'); //解析html模塊; 4 var mongoose = require('mongoose'); //操作mongodb數據庫模塊; 5 mongoose.connect('mongodb://localhost/car'); //鏈接數據庫; 6 7 var readCarPer = new mongoose.Schema({ //json的結構; 8 address:String 9 }); 10 11 var PersonSchema = new mongoose.Schema({ //定義json類型; 12 info:String, //車; 13 money:String, //價錢; 14 phone:String, //電話號碼; 15 time:String, //上牌時間; 16 mileage:String, //公里數; 17 gearbox:String, //變速箱; 18 emission:String, //排放標准; 19 location:String, //上牌地; 20 imgs:Array //圖片; 21 }); 22 23 var num = 0; 24 var readCar = mongoose.model('sell_cars',readCarPer); 25 var sellCarInfo = mongoose.model('sell_carInfo', PersonSchema ); 26 27 var json = null; 28 var url = 'https://www.guazi.com'; //補鏈接前邊的鏈接; 29 var time = null; //間隔時間; 30 var maxNum = 0; 31 32 33 readCar.find({},function(err, character){ //查找數據; 34 35 console.log('成功讀取地址'); 36 37 if(err){ 38 console.log(err); 39 }else{ 40 json = character; 41 maxNum = json.length; 42 43 calls(); 44 45 } 46 47 }) 48 49 50 function calls(){ 51 num++; 52 if( num > maxNum ){ //判斷是否霸區成功; 53 console.log('數據爬去完成~~~'); 54 return false; 55 } 56 57 clearTimeout(time); 58 var lu = json[num].address; 59 60 time = setTimeout(function(){ 61 62 fetchPage(url+lu); //主程序開始運行 63 64 },5000); 65 66 } 67 68 function fetchPage(x) { //封裝了一層函數 69 startRequest(x); 70 } 71 72 function startRequest(x) { 73 console.log(x); 74 //采用http模塊向服務器發起一次get請求 75 http.get(x, function (res) { 76 77 var html = ''; //用來存儲請求網頁的整個html內容 78 var titles = []; 79 res.setEncoding('utf-8'); //防止中文亂碼 80 //監聽data事件,每次取一塊數據 81 res.on('data', function (chunk) { 82 83 html += chunk; 84 85 }); 86 87 //監聽end事件,如果整個網頁內容的html都獲取完畢,就執行回調函數 88 res.on('end', function () { 89 90 var $ = cheerio.load(html); //采用cheerio模塊解析html 91 92 var info = $('.dt-titletype').text() //車名; 93 var money = $('.numtype').text(); //錢; 94 var phone = $('.teltype').eq(0).text(); //電話 95 var time = $('.assort li').eq(0).find('b').text(); //上牌時間 96 var mileage = $('.assort li').eq(1).find('b').text(); //里程數 97 var gearbox = $('.assort li').eq(2).find('b').text(); //變速箱 98 var emission = $('.assort li').eq(3).find('b').text(); //排放標准 99 var location = $('.assort li').eq(4).find('b').text(); //上牌地 100 101 var $imgs = $('.dt-pictype img'); 102 var imgs = []; 103 104 $imgs.each(function(i,obj){ //圖片循環賦值; 105 var img_src = $(obj).attr('data-original'); 106 imgs.push(img_src); 107 }); 108 109 var carInfos = new sellCarInfo({ //保存數據; 110 info:info, 111 money:money, 112 phone:phone, 113 time:time, 114 mileage:mileage, 115 gearbox:gearbox, 116 emission:emission, 117 location:location, 118 imgs:imgs 119 }); 120 121 carInfos.save(function (err) { 122 if (err) { 123 console.log(err); 124 } else { 125 console.log('成功數據!~~~'); 126 calls(); 127 } 128 }); 129 130 }); 131 132 }); 133 }
當時爬數據的截屏:
后記:
這里我沒說 mongodb 安裝、啟動、設置存儲地址 是因為 mongodb本身在window和mac其實是不一樣的所以需要你自己在找找別的文章看看怎么配置(注:window跑真的挺蛋疼的。。。。歡迎去感受一下)
這個栗子的第一個條件就是你要現在cmd里跑起來mongodb 要不剩下的都是白瞎
簡單的mongodb的增刪改查看看 菜鳥教程 就行 實在不行用Robomongo圖形界面也行
說一個小問題
就是我在爬搜索的車輛鏈接的時候 因為下一頁設置的間隔時間比較短 原本2000條的數據最后只爬下來1160,所以爬車輛詳情的時候把間隔調成了5秒 需要注意一下;
如圖:
參考資料:
小小石頭的那些事兒 : http://blog.csdn.net/yezhenxu1992/article/details/50820629