2017.3.6 - 3.17
學(xué)習(xí)內(nèi)容:
- 學(xué)習(xí)nodejs數(shù)據(jù)挖掘基本想法
- 熟悉superagent模塊的基本接口
- 熟悉cheerio模塊的基本接口
- 學(xué)習(xí)范例挖掘Cnode首頁信息
- eventproxy模塊學(xué)習(xí)
- async模塊學(xué)習(xí)
- 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模塊接口整理
一個用于抓取當(dāng)前頁面信息的模塊包
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 接口的變量叙谨,我們習(xí)慣性地將它命名為 `$`
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ù)異步并發(fā):
ep.after('got_file', files.length, function (list) {})
監(jiān)聽事件重復(fù)指定次數(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ù)幸逆,對應(yīng)的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重復(fù)栖袋,找不到dom或找錯dom
- 數(shù)組越界拍顷,導(dǎo)致在debug時的前幾輪循環(huán)中可取,在整體運行中出錯塘幅。
- 重點理解nodejs的異步機制昔案!需要在回調(diào)函數(shù)中操作dom,以防還未捕捉到dom
—————————
Q2:get請求抓取信息的數(shù)據(jù)結(jié)構(gòu)失敗
A2:出于安全保密电媳,攜程網(wǎng)頁的數(shù)據(jù)信息由post請求得到踏揣,因此僅僅通過get請求無法得到目標html,需要在當(dāng)前網(wǎng)頁發(fā)起post請求
參考鏈接
總結(jié):
- 通過一周學(xué)習(xí)匆背,再次理解了上一學(xué)期中易混淆未理解“異步調(diào)用”呼伸、“get/post請求”的概念
異步調(diào)用,依次開啟多個函數(shù)入口钝尸,并發(fā)執(zhí)行括享,返回結(jié)果順序與入口執(zhí)行順序不一定相同,可以使用async模塊包來控制異步與同步的切換珍促。
get請求:通過添加url中的查詢參數(shù)铃辖,向當(dāng)前網(wǎng)頁發(fā)出get請求,獲得返回數(shù)據(jù)猪叙,不具備保密性娇斩。相當(dāng)于得到了帶參數(shù)的url完整路徑,就得到了這個網(wǎng)頁的數(shù)據(jù)穴翩。
post請求:通過某個動作(如搜索按鈕犬第、提交按鈕)向服務(wù)器后臺發(fā)送數(shù)據(jù)包,再收獲相應(yīng)數(shù)據(jù)芒帕,將得到的數(shù)據(jù)渲染到當(dāng)前頁面歉嗓,動態(tài)生成頁面,如果截取到當(dāng)前網(wǎng)頁的url只能獲得一個空的HTML頁面框架背蟆,不具備有價值的數(shù)據(jù)鉴分。
- 對于新工具的學(xué)習(xí)使用能力還要加強
這一次的模擬請求哮幢,用到了postman這個軟件+插件進行網(wǎng)頁抓包(抓取客戶端向服務(wù)器發(fā)出的請求數(shù)據(jù)包,與服務(wù)器返回的響應(yīng)數(shù)據(jù)包)與發(fā)包測試(模擬發(fā)出get/post請求)志珍,在初次使用中因不太理解請求原理+不熟悉使用方法橙垢,導(dǎo)致在盲目測試請求時浪費了很多時間。 - 爬蟲與反爬蟲:通過對反爬蟲的了解伦糯,反面思考爬蟲的設(shè)計思路
現(xiàn)在主流的幾個反爬蟲技術(shù):
1柜某、限制查詢頻率,超過一定頻率舔株,采取封號莺琳、封IP
2、通過圖片驗證碼等技術(shù)識別機器查詢與手工查詢
3载慈、設(shè)計cookie值與cookie值的隨機有效domain
4惭等、加密查詢的參數(shù)
因此通過爬去攜程與去哪兒,了解了兩家的反爬蟲核心:
攜程:
通過post請求傳輸參數(shù)办铡,發(fā)送的參數(shù)中包含"transNo"與"searchKey"兩個參數(shù)辞做,均為隨機加密參數(shù),每次查詢均獨立加密
去哪兒:
通過get請求傳輸參數(shù)寡具,查詢參數(shù)中包含"es"隨機參數(shù)秤茅,每一次查詢都會產(chǎn)生不同的es參數(shù)。
因為缺少這兩個加密參數(shù)童叠,無法獲取加密規(guī)則框喳,使得我們無法爬取攜程與去哪兒兩大門戶的機票信息,嗨呀真是太氣了……