99999久久久久久亚洲,欧美人与禽猛交狂配,高清日韩av在线影院,一个人在线高清免费观看,啦啦啦在线视频免费观看www

熱線電話:13121318867

登錄
首頁精彩閱讀大數(shù)據(jù)時代,這項收集數(shù)據(jù)的技能不可少
大數(shù)據(jù)時代,這項收集數(shù)據(jù)的技能不可少
2017-04-14
收藏

大數(shù)據(jù)時代,這項收集數(shù)據(jù)的技能不可少

大數(shù)據(jù)是未來的“新石油”。《人類簡史:從動物到上帝》的作者尤瓦爾·赫拉利說:大數(shù)據(jù)將是人類自由意志的終結(jié),數(shù)據(jù)主義將取代以往的宗教和人文主義,成為未來的信仰。人人都在談大數(shù)據(jù),談DT時代,我們剝?nèi)ド鐣郊由系耐庖拢瑒t回歸“數(shù)據(jù)”二字。

那如何獲取數(shù)據(jù)呢?

在運營公眾號這么長一段時間,經(jīng)常有人問超模君:超模君,我需要什么的數(shù)據(jù),該怎么處理,或者直接問超模君,能不能給我提供一些數(shù)據(jù)?

其實超模君內(nèi)心是奔潰的。。。而一般我給出的建議如果沒有整理好的數(shù)據(jù),可以嘗試做個爬蟲試試。而在獲取數(shù)據(jù)的道路上并不簡單,爬蟲可謂是“麻雀雖小,五臟俱全”,爬蟲雖然操作起來很簡單,用十幾行腳本語言就可以搞定,但其中可涉及到網(wǎng)絡通信,字符串處理,數(shù)據(jù)庫等,能使用到一種語言的幾乎所有組件。

一言不合就上代碼

我們先來看一個最簡單的最簡單的爬蟲,用python寫成,只需要三行。

import requests
url="http://www.cricode.com"
r=requests.get(url)

上面這三行爬蟲程序,就如下面這三行情詩一般,很干脆利落。

是好男人,

就應該在和女友吵架時,

抱著必輸?shù)男膽B(tài)。

上面那個最簡單的爬蟲,不是一個完整的爬蟲,因為爬蟲通常需要以下3個步驟:

1)給定的種子URLs,爬蟲程序?qū)⑺蟹N子URL頁面爬取下來

2)爬蟲程序解析爬取到的URL頁面中的鏈接,將這些鏈接放入待爬取URL集合里

3)重復1、2步,直到達到指定條件才終止爬取

因此,一個完整的爬蟲大概是這樣子的:

import requests                       #用來爬取網(wǎng)頁
from bs4 import BeautifulSoup         #用來解析網(wǎng)頁
seds = ["http://www.hao123.com",      #我們的種子
              "http://www.csdn.net",
              "http://www.cricode.com"]
sum = 0                               #我們設定終止條件為:爬取到100000個頁面時,就不玩了
 
while sum < 10000 :
    if sum < len(seds):
         r = requests.get(seds[sum])
         sum = sum + 1
         do_save_action(r)
         soup = BeautifulSoup(r.content)               
         urls = soup.find_all("href",.....)                     //解析網(wǎng)頁
         for url in urls:
              seds.append(url)
 
    else:
         break

上面那個完整的爬蟲,不足20行代碼,相信你能找出20個需要改進的地方來。因為它的缺點實在是太多了。下面列舉一下它的N個缺點:

1)我們的任務是爬取1萬個網(wǎng)頁,按上面這個程序,一個人在默默的爬取,假設爬起一個網(wǎng)頁3秒鐘,那么,爬一萬個網(wǎng)頁就要3萬秒鐘。MGD,我們可以考慮開啟多個線程去一起爬取,或者用分布式架構(gòu)去并發(fā)地爬取網(wǎng)頁。

