大家好!從今天開(kāi)始,我要與大家一起打造一個(gè)屬于我們自己的分布式爬蟲(chóng)平臺(tái),同時(shí)也會(huì)對(duì)涉及到的技術(shù)進(jìn)行詳細(xì)介紹。大家如果有什么好的想法請(qǐng)多留言,多提意見(jiàn),一起來(lái)完善我們的爬蟲(chóng)平臺(tái)。在正式介紹平臺(tái)之前,先用一些篇幅對(duì)基礎(chǔ)篇做一點(diǎn)補(bǔ)充。
創(chuàng)新互聯(lián)公司成立于2013年,公司以成都網(wǎng)站制作、網(wǎng)站建設(shè)、系統(tǒng)開(kāi)發(fā)、網(wǎng)絡(luò)推廣、文化傳媒、企業(yè)宣傳、平面廣告設(shè)計(jì)等為主要業(yè)務(wù),適用行業(yè)近百種。服務(wù)企業(yè)客戶1000+,涉及國(guó)內(nèi)多個(gè)省份客戶。擁有多年網(wǎng)站建設(shè)開(kāi)發(fā)經(jīng)驗(yàn)。為企業(yè)提供專(zhuān)業(yè)的網(wǎng)站建設(shè)、創(chuàng)意設(shè)計(jì)、宣傳推廣等服務(wù)。 通過(guò)專(zhuān)業(yè)的設(shè)計(jì)、獨(dú)特的風(fēng)格,為不同客戶提供各種風(fēng)格的特色服務(wù)。
這次的目標(biāo)是爬一個(gè)眾籌網(wǎng)站的所有項(xiàng)目,項(xiàng)目列表頁(yè)如下:https://www.kaistart.com/project/more.html。打開(kāi)后進(jìn)行分析,頁(yè)面顯示出10個(gè)項(xiàng)目:
如果想看到更多項(xiàng)目,并不能像網(wǎng)易云音樂(lè)那樣點(diǎn)“下一頁(yè)”翻頁(yè),而是需要向下拉滾動(dòng)條或者向下滾動(dòng)鼠標(biāo)滾輪來(lái)觸發(fā)異步請(qǐng)求。爬蟲(chóng)該如何應(yīng)對(duì)這種情況呢?我們可以使用selenium的api執(zhí)行js代碼將屏幕內(nèi)容滾動(dòng)到指定位置。
下面這段代碼會(huì)一直向下滾動(dòng)項(xiàng)目頁(yè),一直到滾不動(dòng)為止:
# 一直滾動(dòng)到最底部js1 = 'return document.body.scrollHeight'js2 = 'window.scrollTo(0, document.body.scrollHeight)'old_scroll_height = 0while browser.execute_script(js1) >= old_scroll_height: old_scroll_height = browser.execute_script(js1) browser.execute_script(js2) time.sleep(1)
scrollTo() 方法可把內(nèi)容滾動(dòng)到指定的坐標(biāo):
參數(shù) | 描述 |
xpos | 必需。要在窗口文檔顯示區(qū)左上角顯示的文檔的 x 坐標(biāo)。 |
ypos | 必需。要在窗口文檔顯示區(qū)左上角顯示的文檔的 y 坐標(biāo)。 |
這里用到了scrollHeight,它和ClientHeight還有OffsetHeight有什么區(qū)別呢?
offsetHeight: 包括內(nèi)容可見(jiàn)部分的高度,border,可見(jiàn)的padding,水平方向的scrollbar(如果存在);不包括margin。
clientHeight: 包括內(nèi)容可見(jiàn)部分的高度,可見(jiàn)的padding;不包括border,水平方向的scrollbar,margin。
scrollHeight: 包括內(nèi)容的高度(可見(jiàn)與不可見(jiàn)),padding(可見(jiàn)與不可見(jiàn));不包括border,margin。
代碼寫(xiě)好了,接下來(lái)就用selenium+phantomJs大法實(shí)驗(yàn)一下!滾到底后把項(xiàng)目列表提取出來(lái)看一下:
browser = webdriver.PhantomJs() url = 'https://www.kaistart.com/project/more.html'try: browser.get(url) wait = ui.WebDriverWait(browser, 20) wait.until(lambda dr: dr.find_element_by_class_name('project-detail').is_displayed()) # 一直滾動(dòng)到最底部 js1 = 'return document.body.scrollHeight' js2 = 'window.scrollTo(0, document.body.scrollHeight)' old_scroll_height = 0 while browser.execute_script(js1) >= old_scroll_height: old_scroll_height = browser.execute_script(js1) browser.execute_script(js2) time.sleep(1) sel = Selector(text=browser.page_source) proj_list = sel.xpath('//li[@class="project-li"]')
程序運(yùn)行結(jié)束后,顯示proje_list里面只有25個(gè)元素,而我們自己手動(dòng)滾的話卻有100多個(gè),明顯有bug。想定位這個(gè)問(wèn)題很簡(jiǎn)單,截圖即可,看看為什么停在第25個(gè)項(xiàng)目。對(duì),phantomJs雖然沒(méi)有圖形界面,但是可以截圖。
browser.save_screenshot(debug.png')
這樣就會(huì)把圖片保存在項(xiàng)目目錄,打開(kāi)看看:
發(fā)現(xiàn)項(xiàng)目頁(yè)只能顯示一行,這說(shuō)明網(wǎng)頁(yè)不兼容phantomJs,這倒不是什么新鮮事,換一個(gè)瀏覽器試試唄。第一期介紹過(guò),selenium是支持所有主流瀏覽器的。比如換成Chrome,只需改一行代碼:
browser = webdriver.Chrome()
再次運(yùn)行程序,不出所料,Chrome瀏覽器彈出來(lái),不僅能夠正確顯示頁(yè)面,還一直在滾動(dòng):
項(xiàng)目全都刷出來(lái)了,想爬什么就爬吧!什么?你問(wèn)我在Linux服務(wù)器上怎么爬?純命令行的那種嗎?
PhantomJs是×××面瀏覽器,可以在Linux服務(wù)器上正常運(yùn)行,但Chrome會(huì)在調(diào)用GUI接口時(shí)報(bào)錯(cuò)。既然Linux服務(wù)器沒(méi)有圖形接口服務(wù),也就是X Server,我們就要虛擬出來(lái)一個(gè),才能讓Chrome正常運(yùn)行。于是找到了Xvfb(X virtual frame buffer),它可以用來(lái)作為完整X服務(wù)程序的替代。Xvfb有一個(gè)Python的封裝叫PyVirtualDisplay,我們就用它來(lái)解決這個(gè)問(wèn)題。
安裝:
pip install pyvirtualdisplay
用法:
from selenium import webdriverfrom pyvirtualdisplay import Display display = Display(visible=0, size=(800, 600)) display.start() driver = webdriver.Chrome() driver.get("http://www.baidu.com")print (driver.page_source.encode('utf-8')) driver.quit() display.stop()
運(yùn)行程序后打印出了baidu的頁(yè)面內(nèi)容,現(xiàn)在可以完美運(yùn)行Chrome了。需要補(bǔ)充的是,在Linux上運(yùn)行Chrome需要額外安裝一個(gè)ChromeDriver,比較簡(jiǎn)單,就不詳細(xì)介紹了。
既然我們要打造自己的分布式爬蟲(chóng)平臺(tái),就要先知道什么是分布式系統(tǒng),百度百科是這樣定義的:
分布式系統(tǒng)(distributed system)是建立在網(wǎng)絡(luò)之上的軟件系統(tǒng)。正是因?yàn)檐浖奶匦裕苑植际较到y(tǒng)具有高度的內(nèi)聚性和透明性。因此,網(wǎng)絡(luò)和分布式系統(tǒng)之間的區(qū)別更多的在于高層軟件(特別是操作系統(tǒng)),而不是硬件。內(nèi)聚性是指每一個(gè)數(shù)據(jù)庫(kù)分布節(jié)點(diǎn)高度自治,有本地的數(shù)據(jù)庫(kù)管理系統(tǒng)。透明性是指每一個(gè)數(shù)據(jù)庫(kù)分布節(jié)點(diǎn)對(duì)用戶的應(yīng)用來(lái)說(shuō)都是透明的,看不出是本地還是遠(yuǎn)程。在分布式數(shù)據(jù)庫(kù)系統(tǒng)中,用戶感覺(jué)不到數(shù)據(jù)是分布的,即用戶不須知道關(guān)系是否分割、有無(wú)副本、數(shù)據(jù)存于哪個(gè)站點(diǎn)以及事務(wù)在哪個(gè)站點(diǎn)上執(zhí)行等。
這個(gè)定義不太好理解,看看書(shū)上怎么說(shuō)?!斗植际较到y(tǒng)概念與設(shè)計(jì)》一書(shū)中對(duì)分布式系統(tǒng)做了如下定義:
分布式系統(tǒng)是一個(gè)硬件或軟件組件分布在不同的網(wǎng)絡(luò)計(jì)算機(jī)上,彼此之間僅僅通過(guò)消息傳遞進(jìn)行通信和協(xié)調(diào)的系統(tǒng)。
《分布式系統(tǒng)原理和范型》一書(shū)中是這樣定義分布式系統(tǒng)的:
分布式系統(tǒng)是若干獨(dú)立計(jì)算機(jī)的集合,這些計(jì)算機(jī)對(duì)于用戶來(lái)說(shuō)就像是單個(gè)相關(guān)系統(tǒng)。
簡(jiǎn)單來(lái)說(shuō)就是一群獨(dú)立計(jì)算機(jī)集合共同對(duì)外提供服務(wù),但是對(duì)于系統(tǒng)的用戶來(lái)說(shuō),就像是一臺(tái)計(jì)算機(jī)在提供服務(wù)一樣。分布式意味著可以采用更多的普通計(jì)算機(jī)(相對(duì)于昂貴的大型機(jī))組成分布式集群對(duì)外提供服務(wù)。計(jì)算機(jī)越多,CPU、內(nèi)存、存儲(chǔ)資源等也就越多,能夠處理的并發(fā)訪問(wèn)量也就越大。
從分布式系統(tǒng)的概念中我們知道,各個(gè)主機(jī)之間通信和協(xié)調(diào)主要通過(guò)網(wǎng)絡(luò)進(jìn)行,所以,分布式系統(tǒng)中的計(jì)算機(jī)在空間上幾乎沒(méi)有任何限制,這些計(jì)算機(jī)可能被放在不同的機(jī)柜上,也可能被部署在不同的機(jī)房中,還可能在不同的城市中,對(duì)于大型的網(wǎng)站甚至可能分布在不同的國(guó)家。但是,無(wú)論空間上如何分布,一個(gè)標(biāo)準(zhǔn)的分布式系統(tǒng)應(yīng)該具有以下幾個(gè)主要特征:
透明性
系統(tǒng)資源被所有計(jì)算機(jī)共享。每臺(tái)計(jì)算機(jī)的用戶不僅可以使用本機(jī)的資源,還可以使用本分布式系統(tǒng)中其他計(jì)算機(jī)的資源。
同一性
系統(tǒng)中的若干臺(tái)計(jì)算機(jī)可以互相協(xié)作來(lái)完成一個(gè)共同的任務(wù),或者說(shuō)一個(gè)程序可以分布在幾臺(tái)計(jì)算機(jī)上并行地運(yùn)行。
通信性
系統(tǒng)中的計(jì)算機(jī)都可以通過(guò)通信來(lái)交換信息。
最后,初學(xué)者進(jìn)階的福音
想學(xué)習(xí),基礎(chǔ)不夠?沒(méi)關(guān)系,我們提供免費(fèi)提供VIP基礎(chǔ)學(xué)習(xí)課程,讓你快速入門(mén),掌握Python!
有基礎(chǔ)的小伙伴想學(xué)習(xí)項(xiàng)目實(shí)戰(zhàn)?沒(méi)問(wèn)題,每晚八點(diǎn)都有博士大牛帶你學(xué)習(xí)操作項(xiàng)目!
只要你有一顆想學(xué)習(xí)的心,我們隨時(shí)歡迎~