如何使用 python 爬取全國小區名稱

前言

筆者在做一個 NLPNLP 項目時,需要識別小區名,因此想要查詢網上是否有相關的數據集。經過一番搜索後一無所獲…從而決定自己來爬取這份數據。

由於爬取網站的內容信息之後可能會發生變更,因此此處給出具體的爬蟲思路,便於應對之後的網站結構變更。


方法

1. 爬取網站的確定

既然是爬蟲,那首先就需要確定爬取網站。這時候就需要思考哪些網站可能會涉及小區名字?

  1. 國家統計網?經過一番搜索,沒找到…
  2. 房屋中介網?

因此我們可以選取比較知名的房屋中介網來進行小區名爬取,此處選取的網站是鏈家,原因是該網站有專門的小區板塊。鏈家
在這裏插入圖片描述

2. 網站結構分析

由於鏈家對於不同城市,建立了不同的網頁,因此我們以北京的網頁舉例。

第一步,選中所有選項,查看當前網址。
https://bj.lianjia.com/xiaoqu/pg1y1y2y3y4y5p1p2p3p4p5p6/

多查看幾個網頁,就可以發現上述網址的共性,bj 是城市縮寫,pg1 是頁面編號。
在這裏插入圖片描述

第二步,查看當前網頁的 HtmlHtml,分析元素結構。

執行下述代碼,即可查看該頁面解析過後的格式。

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>

因此我們增加一行代碼來提取 imgimg 標籤中的信息並輸出。

text_list = soup.find_all('img', class_="lj-lazy")
for item in text_list:
    print(item['alt'])
# 輸出結果:
# 首開康乃馨城
# 農光裏
# 理想家園
# 華貿城
# 住欣家園
# 遠洋山水
# 旗勝家園
# 小南莊社區
# ...
第三步,構造網站 urlurl

首先我們考慮頁面如何構造。這個難度不大,我們只需要 forfor 一遍頁面編號即可。這個網站有一個特點在於,網站上可能只顯示了 3030 頁,但是實際上可能有 100100 頁…並且假如第 100100 頁是最後一頁,那麼第 101101 頁的內容將與第 100100 頁保持一致。因此我們根據當前網頁是否與上一個網頁一致,來判斷當前網站爬取是否結束。

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. 完整代碼

在總代碼中,筆者進行了兩項處理。

  1. 使用 trycatchtry-catch 的方式保證頁面 urlurl 出錯時,項目不會崩潰
  2. 通過記錄前一個頁面的方式,保證爬取頁面時能及時退出
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()


後記

代碼總體邏輯不難,總長度也不長,但可惜由於數據量太大,筆者爬了快 1h1h 了也還沒結束…使用者需有一定的耐心…
在這裏插入圖片描述
爬取過程仍在繼續… (〃・o・〃)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章