2)種子URL和后續(xù)解析到的URL都放在一個列表里,我們應該將這些待爬取的URL存放到一個新的更合理的數(shù)據(jù)結(jié)構(gòu)里,例如隊列或者優(yōu)先隊列。

3)對各個網(wǎng)站的URL,我們一視同仁,然而,我們應該是要區(qū)別對待的。應當考慮大站好站優(yōu)先原則。

4)我們每次發(fā)起請求,都是根據(jù)URL來發(fā)起的,而在這個過程中會牽涉到DNS解析(將URL轉(zhuǎn)換成 IP 地址)。一個網(wǎng)站通常有數(shù)以萬計的URL,所以我們可以考慮將這些網(wǎng)站域名的 IP 地址進行緩存,避免每次都發(fā)起DNS請求,浪費時間。

5)解析到網(wǎng)頁中的URLs后,我們沒有做任何去重處理,全部放入了待爬取的列表中。事實上,可能有很多鏈接是重復的,我們做了很多無用功。

6)…..

那么,真正的問題來了,學挖掘機到底哪家強?

現(xiàn)在我們就來列出上面找出的幾個問題的解決方案。

1)如何做到并行爬取

我們可以有多重方法去實現(xiàn)并行。

多線程或者線程池方式,一個爬蟲程序內(nèi)部開啟多個線程。同一臺機器開啟多個爬蟲程序,這樣,我們就有N多爬取線程在同時工作。能大大縮短時間。

此外,當我們要爬取的任務特別多時,一臺機器、一個網(wǎng)點明顯不夠,這時我們就要考慮分布式爬蟲了。常見的分布式架構(gòu)有:主從(Master——Slave)架構(gòu)、點對點(Peer to Peer)架構(gòu),混合架構(gòu)等。

說到分布式架構(gòu),我們需要考慮的問題就有很多,比如我們需要分派任務,各個爬蟲之間需要通信合作,共同完成任務,不要重復爬取相同的網(wǎng)頁。分派任務時我們要做到公平公正,就需要考慮如何進行負載均衡。負載均衡,我們第一個想到的就是Hash,比如根據(jù)網(wǎng)站域名進行hash。

負載均衡分派完任務之后,并不意味著萬事大吉了,萬一哪臺機器崩潰了呢?原先指派給崩潰的那臺機器的任務應該再指派給哪臺機器?又或者哪天要增加幾臺機器,任務重新分配問題該如何解決?

用一致性Hash算法就是一個比較好的解決方案。

2)如何對待待抓取隊列

類似于操作系統(tǒng)如何調(diào)度進程的場景。

不同的網(wǎng)站,重要程度不同,因此,可以設計一個優(yōu)先級隊列來存放待爬取的網(wǎng)頁鏈接。這樣一來,每次抓取時,重要的網(wǎng)頁都會被我們優(yōu)先爬取。

另外,你也可以效仿操作系統(tǒng)的進程調(diào)度策略之多級反饋隊列調(diào)度算法。

3)進行DNS緩存

為了避免每次都發(fā)起DNS查詢,我們可以將DNS進行緩存。DNS緩存當然是設計一個hash表來存儲已有的域名及其 IP 。

4)進行網(wǎng)頁去重

說到網(wǎng)頁去重,應該都會想到垃圾郵件過濾。垃圾郵件過濾的一個經(jīng)典的解決方案是Bloom Filter(布隆過濾器)。布隆過濾器原理簡單來說就是:建立一個大的位數(shù)組,然后用多個Hash函數(shù)對同一個url進行hash得到多個數(shù)字,然后將位數(shù)組中這些數(shù)字對應的位置為1。下次再來一個url時,同樣是用多個Hash函數(shù)進行hash,得到多個數(shù)字,我們只需要判斷位數(shù)組中這些數(shù)字對應的為是全為1,如果全為1,那么說明這個url已經(jīng)出現(xiàn)過。如此,便完成了url去重的問題。不過,這種方法會有誤差,但是只要誤差在我們的接受范圍之內(nèi),就像是1萬個網(wǎng)頁,我們只爬取到了9999個,剩下那1個網(wǎng)頁,誰在乎呢!

