這次換一個售房網(wǎng)站來練練手,爬取目標是我愛我家的成交記錄。
我愛我家的網(wǎng)站結(jié)構(gòu)貌似比鏈家的要復(fù)雜一點點,它并沒有像鏈家網(wǎng)一樣,把成交記錄單獨分成一個版塊,而是把每條成交記錄按小區(qū)進行了匯總,一級界面顯示成交均價,每條的成交價格需要進入各個小區(qū)的二級界面,繼續(xù)往下拖動之后才能查看。那么,我們想要爬取的每條成交價格,實則在二級界面的詳細成交記錄框內(nèi)。
十五家園小區(qū)二級界面
http://hz.5i5j.com/community/22700
以十五家園小區(qū)為例,分析一下二級界面的url。url中22700肯定就是該小區(qū)的ID,那么我們直接獲取不同小區(qū)的ID后,對22700數(shù)值分別進行替換,就構(gòu)建了所有小區(qū)的url列表,然后分別對不同的url進行請求,以獲取每條成交價格行不行呢?結(jié)果應(yīng)該是不行的。
在二級界面的成交框中,每一頁只顯示了4條成交記錄,通過點擊第接下來的幾頁,可以發(fā)現(xiàn)網(wǎng)址欄中的url仍然是http://hz.5i5j.com/community/22700,所以該成交框是通過異步加載完成的,相當于是另一個獨立的網(wǎng)頁內(nèi)嵌在該小區(qū)的二級界面中。直接對二級界面的url進行請求,當然就獲取不到成交框內(nèi)的信息。
此處,我是通過抓包的方式來獲取成交框的url。單擊F12調(diào)出開發(fā)者工具,依次選擇Network→Preserve log→點擊第2頁→選擇Request URL。此處的Request URL應(yīng)該就是成交框的真實url。
成交框url
http://hz.5i5j.com/exchange/getdeals?communityId=22700&page=2&communityname=%E5%8D%81%E4%BA%94%E5%AE%B6%E5%9B%AD
hz.5i5j.com/exchange/getdeals?是主域名,communityid=22700就是該小區(qū)的ID,page=2代表我們剛剛點擊的第2頁,communityname=%5%8...就是小區(qū)名稱十五家園經(jīng)過UTF-8轉(zhuǎn)碼后的表現(xiàn)形式。
一般情況下,如果直接將獲取的這個url復(fù)制下來后并在另一個窗口中打開,應(yīng)該是可以顯示出我們想獲取的成交框中的數(shù)據(jù)。但是此處,打開這個url卻發(fā)現(xiàn)是一個空白頁面,在python中利用requests庫對該url進行請求,也獲得不到任何數(shù)據(jù)。
于是嘗試加入headers之后再進行請求。在F12的開發(fā)者界面中,將Request Headers下的信息添加進Headers之后,對成交框的url進行請求,發(fā)現(xiàn)可以正常顯示出成交框內(nèi)的信息。
進一步對成交框的url進行分析,可以發(fā)現(xiàn)將&communityname=及以后的內(nèi)容刪掉,也可以正常獲得數(shù)據(jù);headers中的X-Requested-With: XMLHttpRequest則不能刪除,否則就返回的是空白頁。
到現(xiàn)在,對網(wǎng)頁的分析已經(jīng)基本完畢!
- 獲取成交數(shù)據(jù)的大致方向就是將URL: http://hz.5i5j.com/exchange/getdeals?communityId=22700&page=2拆分為3部分
- 第一部分http://hz.5i5j.com/exchange/getdeals?,不用變
- 第二部分communityId=22700,將22700替換成不同小區(qū)的ID
- 第三部分page=2,將2換成不同的數(shù)值以代表不同的頁面
- 對構(gòu)建的URL進行請求并獲取數(shù)據(jù)
問題一 如何知道各個小區(qū)的ID?
在一級界面內(nèi)對十五家園小區(qū)的名稱進行審查元素后,發(fā)現(xiàn)ID是藏在了href中。
<a target="_blank" title="十五家園" href="/community/22700">十五家園</a>
因此只需要將一級界面中所有小區(qū)的ID通過xpath的方式抓取出來即可。
問題二 如何知道成交框有多少頁?
加入headers對成交框的url進行請求,返回的成交框源代碼的末尾處,通過對倒數(shù)第二個<li>標簽進行抓取獲得。
此處倒數(shù)第一個<li>標簽是 "尾頁",倒數(shù)第二個<li>標簽是 "6",即最大頁面。整理一下思路就是MaxPage
但是在我愛我家的一級界面中最多只能顯示12條小區(qū)信息,也就是說一個一級界面的url只能獲取12個小區(qū)的ID,只有先獲取了所有一級界面的URL,才能進一步獲得所有小區(qū)的ID。
我愛我家一級界面URL
http://hz.5i5j.com/community/n1
再通過不斷的點擊下一頁,可以發(fā)現(xiàn)n后面的數(shù)字就代表了頁數(shù)。那么問題就簡單了,直接對n后的數(shù)值不斷的迭代,就獲得了所有的一級界面url。
問題真這么簡單嗎?坑爹的發(fā)現(xiàn),將n后的數(shù)值迭代到85時,就不能顯示出小區(qū)信息了,也就是說通過這個方法只能獲得84×15=1260條小區(qū)信息,然而總共有5000多條信息。
老辦法,通過加入篩選條件,對小區(qū)進行分割,此處我還是選擇了以價格為條件,人為的將每個條件下的小區(qū)數(shù)量控制在1260條以下。另外還選擇了以行政區(qū)域為條件,因為在1萬元以下的小區(qū)數(shù)量還是超過了1260條,因此我繼續(xù)對其進行了分割。
#p1 [0,10000)
#p2 [10000,15000)
#p3 [15000,20000)
#p4 [20000,25000)
#p7 [70000,+∞)
start_urls = ['http://hz.5i5j.com/community/gongshu/p1',
'http://hz.5i5j.com/community/xiacheng/p1',
'http://hz.5i5j.com/community/shangcheng/p1',
'http://hz.5i5j.com/community/binjiang/p1',
'http://hz.5i5j.com/community/yuhang/p1',
'http://hz.5i5j.com/community/xiaoshan/p1',
'http://hz.5i5j.com/community/xihu/p1',
'http://hz.5i5j.com/community/jianggan/p1',
'http://hz.5i5j.com/community/fuyang/p1',
'http://hz.5i5j.com/community/p2/',
'http://hz.5i5j.com/community/p3/',
'http://hz.5i5j.com/community/p4/',
'http://hz.5i5j.com/community/p5/',
'http://hz.5i5j.com/community/p6/',
'http://hz.5i5j.com/community/p7/']
分割完畢之后,另一個問題是如何知道每個條件下的最大頁面數(shù)量。我們知道,每1頁最多只能顯示12條小區(qū),只要先知道在當前篩選條件下,一共有多少小區(qū),就可以計算出有多少頁。比如上面這個例子,一共有405個小區(qū),那么就有405/12=33.75,向上取整即34頁。
現(xiàn)在,整個流程已經(jīng)清晰!
- 最大頁面數(shù)X:用于構(gòu)建所有一級的界面URL。
例如http://hz.5i5j.com/community/xiacheng/p(1~X) - ID Y和MaxPage Z用于構(gòu)建該小區(qū)下的所有成交頁面URL。
例如http://hz.5i5j.com/exchange/getdeals?communityId=Y&page=(1~Z)
對不同條件下的一級界面URL進行迭代至最大頁數(shù)X,獲取所有小區(qū)的ID,再對各個小區(qū)的成交框URL進行接待至最大頁面數(shù)Z,抓取想要的信息即可。
最后放上源代碼。
爬蟲代碼--我愛我家