Nodejs爬蟲——機票查詢學習筆記(1).md

2017.3.6 - 3.17

學習內(nèi)容:

  • 學習nodejs數(shù)據(jù)挖掘基本想法
  • 熟悉superagent模塊的基本接口
  • 熟悉cheerio模塊的基本接口
  • 學習范例挖掘Cnode首頁信息
  • eventproxy模塊學習
  • async模塊學習
  • js變量提升
  • 模擬post請求與get請求

詳細筆記:

1. 基本想法

nodejs項目通過superagent模塊包向網(wǎng)站發(fā)起有(或無)參數(shù)的get/post請求,獲取目標網(wǎng)頁的html源代碼
——>使用cherrio模塊包分析前一步抓取的html,使用方法類似Jquery
——>保存json數(shù)據(jù)到文本

2. superagent模塊接口整理

參考文獻:superagent文檔 整理稿
一個用于發(fā)起get/post請求的https模塊包

3. cherrio模塊接口整理

一個用于抓取當前頁面信息的模塊包

4. 簡單抓取頁面信息的核心代碼 ——————挖掘Cnode首頁
//通過get請求抓取
router.get('/', function(req, res, next) {
    superAgent.get('https://cnodejs.org/')
      .end(function (err, sres) {
        if(err){
          return next(err);
        }
        // sres.text 里面存儲著網(wǎng)頁的 html 內(nèi)容,將它傳給 cheerio.load 之后
        // 就可以得到一個實現(xiàn)了 jquery 接口的變量,我們習慣性地將它命名為 `$`
        var $ = cherrio.load(sres.text);
        var items = [];
        $('#topic_list .topic_title').each(function (idx, element) {
          // 對每一個查找到的結(jié)果(idx, element),存入items數(shù)組?中
          var $element = $(element);
          items.push({
                  title: $element.attr('title'),
                  href: $element.attr('href'),
                });
        });
        res.send(items);
      })
});  
5. js變量聲明提升,賦值不提升

參考博客:js中的變量提升hoisting
總結(jié):
JavaScript是函數(shù)級作用域(function-level scope)。只有在函數(shù)中才會創(chuàng)建新的作用域(適用局部變量)。

// 初始代碼
var v='Hello World';
(function(){
    alert(v);
    var v='I love you';
})()
// 運行結(jié)果  : 彈出 undefined
// 實際運行過程
var v='Hello World';
(function(){
    var v;              //變量聲明被提升
    alert(v);
    v='I love you';     //變量賦值未提升
})()
//對于函數(shù)級作用域的理解
function foo() {
    var x = 1;
    if (x) {
        (function () {
            var x = 2;
            // some other code
        }());
    }
    // x is still 1.     //匿名函數(shù)中的作用域與foo函數(shù)的作用域無關(guān)
}
6. eventproxy模塊包API整理

一個用于監(jiān)聽多個函數(shù)并發(fā)執(zhí)行的模塊報(類似于計數(shù)器,等所有監(jiān)聽事件都冒泡表示完成,在執(zhí)行callback)
eventproxy——API

  • 注冊單個異步并發(fā):
    ep.all('tpl', 'data', function (tpl, data) {})
    所有監(jiān)聽事件完成后觸發(fā)callback

  • 注冊重復異步并發(fā):
    ep.after('got_file', files.length, function (list) {})
    監(jiān)聽事件重復指定次數(shù)后,觸發(fā)callback

  • 注冊持續(xù)異步并發(fā):
    ep.tail('tpl', 'data', function (tpl, data) {})
    在所有監(jiān)聽事件執(zhí)行后,觸發(fā)callback;監(jiān)聽事件再次更新,仍然觸發(fā)callback

7. async模塊API整理
  • 流程控制:簡化十種常見流程的處理
    --- series(tasks, [callback]) (多個函數(shù)依次執(zhí)行,之間沒有數(shù)據(jù)交換)
    有多個異步函數(shù)需要依次調(diào)用,一個完成之后才能執(zhí)行下一個。各函數(shù)之間沒有數(shù)據(jù)的交換,僅僅需要保證其執(zhí)行順序。
    --- parallel(tasks, [callback]) (多個函數(shù)并行執(zhí)行)
    并行執(zhí)行多個函數(shù),每個函數(shù)都是立即執(zhí)行,不需要等待其它函數(shù)先執(zhí)行。傳給最終callback的數(shù)組中的數(shù)據(jù)按照tasks中聲明的順序,而不是執(zhí)行完成的順序。
    如果某個函數(shù)出錯,則立刻將err和已經(jīng)執(zhí)行完的函數(shù)的結(jié)果值傳給parallel最終的callback。其它未執(zhí)行完的函數(shù)的值不會傳到最終數(shù)據(jù),但要占個位置。
    --- waterfall(tasks, [callback]) (多個函數(shù)依次執(zhí)行,且前一個的輸出為后一個的輸入)
    與seires相似,按順序依次執(zhí)行多個函數(shù)。不同之處,每一個函數(shù)產(chǎn)生的值,都將傳給下一個函數(shù)。如果中途出錯,后面的函數(shù)將不會被執(zhí)行。錯誤信息以及之前產(chǎn)生的結(jié)果,將傳給waterfall最終的callback。

  • 集合處理:如何使用異步操作處理集合中的數(shù)據(jù)
    forEach:對集合中每個元素進行異步操作
    map:對集合中的每個元素通過異步操作得到另一個值,得到新的集合
    filter:對集合中元素使用異步操作進行篩選,得到符合條件的集合
    reject:與filter相似,只是判斷條件時正好相反,得到剩下的元素的集合
    reduce:使用一個初始值同集合中每一個元素進行異步操作,最后得到一個唯一的結(jié)果
    detect:得到集合中滿足條件的第一個數(shù)據(jù)
    sortBy:對集合中的數(shù)據(jù)進行異步操作,再根據(jù)值從小到大排序
    some/any:集合中是否有至少一個元素滿足條件
    every/all:集合中是否每個元素都滿足條件
    concat:對集合中的元素進行異步操作,將結(jié)果集合并成一個數(shù)組

  • 工具類:幾個常用的工具類