5)數(shù)據(jù)存儲的問題

數(shù)據(jù)存儲同樣是一個很有技術(shù)含量的問題。用關(guān)系數(shù)據(jù)庫存取還是用NoSQL,或者是自己設計特定的文件格式進行存儲,都有很大工程可做。

6)如何完成進程間通信

分布式爬蟲,離不開進程間的通信。我們可以以規(guī)定的數(shù)據(jù)格式進行數(shù)據(jù)交互,去完成進程間的通信。


數(shù)據(jù)分析咨詢請掃描二維碼

若不方便掃碼,搜微信號:CDAshujufenxi

數(shù)據(jù)分析師資訊
更多

OK
客服在線
立即咨詢
客服在線
立即咨詢
') } function initGt() { var handler = function (captchaObj) { captchaObj.appendTo('#captcha'); captchaObj.onReady(function () { $("#wait").hide(); }).onSuccess(function(){ $('.getcheckcode').removeClass('dis'); $('.getcheckcode').trigger('click'); }); window.captchaObj = captchaObj; }; $('#captcha').show(); $.ajax({ url: "/login/gtstart?t=" + (new Date()).getTime(), // 加隨機數(shù)防止緩存 type: "get", dataType: "json", success: function (data) { $('#text').hide(); $('#wait').show(); // 調(diào)用 initGeetest 進行初始化 // 參數(shù)1:配置參數(shù) // 參數(shù)2:回調(diào),回調(diào)的第一個參數(shù)驗證碼對象,之后可以使用它調(diào)用相應的接口 initGeetest({ // 以下 4 個配置參數(shù)為必須,不能缺少 gt: data.gt, challenge: data.challenge, offline: !data.success, // 表示用戶后臺檢測極驗服務器是否宕機 new_captcha: data.new_captcha, // 用于宕機時表示是新驗證碼的宕機 product: "float", // 產(chǎn)品形式,包括:float,popup width: "280px", https: true // 更多配置參數(shù)說明請參見:http://docs.geetest.com/install/client/web-front/ }, handler); } }); } function codeCutdown() { if(_wait == 0){ //倒計時完成 $(".getcheckcode").removeClass('dis').html("重新獲取"); }else{ $(".getcheckcode").addClass('dis').html("重新獲取("+_wait+"s)"); _wait--; setTimeout(function () { codeCutdown(); },1000); } } function inputValidate(ele,telInput) { var oInput = ele; var inputVal = oInput.val(); var oType = ele.attr('data-type'); var oEtag = $('#etag').val(); var oErr = oInput.closest('.form_box').next('.err_txt'); var empTxt = '請輸入'+oInput.attr('placeholder')+'!'; var errTxt = '請輸入正確的'+oInput.attr('placeholder')+'!'; var pattern; if(inputVal==""){ if(!telInput){ errFun(oErr,empTxt); } return false; }else { switch (oType){ case 'login_mobile': pattern = /^1[3456789]\d{9}$/; if(inputVal.length==11) { $.ajax({ url: '/login/checkmobile', type: "post", dataType: "json", data: { mobile: inputVal, etag: oEtag, page_ur: window.location.href, page_referer: document.referrer }, success: function (data) { } }); } break; case 'login_yzm': pattern = /^\d{6}$/; break; } if(oType=='login_mobile'){ } if(!!validateFun(pattern,inputVal)){ errFun(oErr,'') if(telInput){ $('.getcheckcode').removeClass('dis'); } }else { if(!telInput) { errFun(oErr, errTxt); }else { $('.getcheckcode').addClass('dis'); } return false; } } return true; } function errFun(obj,msg) { obj.html(msg); if(msg==''){ $('.login_submit').removeClass('dis'); }else { $('.login_submit').addClass('dis'); } } function validateFun(pat,val) { return pat.test(val); }