Python安居客二手小区数据爬取(2025年)

news2025/2/2 20:03:19

目录

  • 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解析
特殊装备:自动重试机制防掉线
"""

🎯 核心代码拆解(重点!)

  1. 配置侦察兵参数
# 伪装成浏览器(重要!)
HEADERS = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)...'  # 完整UA太长省略
}

# 你的VIP通行证(定期更新!)
COOKIES = {
    'ajkAuthTicket': 'TT=3f67c23d85c369b7018fcb4e...',  # 填你复制的Cookie
    'ctid': '24'
}
  1. 创建不死鸟连接器
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 session

def 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
                ]
                
                # 写入CSV
                writer.writerow(row)
                collected += 1
                print(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]:【爬虫】安居客二手房数据爬取

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2290922.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

happytime

happytime 一、查壳 无壳,64位 二、IDA分析 1.main 2.cry函数 总体:是魔改的XXTEA加密 在main中可以看到被加密且分段的flag在最后的循环中与V6进行比较,刚好和上面v6数组相同。 所以毫无疑问密文是v6. 而与flag一起进入加密函数的v5就…

深度学习 DAY3:NLP发展史

NLP发展史 NLP发展脉络简要梳理如下: (远古模型,上图没有但也可以算NLP) 1940 - BOW(无序统计模型) 1950 - n-gram(基于词序的模型) (近代模型) 2001 - Neural language models&am…

家居EDI:Hom Furniture EDI需求分析

HOM Furniture 是一家成立于1977年的美国家具零售商,总部位于明尼苏达州。公司致力于提供高品质、时尚的家具和家居用品,满足各种家庭和办公需求。HOM Furniture 以广泛的产品线和优质的客户服务在市场上赢得了良好的口碑。公司经营的产品包括卧室、客厅…

【08-飞线和布线与输出文件】

导入网表后 1.复制结构图(带板宽的) 在机械一层画好外围线 2.重新定义板子形状(根据选则对象取定义) 选中对象生成板子线条形状 3.PCB和原理图交叉选择模式 过滤器选择原理图里的元器件 过滤器"OFF",只开启Componnets,只是显示元器件 4. 模块化布局 PCB高亮元…

【单细胞第二节:单细胞示例数据分析-GSE218208】

GSE218208 1.创建Seurat对象 #untar(“GSE218208_RAW.tar”) rm(list ls()) a data.table::fread("GSM6736629_10x-PBMC-1_ds0.1974_CountMatrix.tsv.gz",data.table F) a[1:4,1:4] library(tidyverse) a$alias:gene str_split(a$alias:gene,":",si…

ZZNUOJ(C/C++)基础练习1031——1040(详解版)

1031 : 判断点在第几象限 题目描述 从键盘输入2个整数x、y值,表示平面上一个坐标点,判断该坐标点处于第几象限,并输出相应的结果。 输入 输入x,y值表示一个坐标点。坐标点不会处于x轴和y轴上,也不会在原点。 输出 输出…

【C语言】main函数解析

文章目录 一、前言二、main函数解析三、代码示例四、应用场景 一、前言 在学习编程的过程中,我们很早就接触到了main函数。在Linux系统中,当你运行一个可执行文件(例如 ./a.out)时,如果需要传入参数,就需要…

深度学习练手小例子——cifar10数据集分类问题

CIFAR-10 是一个经典的计算机视觉数据集,广泛用于图像分类任务。它包含 10 个类别的 60,000 张彩色图像,每张图像的大小是 32x32 像素。数据集被分为 50,000 张训练图像和 10,000 张测试图像。每个类别包含 6,000 张图像,具体类别包括&#x…

【Git】初识Git Git基本操作详解

文章目录 学习目标Ⅰ. 初始 Git💥注意事项 Ⅱ. Git 安装Linux-centos安装Git Ⅲ. Git基本操作一、创建git本地仓库 -- git init二、配置 Git -- git config三、认识工作区、暂存区、版本库① 工作区② 暂存区③ 版本库④ 三者的关系 四、添加、提交更改、查看提交日…

【JavaEE进阶】应用分层

目录 🎋序言 🍃什么是应用分层 🎍为什么需要应用分层 🍀如何分层(三层架构) 🎄MVC和三层架构的区别和联系 🌳什么是高内聚低耦合 🎋序言 通过上⾯的练习,我们学习了SpringMVC简单功能的开…

【数据结构篇】时间复杂度

一.数据结构前言 1.1 数据结构的概念 数据结构(Data Structure)是计算机存储、组织数据的⽅式,指相互之间存在⼀种或多种特定关系的数 据元素的集合。没有⼀种单⼀的数据结构对所有⽤途都有⽤,所以我们要学各式各样的数据结构, 如&#xff1a…

【数据结构】_链表经典算法OJ(力扣/牛客第二弹)

目录 1. 题目1:返回倒数第k个节点 1.1 题目链接及描述 1.2 解题思路 1.3 程序 2. 题目2:链表的回文结构 2.1 题目链接及描述 2.2 解题思路 2.3 程序 1. 题目1:返回倒数第k个节点 1.1 题目链接及描述 题目链接: 面试题 …

深度学习之“缺失数据处理”

缺失值检测 缺失数据就是我们没有的数据。如果数据集是由向量表示的特征组成,那么缺失值可能表现为某些样本的一个或多个特征因为某些原因而没有测量的值。通常情况下,缺失值由特殊的编码方式。如果正常值都是正数,那么缺失值可能被标记为-1…

MYSQL--一条SQL执行的流程,分析MYSQL的架构

文章目录 第一步建立连接第二部解析 SQL第三步执行 sql预处理优化阶段执行阶段索引下推 执行一条select 语句中间会发生什么? 这个是对 mysql 架构的深入理解。 select * from product where id 1;对于mysql的架构分层: mysql 架构分成了 Server 层和存储引擎层&a…

C++解决输入空格字符串的三种方法

一.gets和fgets char * gets ( char * str ); char * fgets ( char * str, int num, FILE * stream ); 1. gets 是从第⼀个字符开始读取,⼀直读取到 \n 停⽌,但是不会读取 \n ,也就是读取到的内容 中没有包含 \n ,但是会在读取到的内…

多模态论文笔记——NaViT

大家好,这里是好评笔记,公主号:Goodnote,专栏文章私信限时Free。本文详细解读多模态论文NaViT(Native Resolution ViT),将来自不同图像的多个patches打包成一个单一序列——称为Patch n’ Pack—…

云中漫步:精工细作铸就免费公益刷步平台

云中漫步,历经三年深度研发与优化,平台以高稳定性、零成本及公益属性为核心特色,依托前沿技术手段与多重安全防护机制,确保用户步数数据的精准修改与隐私安全。我们致力于提供无缝流畅的用户体验,让每一次步数更新都轻…

neo4j入门

文章目录 neo4j版本说明部署安装Mac部署docker部署 neo4j web工具使用数据结构图数据库VS关系数据库 neo4j neo4j官网Neo4j是用ava实现的开源NoSQL图数据库。Neo4作为图数据库中的代表产品,已经在众多的行业项目中进行了应用,如:网络管理&am…

【ts + java】古玩系统开发总结

src别名的配置 开发中文件和文件的关系会比较复杂,我们需要给src文件夹一个别名吧 vite.config.js import { defineConfig } from vite import vue from vitejs/plugin-vue import path from path// https://vitejs.dev/config/ export default defineConfig({pl…

【Docker】快速部署 Nacos 注册中心

【Docker】快速部署 Nacos 注册中心 引言 Nacos 注册中心是一个用于服务发现和配置管理的开源项目。提供了动态服务发现、服务健康检查、动态配置管理和服务管理等功能,帮助开发者更轻松地构建微服务架构。 仓库地址 https://github.com/alibaba/nacos 步骤 拉取…