最近需要對某消防網站進行宣傳力度區域進行統計,使用一般采用的http模塊進行數據抓取的時候發現結果是亂碼,翻看原網站才發現,該消防網站是gb2312的編碼,而http模塊爬出的數據不能進行gbk解析,因此本片文章主要為解決用node對網站編碼為gb2312爬蟲時得到亂碼這一問題。
1. 使用工具:webstorm,node開發神器,強烈推薦
2. 再說思路:先對新聞列表頁面進行爬蟲,再對抓到的鏈接一一進行目標網頁的標題顯示和新聞來源的統計,本頁面新聞統計完畢后再跳轉下一頁,重新進行該過程。
備注:至於為什么不采用的“先對一篇文章進行目標內容獲取,再對‘下一篇’進行地址獲取”這個方式,是因為,該消防網站的下一篇與新聞列表順序不符 /手動微笑臉
3. 代碼如下:
1 var http = require("http"); 2 var fs = require("fs"); 3 var cheerio = require("cheerio"); 4 var charset = require("superagent-charset"); 5 var agent = require("superagent"); 6 charset(agent); // 7 8 var obj = {}; 9 10 var page = 1; // 開始頁碼 11 var MAXPAGE = 38; // 結束頁碼 12 13 var num = 0; // 記錄條數 14 15 var url = "http://www.cqfire.com/xxzx/news.asp?class1=%D0%C2%CE%C5%D6%D0%D0%C4&class2=%CA%D0%C4%DA%D0%C2%CE%C5"; 16 17 startRequest(url + "&PageNo=" + page, 0); 18 function startRequest(site, flag){ 19 var html = ''; 20 var resStr = ''; 21 agent.get(site).charset('gbk').end((err, res) => { 22 html = res.text; 23 var $ = cheerio.load(html); // 采用cheerio模塊解析html 24 25 if(flag == 0){ 26 // 如果flag為0,表示列表頁面,需要對頁面進行解析 27 var eles = $("a").not(".nav_menu").not(".left_menu_class").not(".copy_menu"); 28 for(var i = 0 ; i < eles.length; i ++){ 29 // 將提取出a中的url傳入flag為1的本方法中 30 var target = "http://www.cqfire.com/" + eles.eq(i).attr("href"); 31 startRequest(target, 1); 32 } 33 34 if(page < MAXPAGE){ 35 // 如果未達到最大頁數,則進行下一頁,傳入flag為0 36 page ++; 37 console.log(url + "&PageNo=" + page); 38 startRequest(url + "&PageNo=" + page, 0); 39 } 40 }else{ 41 // 如果flag為1,則表示為具體新聞頁面,需要對標題和來源進行提取 42 // 獲取新聞標題 43 var title = $("span.STYLE2").text().trim(); 44 // 獲取新聞來源 45 var origin = $("span.STYLE2").parent().parent().parent().parent().parent().next().find("td[align='middle']").text().trim(); 46 var from = origin.split(" ")[0].split(":")[1]; 47 48 num++; // num表示當前新聞的條數 49 console.log(num +"-->"+title); 50 51 // 將來源為key,統計個數為value存入結果對象中 52 if(!obj[from]){ 53 obj[from] = 0; 54 } 55 obj[from] += 1; 56 57 for(var key in obj){ 58 resStr += key + '\t' + obj[key] + '\n'; 59 } 60 // 將結果以字符串的形式存入txt中,這里要使用同步方法,否則輸出會出現很多null,但是txt文檔中統計結果與同步方法一致,這里不解 61 fs.writeFileSync('./data/result.txt', resStr, 'utf-8', function (err) { 62 console.log(err); 63 }) 64 } 65 66 }) 67 68 }
4. 使用的是superagent,superagent-charset兩個插件,在第21行使用charset()方法,也可以不傳入參數表示自動檢測網頁的編碼方式;
5. 利用cheerio包對目標網頁DOM結構進行解析,獲取目標內容的方法與jQuery方法一致
總結:
利用node進行爬蟲的關鍵點有三點:
1. 如何獲取“下一頁”的地址,本方法中使用的網頁中國PageNo參數,這一點需要在確定爬蟲方式之后,找到規律
2. 在目標頁如何獲取目標內容,這需要對文檔結構進行觀察,本方法中使用的cherrio包,其獲取目標內容的方法與jQuery一致,也是node爬蟲的主流選擇
3. 如何結束遞歸,本方法是確定最大頁數,也可以設置最大條數,也可以進行手動結束遞歸,但要注意做好已經爬好的數據的記錄