回覆“書籍”即可獲贈Python從入門到進階共10本電子書
大家好,我是小一
今天分享一篇爬蟲教程,文章比較細緻,適合剛上手的小白,老讀者可以酌情加速閱讀
文中涉及的代碼已經測試過,可以正常跑通,文章案例的所有數據也已經成功爬取。
今天要分享的教程是爬取各大城市的二手房數據,拋開以前的文章不談,下面的內容應該足夠你實現這篇爬蟲。以下是正文:
1. 確定目標
今天我們的目標官網鏈接是:https://www.lianjia.com/
對應的某個城市的二手房頁面應該是:https://sz.lianjia.com/ershoufang/
sz 代表城市深圳的簡寫,廣州對應的是 gz。
ok,前提條件交代清楚了,接下來看看今天要爬取的目標數據
有兩個頁面需要注意,第一個頁面是你打開上面那個鏈接之後顯示的列表頁面,第二個頁面是你點擊某個二手房的鏈接之後跳轉的房屋詳細數據頁面
1.1. 先來說第一個頁面
這個頁面包括三部分,最上面的搜索部分、中間的列表部分、下面的翻頁部分。
上面的搜索部分看似無用,但其實是官方強行設置的一個小操作。
舉個最直觀的例子:在某個搜索條件下,例如深圳市,對應的清單中有 39053 條記錄
而你將頁面拉到最下面進行翻頁,發現實際只有 100 頁可供操作
根據每一頁只有 30 條數據的官方設置,你如果不設置搜索條件,只能拿到 3000 條數據
所以,要想獲取全部數據,第一個搜索功能就派上用場了。
但是,添加搜索必然會導致整個程序的複雜度直線上升,特別是現在有如此多的搜索條件
綜上,最好的解決方式是篩選出 重要且能完美區分的搜索條件,例如:區域+戶型+朝向
上述設置的目的是:
通過條件設置之後,通過篩選 xx區 的數據,發現數據大於 3000條,則利用戶型是 x居室 的進行二次篩選,如果發現仍大於 3000條,再次通過 朝x 進行三次篩選
基本上到了第三次篩選之後,數據會在 3000以內,對應的可以全部拿到。
其他篩選條件應該也能實現同樣的效果,這個自己設定即可
對了,篩選條件除了每個城市的區域沒法固定外,居室和朝向都是固定的
通過F12查看源碼可以看到居室和朝向對應的系統定位如下:
對應的,在代碼中也就可以將其進行映射:
# 戶型:一室、二室、三室、四室、五室、五室+
self.rooms_number = ['l1', 'l2', 'l3', 'l4', 'l5', 'l6']
# 朝向:朝東+朝南+朝西+朝北+南北
self.orientation = ['f1', 'f2', 'f3', 'f4', 'f5']
再來看中間的列表部分
列表部分有 3 個信息需要注意,如下圖:
分別是:小區名+區域、其他標籤、價格
如果這些字段信息已經可以滿足你的數據需求,那對應的爬蟲只需要獲取這個頁面的數據,不需要分析第二個頁面,相對來說比較簡單
如果你需要更詳細的二手房指標,例如:掛牌時間、抵押情況、產權等,以及該房子的經緯度數據,那你需要分析第二個頁面
最後是下面的翻頁部分
翻頁部分原理比較簡單,通過多次點擊下一頁按鈕,觀察新頁面的 url 鏈接就能發現規律
例如:https://sz.lianjia.com/ershoufang/luohuqu/pg2l1/ 中的 pg2 對應的是第二頁的數據
而 l1 在前面我們已經知道是一居室的意思,所以對應的翻頁頁面的 url 規則應該是:主頁+區域+pg頁碼+居室
在翻頁遍歷的過程中只需要更改 pg頁碼 即可。
1.2. 再來說第二個頁面
第二個頁面是通過第一個頁面點擊跳轉的,我舉個例子:
通過點擊圖中上面的標籤,會跳轉到下面鏈接對應的新頁面
鏈接中後面的數字編號對應的是該二手房的編碼id。
第二個頁面有三個部分,分別是:價格+位置、基本信息+交易信息、地圖
價格+位置部分數據如下圖:
從價格部分可以獲取到:參考總價、單價
從所在區域可以獲取到:小區名稱、大區域+小區域
基本信息+交易信息數據如下圖:
因爲這張圖上的數據比較全,所以我並沒有解析上張圖的其他數據
這張圖上的基本屬性和交易屬性都可以拿下來作爲房屋字段
最後是地圖部分的數據:
這部分數據比較多,例如:最近的地鐵站點、公交站點等
以及在地圖插件中隱藏的房屋經緯度數據
因爲以前的文章專門爬過地鐵站點數據,所以我在這裏只拿了經緯度數據
2. 流程設計
目標已經明確,總結一下上面我們需要注意的地方,大概如下:
首先,判斷該城市的總數據是否超過 3000 條,若超過則需要設置篩選條件。先通過區域進行篩選,其次通過居室進行篩選,最後通過朝向進行篩選
上述篩選過程中任一過程若存在數據小於 3000條,則停止往下篩選。
其次,在確定篩選條件之後,通過解析每一頁的二手房鏈接跳轉到詳情頁。翻頁操作只需要根據頁碼重新構造 url 即可
最後,對二手房詳情頁進行解析,保存數據到本地文件中。
爲了方便對整個流程進行復現,我做了一個流程圖,如下:
3. 主要代碼復現
通過上面的流程圖,可以完成整個爬蟲的代碼復現
因爲涉及的代碼較多,這裏只貼核心代碼,完整的代碼可以在文末獲取
首先是獲取當前條件下的房屋數據個數:
def get_house_count(self):
"""
獲取當前篩選條件下的房屋數據個數
"""
# 爬取區域起始頁面的數據
response = requests.get(url=self.current_url, headers=self.headers)
# 通過 BeautifulSoup 進行頁面解析
soup = BeautifulSoup(response.text, 'html.parser')
# 獲取數據總條數
count = soup.find('h2', class_='total fl').find('span').string.lstrip()
return soup, count
其次是主頁面的設計:
判斷是否超過3000,若超過則進行第二級篩選,若未超過則直接獲取數據
def get_main_page(self):
# 獲取當前篩選條件下數據總條數
soup, count_main = self.get_house_count()
# 如果當前當前篩選條件下的數據個數大於最大可查詢個數,則設置第一次查詢條件
if int(count_main) > self.page_size*self.max_pages:
# 獲取當前地市的所有行政區域,當做第一個查詢條件
soup_uls = soup.find('div', attrs={'data-role': 'ershoufang'}).div.find_all('a')
self.area = self.get_area_list(soup_uls)
# 遍歷行政區域,重新生成篩選條件
for area in self.area:
self.get_area_page(area)
else:
# 直接獲取數據
self.get_pages(int(count_main), '', '', '')
# 保存數據到本地
self.data_to_csv()
對應的在確定區域的條件下,繼續判斷並篩選居室
在確定區域和居室的條件下,繼續判斷並篩選朝向
在確定區域、居室和朝向的條件下,直接獲取 前3000條 數據
可以看到上面的流程十分類似,對應的代碼大家注意看源碼就行。
如果在三級篩選下仍存在超過3000條數據,照葫蘆畫瓢就行
在代碼執行的過程中,建議每獲取到 10條 數據保存一次,避免中途程序出錯而前功盡棄
對應的代碼可以參考如下:
'''超過10條數據,保存到本地'''
if len(self.data_info) >= 10:
self.data_to_csv()
在保存到本地 csv 的時候,建議採用追加的方式進行保存
也就是在 data_to_csv 函數中這樣寫:
def data_to_csv(self):
"""
保存/追加數據到本地
@return:
"""
df_data = pd.DataFrame(self.data_info)
if os.path.exists(self.save_file_path) and os.path.getsize(self.save_file_path):
# 追加寫入文件
df_data.to_csv(self.save_file_path, mode='a', encoding='utf-8', header=False, index=False)
else:
# 寫入文件,帶表頭
df_data.to_csv(self.save_file_path, mode='a', encoding='utf-8', index=False)
# 清空當前數據集
self.data_info = []
另外,考慮到大多時候需要運行好幾次程序才能獲取到所有數據
在每次運行程序的時候先統計已經爬到的房屋數據,跳過已經爬到的數據
對應的代碼可以這樣寫:
# 所有已經保存的房屋 id,用來驗證去重
self.house_id = self.get_exists_house_id()
def get_exists_house_id(self):
"""
通過已經爬取到的房屋信息,並獲取房屋id
@return:
"""
if os.path.exists(self.save_file_path):
df_data = pd.read_csv(self.save_file_path, encoding='utf-8', )
df_data['house_id'] = df_data['house_id'].astype(str)
return df_data['house_id'].to_list()
else:
return []
最後,在主函數中只需要設置城市名稱和數據保存路徑即可
代碼如下:
if __name__ == '__main__':
city_number = 'sz'
city_name = '深圳'
url = 'https://{0}.lianjia.com/ershoufang/'.format(city_number)
page_size = 30
save_file_path = '二手房數據-sz.csv'
house = House(city_name, url, page_size, save_file_path)
house.get_main_page()
完整的代碼可以在文末獲取
4. 程序運行截圖
如果是第一次運行程序,設置好相關參數後,運行截圖如下:
如果之前有運行過程序,中途退出了。
再次運行時無需設置參數,直接運行即可,截圖如下:
最終爬取到的部分數據如下:
5. 寫在最後的話
整體來說,雖然流程的設計比較繁瑣,但是仍然是很基礎的一篇內容
與本文相關的爬蟲參數設置、簡單爬蟲僞裝,網頁解析都可以在以前的文章中找到,在此不一一提及
另外,建議大家在運行的過程中,適當的設置程序休眠,理性爬蟲。
------------------- End -------------------
往期精彩文章推薦:
歡迎大家點贊,留言,轉發,轉載,感謝大家的相伴與支持
想加入Python學習羣請在後臺回覆【入羣】
萬水千山總是情,點個【在看】行不行
/今日留言主題/
隨便說一兩句吧~~
本文分享自微信公衆號 - Python爬蟲與數據挖掘(crawler_python)。
如有侵權,請聯繫 [email protected] 刪除。
本文參與“OSC源創計劃”,歡迎正在閱讀的你也加入,一起分享。