前言
筆者在做一個 項目時,需要識別小區名,因此想要查詢網上是否有相關的數據集。經過一番搜索後一無所獲…從而決定自己來爬取這份數據。
由於爬取網站的內容信息之後可能會發生變更,因此此處給出具體的爬蟲思路,便於應對之後的網站結構變更。
方法
1. 爬取網站的確定
既然是爬蟲,那首先就需要確定爬取網站。這時候就需要思考哪些網站可能會涉及小區名字?
- 國家統計網?經過一番搜索,沒找到…
- 房屋中介網?√
因此我們可以選取比較知名的房屋中介網來進行小區名爬取,此處選取的網站是鏈家,原因是該網站有專門的小區板塊。鏈家
2. 網站結構分析
由於鏈家對於不同城市,建立了不同的網頁,因此我們以北京的網頁舉例。
第一步,選中所有選項,查看當前網址。
https://bj.lianjia.com/xiaoqu/pg1y1y2y3y4y5p1p2p3p4p5p6/
多查看幾個網頁,就可以發現上述網址的共性,bj
是城市縮寫,pg1
是頁面編號。
第二步,查看當前網頁的 ,分析元素結構。
執行下述代碼,即可查看該頁面解析過後的格式。
from bs4 import BeautifulSoup
import requests
url = 'https://{}.lianjia.com/xiaoqu/pg{}y1y2y3y4y5p1p2p3p4p5p6/'
response = requests.get("https://bj.lianjia.com/xiaoqu/pg1y1y2y3y4y5p1p2p3p4p5p6/").text
soup = BeautifulSoup(response, 'lxml')
print(soup)
對上述輸出的內容稍加搜索,即可發現小區名所在頁面結構如下。可以發現在下面兩種格式中均出現了小區名,一個在圖片結構中,另一個是頁面顯示的文字,我們選取圖片結構對小區信息進行提取。
<img alt="新龍城" class="lj-lazy" data-original="https://image1.ljcdn.com/hdic-resblock/025cb5ab-9460-417e-bd4b-78868900d752.jpg.232x174.jpg" src="https://s1.ljcdn.com/feroot/pc/asset/img/blank.gif?_v=20200331145335"/>
<a href="https://bj.lianjia.com/xiaoqu/1111027381003/" target="_blank">新龍城</a>
因此我們增加一行代碼來提取 標籤中的信息並輸出。
text_list = soup.find_all('img', class_="lj-lazy")
for item in text_list:
print(item['alt'])
# 輸出結果:
# 首開康乃馨城
# 農光裏
# 理想家園
# 華貿城
# 住欣家園
# 遠洋山水
# 旗勝家園
# 小南莊社區
# ...
第三步,構造網站
首先我們考慮頁面如何構造。這個難度不大,我們只需要 一遍頁面編號即可。這個網站有一個特點在於,網站上可能只顯示了 頁,但是實際上可能有 頁…並且假如第 頁是最後一頁,那麼第 頁的內容將與第 頁保持一致。因此我們根據當前網頁是否與上一個網頁一致,來判斷當前網站爬取是否結束。
def get_housing_estate():
fo = open("data/housing_estate.txt", "w")
# 設置初始值
last = BeautifulSoup(requests.get(url.format("wz", 1)).text, 'lxml').find_all('img', class_="lj-lazy")
for city in address_list:
for page in range(1, 500):
print(city, page)
# 創建bs對象
try:
response = requests.get(url.format(city, page)).text
except:
# 頁面出錯,則更換下一個城市
break
soup = BeautifulSoup(response, 'lxml') # 使用到了lxml解析庫
text_list = soup.find_all('img', class_="lj-lazy")
# 出現重複頁面
if text_list == last:
break
last = text_list
# 寫入文件
for item in text_list:
fo.write(item['alt'] + '\n')
接下來就要考慮城市簡寫如何爬取了。我們可以根據這個網站中提供的城市分類來對網站進行爬取。
然後問題就變成了這個網站的城市名如何爬取呢?流程與上述三步一致,爬取網頁,分析結構,提取數據。此處就不再具體展開分析了,直接提供代碼,大家也可以先不看代碼,自己嘗試爬取。
def get_address():
response = requests.get("https://www.lianjia.com/city/").text
soup = BeautifulSoup(response, 'lxml')
text_list = soup.find_all('a')
for item in text_list:
if type(item.get('href')) == str and item.get('href')[0] == 'h':
value = item.get('href').split("https://")[1].split('.')[0]
if value not in address_list:
address_list.append(value)
if value == 'yw':
break
print(address_list)
3. 完整代碼
在總代碼中,筆者進行了兩項處理。
- 使用 的方式保證頁面 出錯時,項目不會崩潰
- 通過記錄前一個頁面的方式,保證爬取頁面時能及時退出
from bs4 import BeautifulSoup
import requests
address_list = []
url = 'https://{}.lianjia.com/xiaoqu/pg{}y1y2y3y4y5p1p2p3p4p5p6/'
def get_address():
response = requests.get("https://www.lianjia.com/city/").text
soup = BeautifulSoup(response, 'lxml')
text_list = soup.find_all('a')
for item in text_list:
if type(item.get('href')) == str and item.get('href')[0] == 'h':
value = item.get('href').split("https://")[1].split('.')[0]
if value not in address_list:
address_list.append(value)
if value == 'yw':
break
print(address_list)
def get_housing_estate():
fo = open("data/housing_estate.txt", "w")
last = BeautifulSoup(requests.get(url.format("wz", 1)).text, 'lxml').find_all('img', class_="lj-lazy")
for city in address_list:
for page in range(1, 500):
print(city, page)
# 創建bs對象
try:
response = requests.get(url.format(city, page)).text
except:
break
soup = BeautifulSoup(response, 'lxml') # 使用到了lxml解析庫
text_list = soup.find_all('img', class_="lj-lazy")
# 出現重複頁面
if text_list == last:
break
last = text_list
# 寫入文件
for item in text_list:
fo.write(item['alt'] + '\n')
def main():
get_address()
get_housing_estate()
if __name__ == "__main__":
main()
後記
代碼總體邏輯不難,總長度也不長,但可惜由於數據量太大,筆者爬了快 了也還沒結束…使用者需有一定的耐心…
爬取過程仍在繼續… (〃・o・〃)