8. 定時抓取補充

https://github.com/node-schedule/node-schedule

9. jqury的API

$.map() 遍歷
$.trim() 字符串去首位的空格

10. 爬蟲相關(guān)的模塊介紹

爬蟲相關(guān)模塊
express框架詳細總結(jié)

11. 模擬post請求與get請求 規(guī)范整理
//模擬發(fā)起get請求
superAgent.get('http://flight.qunar.com/twell/flight/inter/search')
    .query(queryString)
    .set(headers)
    .end(function (err, res) {
        if (res.error)
            throw new Error(res.error);
        console.log(res.body);
    });

****在get請求中需要注意的地方:****  
1. 在chrome檢查——network——headers中查到看的request URL要去除查詢參數(shù)(?search/departCity=XXXXX等)  
2. 在.query中發(fā)送查詢參數(shù),對應的post方法則是用send(data)的方式發(fā)送參數(shù)  
//模擬發(fā)起post請求
superAgent.post('http://flights.ctrip.com/international/AjaxRequest/SearchFlights/AsyncSearchHandlerSOAII.ashx')
    .set(ctripHeaders)
    .type('form')
    .send(data)
    .end(function (err, res) {
        // res是json對象
        if (err){
            return console.error(err);
        }
        console.dir(res.body);
    })

****在post請求中的注意:****
1. 在chrome檢查——network中找準發(fā)起請求的URL,并且保證req的參數(shù)完整且正確  
2. 在發(fā)送數(shù)據(jù)前通過.type('form') 聲明發(fā)送數(shù)據(jù)的格式  
3. 注意返回數(shù)據(jù)的解析

json文件讀寫
sublime中的json格式化插件—— pretty json

遇到的問題

Q1:一個json數(shù)組在debug時,可以取到其中的值,但是在實際運行中,出現(xiàn)Cannot read property 'href' of undefined
A1:- id重復,找不到dom或找錯dom

  • 數(shù)組越界,導致在debug時的前幾輪循環(huán)中可取,在整體運行中出錯。
  • 重點理解nodejs的異步機制!需要在回調(diào)函數(shù)中操作dom,以防還未捕捉到dom
    —————————
    Q2:get請求抓取信息的數(shù)據(jù)結(jié)構(gòu)失敗
    A2:出于安全保密,攜程網(wǎng)頁的數(shù)據(jù)信息由post請求得到,因此僅僅通過get請求無法得到目標html,需要在當前網(wǎng)頁發(fā)起post請求
    參考鏈接

總結(jié):

  1. 通過一周學習,再次理解了上一學期中易混淆未理解“異步調(diào)用”、“get/post請求”的概念
    異步調(diào)用,依次開啟多個函數(shù)入口,并發(fā)執(zhí)行,返回結(jié)果順序與入口執(zhí)行順序不一定相同,可以使用async模塊包來控制異步與同步的切換。
    get請求:通過添加url中的查詢參數(shù),向當前網(wǎng)頁發(fā)出get請求,獲得返回數(shù)據(jù),不具備保密性。相當于得到了帶參數(shù)的url完整路徑,就得到了這個網(wǎng)頁的數(shù)據(jù)。
    post請求:通過某個動作(如搜索按鈕、提交按鈕)向服務器后臺發(fā)送數(shù)據(jù)包,再收獲相應數(shù)據(jù),將得到的數(shù)據(jù)渲染到當前頁面,動態(tài)生成頁面,如果截取到當前網(wǎng)頁的url只能獲得一個空的HTML頁面框架,不具備有價值的數(shù)據(jù)。
  1. 對于新工具的學習使用能力還要加強
    這一次的模擬請求,用到了postman這個軟件+插件進行網(wǎng)頁抓包(抓取客戶端向服務器發(fā)出的請求數(shù)據(jù)包,與服務器返回的響應數(shù)據(jù)包)與發(fā)包測試(模擬發(fā)出get/post請求),在初次使用中因不太理解請求原理+不熟悉使用方法,導致在盲目測試請求時浪費了很多時間。
  2. 爬蟲與反爬蟲:通過對反爬蟲的了解,反面思考爬蟲的設計思路
    現(xiàn)在主流的幾個反爬蟲技術(shù):
    1、限制查詢頻率,超過一定頻率,采取封號、封IP
    2、通過圖片驗證碼等技術(shù)識別機器查詢與手工查詢
    3、設計cookie值與cookie值的隨機有效domain
    4、加密查詢的參數(shù)
    因此通過爬去攜程與去哪兒,了解了兩家的反爬蟲核心:
    攜程
    通過post請求傳輸參數(shù),發(fā)送的參數(shù)中包含"transNo"與"searchKey"兩個參數(shù),均為隨機加密參數(shù),每次查詢均獨立加密
攜程的查詢參數(shù)

去哪兒
通過get請求傳輸參數(shù),查詢參數(shù)中包含"es"隨機參數(shù),每一次查詢都會產(chǎn)生不同的es參數(shù)。
因為缺少這兩個加密參數(shù),無法獲取加密規(guī)則,使得我們無法爬取攜程與去哪兒兩大門戶的機票信息,嗨呀真是太氣了……

去哪兒的查詢參數(shù)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容