目錄
- 2025年安居客二手小區數據爬取
- 觀察目標網頁
- 觀察詳情頁數據
- 準備工作:安裝裝備就像打游戲
- 代碼詳解:每行代碼都是你的小兵
- 完整代碼大放送
- 爬取結果
2025年安居客二手小區數據爬取
這段時間需要爬取安居客二手小區數據,看了一下相關教程基本也都有點久遠,趁著新年期間我也把自己爬取的思路跟流程記錄一下(適合有一點爬蟲基礎的寶寶食用),如有不對,歡迎私信交流~
觀察目標網頁
我們這里爬取的是安居客二手小區數據,從官網進去
這里看到小區的總數量,以及相關的小區的名字等信息,紅框框起來的數據一般是我們所關心的
當然,點擊小區可以進入詳情頁,這里列出了關于該小區更加具體的信息,我們這里嘗試把框起來的數據都爬取下來!
知道了我們需要爬取的數據之后,下一步我們需要進一步分析這些數據的來源——數據是寫在靜態網頁中還是從服務器異步加載過來的,讓我們分析一下網頁結構:
從上面這張圖里我們可以發現數據是寫在了html的源碼里的,每個小區的數據都包裹在一個li-row的a標簽里面,因此我們只需要把list-cell里面的所有li-row都遍歷一遍,就可以獲取一頁的小區相關數據,當然這里還沒包含詳情頁數據~
觀察詳情頁數據
我們可以發現這個小區詳情頁的數據會存放在maininfo的div大盒子里面,然后這個大盒子里由house-price跟info兩個div小盒子組成,因此我們只需要從這兩個小盒子里取數據即可~下面開始搓我們的代碼!
準備工作:安裝裝備就像打游戲
1?? 裝Python環境(不會的看這里)
👉 去Python官網下載最新版,安裝時記得勾選"Add Python to PATH"
2?? 安裝必備武器庫(打開cmd / powershell)
pip install requests beautifulsoup4
💡 這倆庫相當于你的"爬蟲工具箱",一個負責上網,一個負責解析網頁
3?? 準備VIP通行證 (Cookie獲取)
cookie的作用可以讓我們在模擬登陸的時候維持一下會話,因為安居客這個網站每隔一段時間就需要輸入一下驗證碼或者重新登陸,設置一下cookie方便很多!!!
具體自己瀏覽器的cookie在登陸之后,按F12打開開發者工具,找到Network標簽 → 刷新頁面 → 隨便選個請求 → 復制一下響應標頭里的set-cookie里的內容即可~
代碼詳解:每行代碼都是你的小兵
🛠? 先看整體作戰計劃:
"""
作戰目標:自動抓取指定數量的小區信息
作戰路線:列表頁 → 詳情頁 → 數據保存
武器配置:requests發請求,BeautifulSoup解析
特殊裝備:自動重試機制防掉線
"""
🎯 核心代碼拆解(重點!)
- 配置偵察兵參數
# 偽裝成瀏覽器(重要!)
HEADERS = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)...' # 完整UA太長省略
}# 你的VIP通行證(定期更新!)
COOKIES = {'ajkAuthTicket': 'TT=3f67c23d85c369b7018fcb4e...', # 填你復制的Cookie'ctid': '24'
}
- 創建不死鳥連接器
def create_session():session = requests.Session()# 配置自動重試(網絡不好也不怕)adapter = HTTPAdapter(max_retries=Retry(total=3, backoff_factor=1,status_forcelist=[500, 502, 503, 504]))session.mount('https://', adapter)return session
💡 這個相當于你的"網絡保鏢",遇到問題自動重試三次
3. 萬能數據提取器
def safe_get_text(element, selector, default='N/A'):""" 安全提取文本,找不到元素也不報錯 """target = element.select_one(selector)return target.text.strip() if target else default
🌟 使用場景:就像用鑷子精準夾取頁面數據,夾不到就返回默認值
4. 主力作戰部隊(main函數)
def main():# 輸入要抓多少小區community_count = int(input("想抓多少小區?輸入數字:"))# 創建偵察兵小隊with open('小區數據.csv', 'w', encoding='utf-8') as f:writer = csv.writer(f)writer.writerow(['小區名稱', '價格', '地址', ...]) # 完整表頭# 開始翻頁抓取for page in range(1, 總頁數+1):# 獲取當前頁所有小區鏈接# 逐個訪問詳情頁提取數據# 保存到CSV# 休息0.5秒防止被封
💡 這里用了with open自動管理文件,就像有個小秘書幫你保存數據
完整代碼大放送
"""
安居客小區信息爬蟲
"""
import csv
import time
import requests
from requests.adapters import HTTPAdapter
from requests.packages.urllib3.util.retry import Retry
from bs4 import BeautifulSoup# ========================== 全局配置 ==========================
# 請求頭配置(模擬瀏覽器訪問)
HEADERS = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36 Edg/132.0.0.0','Referer': 'https://member.anjuke.com/','Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
}# Cookies配置(需要定期更新)
COOKIES = {'ajkAuthTicket': 'TT=3f67c23d85c369b7018fcb4e1418466f&TS=1738219179437&PBODY=IotzzfNhkTJKGH_LuUrSfcNHUGin1wBsHjAQYBL3k0USZDHrUxL6RQUv1ZsFPDHjxvQl0uvU2zSgIEdSFCHUc7wYEf4slKV2U2F9rwNnp6xHgufTxMgdYWZEob_Tep-poDqBMbQQgayOQhsaRgVjw8K8ut3QqqMfPgYGpKJJBHw&VER=2&CUID=fzgJGetduRhII81NXadF-HKyO1Hvr8W-','ctid': '24',
}# 重試策略配置
RETRY_STRATEGY = Retry(total=3, # 最大重試次數backoff_factor=1, # 重試等待時間因子status_forcelist=[500, 502, 503, 504], # 需要重試的狀態碼allowed_methods=frozenset(['GET', 'POST']) # 允許重試的HTTP方法
)# 其他配置
BASE_URL = 'https://foshan.anjuke.com/community/p{page}/' # 分頁URL模板
REQUEST_DELAY = 0.5 # 請求間隔時間(秒),防止被封禁
CSV_HEADERS = [ # CSV文件表頭'小區名稱', '價格', '地址', '小區鏈接','物業類型', '權屬類別', '竣工時間', '產權年限', '總戶數', '總建筑面積', '容積率', '綠化率', '建筑類型', '所屬商圈', '統一供暖', '供水供電', '停車位', '物業費','停車費', '車位管理費', '物業公司', '小區地址', '開發商', '在售房源', '在租房源'
]# ========================== 工具函數 ==========================
def create_session():"""創建帶有重試策略的請求會話返回:requests.Session - 配置好的會話對象"""session = requests.Session()adapter = HTTPAdapter(max_retries=RETRY_STRATEGY)session.mount('https://', adapter)session.mount('http://', adapter)return sessiondef safe_get_text(element, selector, default='N/A'):"""安全獲取元素文本內容參數:element: BeautifulSoup對象 - 父元素selector: str - CSS選擇器default: str - 默認返回值返回:str - 元素的文本內容或默認值"""target = element.select_one(selector)return target.get_text(strip=True) if target else default# ========================== 主程序 ==========================
def main():# 用戶輸入community_count = int(input("請輸入需要抓取的小區數量:"))# 初始化會話session = create_session()# 準備CSV文件with open('communities.csv', mode='w', newline='', encoding='utf-8') as csv_file:writer = csv.writer(csv_file)writer.writerow(CSV_HEADERS)page_count = (community_count // 25) + (1 if community_count % 25 else 0)collected = 0 # 已收集數量# 分頁抓取for current_page in range(1, page_count + 1):print(f"\n? 正在處理第 {current_page}/{page_count} 頁...")# 獲取列表頁try:list_url = BASE_URL.format(page=current_page)response = session.get(list_url,headers=HEADERS,cookies=COOKIES,timeout=10)response.raise_for_status()except Exception as e:print(f"?? 列表頁請求失敗: {e}")continue# 解析小區列表list_soup = BeautifulSoup(response.text, 'html.parser')communities = list_soup.find_all('a', class_='li-row')# 遍歷每個小區for community in communities:if collected >= community_count:break# 提取基本信息name = safe_get_text(community, 'div.li-title')price = safe_get_text(community, 'div.community-price')address = safe_get_text(community, 'div.props')link = community.get('href', '')print(f"\n▌ 正在處理小區:{name}")# 獲取詳情頁try:detail_response = session.get(link,headers=HEADERS,cookies=COOKIES,timeout=15)detail_response.raise_for_status()except Exception as e:print(f" ?? 詳情頁請求失敗: {e}")continue# 解析詳情頁detail_soup = BeautifulSoup(detail_response.text, 'html.parser')details = []# 提取主要信息for index in range(14): # 0-13對應預設的標簽value = safe_get_text(detail_soup, f'div.value.value_{index}')details.append(value)# 提取額外信息extra_info = {'停車費': 'N/A','車位管理費': 'N/A','物業公司': 'N/A','小區地址': 'N/A','開發商': 'N/A'}for column in detail_soup.find_all('div', class_='column-1'):label = safe_get_text(column, 'div.label')value = safe_get_text(column, 'div.value')for key in extra_info:if key in label:extra_info[key] = value# 提取房源信息sale = detail_soup.find('div', class_='sale')rent = detail_soup.find('div', class_='rent')sale_info = f"{safe_get_text(sale, 'i.source-number')} {safe_get_text(sale, 'i.source-unit')}" if sale else 'N/A'rent_info = f"{safe_get_text(rent, 'i.source-number')} {safe_get_text(rent, 'i.source-unit')}" if rent else 'N/A'# 構建完整數據行row = [name, price, address, link,*details,*extra_info.values(),sale_info, rent_info]# 寫入CSVwriter.writerow(row)collected += 1print(f" ? 已保存 {collected}/{community_count} - {name}")# 請求間隔time.sleep(REQUEST_DELAY)print("\n🎉 數據抓取完成!結果已保存到 communities.csv")if __name__ == '__main__':main()
爬取結果
這是爬取的結果,如果只要其中的部分列,我建議直接刪除最終的csv表格,而不是修改代碼,代碼能運行就盡量別動 -_-!!!
完結撒花~
參考文章:
[1]: 菜鳥爬蟲——獲取安居客二手房信息
[2]:Python爬蟲之路(9)–an居客數據獲取
[3]:Python之爬取安居客網二手房小區詳情頁數據
[4]:python使用代理爬取安居客二手房數據(一)
[5]:(項目)爬取安居客二手房房屋信息
[6]:【爬蟲】安居客二手房數據爬取