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

熱線電話:13121318867

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

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

大數(shù)據(jù)是未來的“新石油”?!度祟惡喪罚簭膭?dòng)物到上帝》的作者尤瓦爾·赫拉利說:大數(shù)據(jù)將是人類自由意志的終結(jié),數(shù)據(jù)主義將取代以往的宗教和人文主義,成為未來的信仰。人人都在談大數(shù)據(jù),談DT時(shí)代,我們剝?nèi)ド鐣?huì)附加上的外衣,則回歸“數(shù)據(jù)”二字。

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

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

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

一言不合就上代碼

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

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

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

是好男人,

就應(yīng)該在和女友吵架時(shí),

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

上面那個(gè)最簡單的爬蟲,不是一個(gè)完整的爬蟲,因?yàn)榕老x通常需要以下3個(gè)步驟:

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

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

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

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

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                               #我們設(shè)定終止條件為:爬取到100000個(gè)頁面時(shí),就不玩了
 
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

上面那個(gè)完整的爬蟲,不足20行代碼,相信你能找出20個(gè)需要改進(jìn)的地方來。因?yàn)樗娜秉c(diǎn)實(shí)在是太多了。下面列舉一下它的N個(gè)缺點(diǎn):

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

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

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

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

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

6)…..

那么,真正的問題來了,學(xué)挖掘機(jī)到底哪家強(qiáng)?

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

1)如何做到并行爬取

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

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

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

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

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

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

2)如何對待待抓取隊(duì)列

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

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

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

3)進(jìn)行DNS緩存

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

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

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

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

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

6)如何完成進(jìn)程間通信

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

7)……

廢話說了那么多,真正的問題來了,問題不是學(xué)挖掘機(jī)到底哪家強(qiáng)?而是如何實(shí)現(xiàn)上面這些東西?。海?

數(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(), // 加隨機(jī)數(shù)防止緩存 type: "get", dataType: "json", success: function (data) { $('#text').hide(); $('#wait').show(); // 調(diào)用 initGeetest 進(jìn)行初始化 // 參數(shù)1:配置參數(shù) // 參數(shù)2:回調(diào),回調(diào)的第一個(gè)參數(shù)驗(yàn)證碼對象,之后可以使用它調(diào)用相應(yīng)的接口 initGeetest({ // 以下 4 個(gè)配置參數(shù)為必須,不能缺少 gt: data.gt, challenge: data.challenge, offline: !data.success, // 表示用戶后臺檢測極驗(yàn)服務(wù)器是否宕機(jī) new_captcha: data.new_captcha, // 用于宕機(jī)時(shí)表示是新驗(yàn)證碼的宕機(jī) 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){ //倒計(jì)時(shí)完成 $(".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); }