Python爬虫入门实战:用requests和正则抓取安居客新房信息

发布时间:2026/10/3 4:30:08

Python爬虫入门实战:用requests和正则抓取安居客新房信息 先交代一句这篇博文写的是个人练手项目代码和思路仅用于学习交流抓取前请先确认目标网站的服务条款和robots协议控制频率、别给服务器添堵。下面进入正题。年初帮家里人看房发现手动翻安居客的新房列表特别费劲——今天看过的盘明天又要重新翻一遍价格、户型、面积这些信息散落在各个页面里想做个横向对比得靠复制粘贴效率低到让人怀疑人生。于是花了一个周末用Python写了个“能跑就行”的简易版数据抓取脚本目标只有一个把指定城市的新房列表页里的楼盘名、均价、户型、地址、标签这几项关键信息自动抓下来存成CSV方便用Excel做筛选和对比。整个项目没有用Selenium没有用Scrapy核心工具就是requests加正则表达式加上标准库里的csv和time总共一百多行代码。它解决的是“轻量、快速、够用”的问题——你不是要做大规模数据平台你只是想把某个页面的表格信息变成一张自己能用的表。这篇文章会完整拆解我的设计思路、页面分析过程、代码实现和调试时踩过的坑适合刚学完Python基础、想拿真实网站练手的人直接参考。1. 整体设计思路与技术选型1.1 为什么不用Selenium全家桶很多人一提到爬虫第一反应就是上Selenium觉得能模拟浏览器就万事大吉。但在这个项目里Selenium是明显杀鸡用牛刀——它的启动速度慢、内存占用高还得额外维护浏览器驱动版本为了抓一个静态列表页完全不值得。我实测过Selenium启动Chrome差不多要两三秒加上页面渲染等待一个页面跑下来五六秒很正常而用requests直接请求同样的页面基本在一秒内完成十页数据也就是十几秒的事。当然Selenium有它不可替代的场景比如页面内容靠JavaScript动态渲染、需要模拟点击翻页、要绕过复杂的交互验证。但安居客的新房列表页恰好是服务端渲染的HTML里直接带着完整的数据这就给轻量方案留足了空间。先打开浏览器开发者工具看一眼页面源码确认数据在不在HTML里再决定用什么方案这是爬虫项目选型的第一步。1.2 requests加正则的轻量组合requests负责把网页源码拿回来正则表达式负责从源码里把目标数据抠出来。很多人觉得正则难写、难调试但在处理结构比较规整的HTML时它反而是最快的工具——不需要解析DOM树不需要关心标签嵌套只要目标字段附近的HTML特征足够稳定一行正则就能解决问题。在这个项目里每个楼盘的基本信息都被包在div classitem-mod这个容器里楼层、户型、面积、地址这些字段各有固定的class名。比如楼盘名在span classitems-name里均价在span classprice-num里。这种结构下直接用正则从整个页面源码里圈出每一个楼盘块再从每个块里提取具体字段逻辑非常清晰。选择正则还有一个现实原因目标站点的页面结构偶尔会调整但大部分字段的class命名规律都保留着出问题时定位代码、改正则的成本比重新调试一套XPath解析逻辑要低得多。后面我会详细说正则和XPath的取舍。2. 页面分析与数据点定位2.1 找到目标页面与关键参数开始写代码之前先在浏览器里手动打开目标城市的安居客新房频道按F12进入开发者工具切到Network面板刷新页面找到第一个文档请求看它的响应内容。这一步的目的是确认html里是否直接包含楼盘数据。我以北京为例新房频道首页地址是https://beijing.anjuke.com/fangjia/之类但实际列表页通常长这样https://beijing.anjuke.com/loupan/?fromnavigation。打开后往下滚动能看到一整个楼盘列表每个楼盘一个卡片块。我随机右键一个楼盘名选择“检查”定位到对应的HTML元素发现结构大概是div classitem-mod a classlp-name hrefhttps://beijing.anjuke.com/loupan/xxx.html span classitems-name某某楼盘/span /a p classaddress北京市大兴区XX路与XX街交汇处/p span classprice-num58000/span span classunit-price元/㎡/span div classtags span近地铁/span span品牌房企/span /div p classarea3室/89㎡/p /div这个结构就是整个项目的地基。你不需要理解每一行HTML只需要确认两件事第一数据确实在HTML源码里第二目标字段的class名称是稳定且有规律的。这两点确认后后面的正则提取就是水到渠成的事。还有一个关键参数在这个页面里藏着翻页时URL会多出p参数比如https://beijing.anjuke.com/loupan/p2/。把这个规律找到后循环页码就只需要改一个数字。2.2 用正则把字段从一个HTML块里抠出来拿到页面结构后第一版提取方案是先整页匹配所有楼盘块再逐块提取字段。这里有一个很关键的经验不要试图用一个超级复杂的正则把整页所有字段一次性提出来那样出错时你根本不知道是哪里匹配失败了。正确的做法是分两步走——先用一个范围正则切出每个楼盘的HTML片段再在小片段里做细粒度提取。切分楼盘块的正则长这样pattern_block re.compile(rdiv classitem-mod(.*?)/div, re.S) blocks pattern_block.findall(html)re.S这个flag必须加它让.能匹配换行符。因为一个楼盘块的HTML可能跨多行不加这个flag匹配就会失败。提取出来之后每个block就是一段独立的楼盘HTML接下来在block里找字段就简单多了name re.search(rspan classitems-name(.*?)/span, block) price re.search(rspan classprice-num(.*?)/span, block) address re.search(rp classaddress(.*?)/p, block)如果某个字段提取不到最可能的原因是页面结构调整或者该楼盘信息不完整。我的处理方式是写一个小函数匹配不到就返回空字符串而不是让整个程序报错退出——爬虫项目里单个数据缺失是常态程序要能容忍“脏数据”。2.3 去重与后续扩展列表页存在重复数据的情况不少比如同一楼盘出现在不同的推荐位或者多页列表之间存在交叉。因此我在代码里加了一个简单的去重逻辑维护一个已经见过的楼盘名集合新抓到的楼盘名如果已在集合里就跳过。这个逻辑简单、有效而且不依赖任何第三方库。至于后续扩展比如想抓详情页的更多信息思路也很直接从列表页拿到每个楼盘的详情链接lp-name里那个href然后对详情页重复同样的“请求——解析——提取”流程。这个项目先不做详情页但链接字段我有专门提取并保存下来方便以后扩展。3. 代码实现与运行流程3.1 完整代码下面是这个简易版爬虫的完整代码。我刻意把逻辑写得线性、直接没有封装成类就是为了让刚入门的人能一眼看懂主流程。所有关键步骤都加了注释直接复制到本地把city_url换成你想抓的城市列表页地址就能跑起来。import requests import re import csv import time headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36, Referer: https://www.anjuke.com/, Accept-Language: zh-CN,zh;q0.9, } # 北京新房列表页翻页通过 p 参数控制 base_url https://beijing.anjuke.com/loupan/p{page}/ pattern_block re.compile(rdiv classitem-mod(.*?)/div, re.S) pattern_name re.compile(rspan classitems-name(.*?)/span) pattern_price re.compile(rspan classprice-num(.*?)/span) pattern_address re.compile(rp classaddress(.*?)/p) pattern_rooms re.compile(rp classarea(.*?)/p) pattern_tags re.compile(rdiv classtags(.*?)/div, re.S) pattern_tag re.compile(rspan(.*?)/span) pattern_link re.compile(ra classlp-name href(.*?)) def get_html(url): try: resp requests.get(url, headersheaders, timeout10) resp.raise_for_status() resp.encoding utf-8 return resp.text except Exception as e: print(f[请求失败] {url} - {e}) return def extract_field(block, pattern): m pattern.search(block) return m.group(1).strip() if m else def clean_tag_text(raw): # 把标签块里的HTML标签去掉只留文本 s re.sub(r.*?, , raw) s s.replace(\n, ).replace( , ) return s def crawl_page(page): url base_url.format(pagepage) html get_html(url) if not html: return [] blocks pattern_block.findall(html) result [] for block in blocks: name extract_field(block, pattern_name) if not name: continue price extract_field(block, pattern_price) address extract_field(block, pattern_address) rooms extract_field(block, pattern_rooms) tags_raw extract_field(block, pattern_tags) tags clean_tag_text(tags_raw) if tags_raw else link extract_field(block, pattern_link) result.append({ 楼盘名: name, 均价: price, 户型面积: rooms, 地址: address, 标签: tags, 链接: link, }) return result def main(): all_data [] seen set() # 抓第1到第5页演示用想抓更多就改 range for page in range(1, 6): print(f正在抓取第 {page} 页...) page_data crawl_page(page) for item in page_data: if item[楼盘名] in seen: continue seen.add(item[楼盘名]) all_data.append(item) print(f第 {page} 页抓到 {len(page_data)} 条累计 {len(all_data)} 条) time.sleep(2) # 礼貌延时别给服务器添堵 if not all_data: print(没有抓到任何数据请检查页面结构或请求头) return with open(anjuke_newhouse.csv, w, newline, encodingutf-8-sig) as f: writer csv.DictWriter(f, fieldnames[楼盘名, 均价, 户型面积, 地址, 标签, 链接]) writer.writeheader() writer.writerows(all_data) print(f完成共保存 {len(all_data)} 条数据到 anjuke_newhouse.csv) if __name__ __main__: main()3.2 代码关键点解析有几个地方值得单独拿出来讲一讲。第一是请求头的Referer字段。很多网站会校验请求来源如果直接请求列表页而Referer为空或者来自搜索引擎服务器可能会返回异常页面。我虽然不确定安居客对Referer的校验有多严格但把浏览器的常规请求头完整带上是每个爬虫项目都应该养成的习惯成本几乎为零却能减少很多不必要的麻烦。第二是resp.encoding utf-8。有些库会根据响应头猜编码猜错时中文会变成乱码。强制指定utf-8能避免大部分乱码问题。如果你抓的页面实际是gbk编码这里就要改成gbk怎么判断打印一小段源码出来看中文是否正常即可。第三是保存CSV时用了encodingutf-8-sig。这个细节很关键用普通的utf-8保存Excel直接打开会乱码而utf-8-sig会在文件开头写入BOM标记Excel就能正确识别编码。这是我在实际使用中被坑过一次才记住的。第四是time.sleep(2)。每抓一页歇两秒这个延时不是为了装样子而是对目标服务器最基本的尊重。频率太高容易被封IP封了之后不仅这个项目跑不了还可能影响你正常浏览网站。后面我会专门说频率控制的问题。3.3 运行流程与结果代码的运行流程很直接main函数从第1页循环到第5页每页调用crawl_page抓取并解析解析结果先查重再存进总列表最后统一写入CSV。实际运行效果大概是这样的输出正在抓取第 1 页... 第 1 页抓到 20 条累计 20 条 正在抓取第 2 页... 第 2 页抓到 20 条累计 40 条 ... 完成共保存 100 条数据到 anjuke_newhouse.csv生成的CSV在Excel里打开后就是一列楼盘名、一列均价、一列户型面积清清楚楚。我当时拿这个表做了一个简单的筛选均价在5万以下、有“近地铁”标签的楼盘。整个过程不到一分钟比手动翻网页舒服太多了。4. 常见问题与排查实录4.1 请求被拒或返回验证页面我把代码跑通之后第二天再运行突然发现抓不到任何数据打印出来的HTML源码里全是登录框和验证码。这种情况大概率是IP被临时限制或者触发了网站的反爬策略。排查思路是先在浏览器里手动访问目标页面看能否正常打开。如果能打开说明内容没问题问题在请求环节——试着更换User-Agent、降低抓取频率、增加随机延时。如果换UA还不行就考虑用代理IP但这就超出“简易版”的范畴了我建议先休息一段时间再继续抓。爬虫项目里反爬对抗的本质是“别让对方觉得你是机器”频率控制永远是最重要的手段。4.2 字段提取为空或格式错乱如果CSV里某些行的“均价”是空的先别急着改代码。用浏览器打开对应的楼盘详情页检查列表页里这个楼盘是不是本身就没展示价格。新房列表页里“价格待定”的楼盘很常见这种楼盘在HTML里根本没有price-num这个节点所以正则匹配不到是正常的返回空字符串符合预期。真正需要警惕的是另一种情况某一类字段大面积为空。这说明页面结构可能变了比如class名改了或者整个列表的DOM结构换了。这种时候要做的是回到浏览器里重新检查元素对比之前记录的结构差异针对性更新正则即可。没有一劳永逸的爬虫页面改版是家常便饭做好定期维护的心理准备。4.3 保存CSV后乱码CSV用Excel打开乱码几乎都是编码问题。我在前面已经提过用utf-8-sig这里再补充一个细节如果你是用记事本或者VS Code打开CSVutf-8-sig显示也完全正常不会出现奇怪的字符。所以这个编码可以无脑用。还有一个容易忽略的问题如果某个字段内容里本身包含逗号或者换行直接用csv.DictWriter写入是没问题的库会自动处理引号转义。但如果你是自己用字符串拼CSV就一定要小心逗号否则列会对不齐。这也是我建议用csv库而不是手动拼字符串的原因。4.4 抓取频率与合规性这个项目只是个人学习练手抓的是公开的列表信息量也很小但我还是想多说两句合规性的事。爬虫不是不能写关键要记住三条底线第一遵守robots协议和网站服务条款如果站方明确禁止抓取就别碰第二控制频率和总量不要对目标服务器造成压力第三抓到的数据不要用于商业用途不要批量转售尤其是涉及个人隐私的数据碰都不要碰。把这些原则放在心里写爬虫会踏实很多。我见过有人为了跑数据把人家网站打到宕机的那已经不是技术问题是法律问题了没必要。写在最后这个项目最让我受益的一点是它把Python基础语法里的requests请求、正则表达式、文件读写、循环和异常处理全部串起来用在一个真实场景里。你可以在课本里学一万遍正则语法不如亲手写一个re.search从一个HTML块里抠出楼盘名来得印象深刻。学习爬虫的最好方式就是找一个结构规整的静态页面像我这样反复练习。还有一个小技巧送给你写这类解析代码时不要一上来就写完整版。先把HTML保存到本地文件用脚本读本地文件做解析调试通过后再换成requests在线抓取。这样既能节省请求次数、降低被封风险又能大幅提高调试效率。我后来做所有解析类脚本都沿用这个习惯可以说屡试不爽。
延伸阅读

更多相关文章

2026/10/3 4:30:08

主观题自动阅卷系统设计:基于TF-IDF和余弦相似度的Python实现

简介:这套基于Python的主观题自动阅卷系统毕业设计资源,完整覆盖前后端开发、MySQL数据库与说明文档,面向计算机相关专业学生或需要教学评分自动化方案的开发者,可参考其从需求分析、系统设计到智能评分的全过程。压缩包包含320个…

2026/10/3 4:25:08

深圳2020 POI数据清洗与坐标统一实战指南

简介:本资源为深圳市2020年高实用性GIS地理信息数据集,面向城市规划、交通管理、商业选址及地理信息科研领域的初/中级用户,解决多源POI与地形基础数据缺失、格式不统一、空间分析门槛高等实际问题。压缩包共137个文件,54.04MB&am…

2026/10/3 5:15:10

hindsight:用本地大模型自动复盘数字生活,生成决策建议

"古人说以史为鉴,但现代人的数字生活,其实比任何王朝史书都更详细、更琐碎,也更能暴露真实的决策轨迹。今天要聊的这个项目,名字叫hindsight,它是典型的事后复盘工具。说白了,就是把你过去在电脑、手机…

2026/10/3 5:15:10

企业AI Agent落地实战:从智能体设计到基础设施建设

1. 这份报告不是“预测”,而是企业AI落地的路线图沙盘你点开这份标题写着“2026中国AI Agent企业应用市场预测报告”的PDF,第一眼看到的可能是一堆增长率曲线、市场份额饼图、厂商排名表格——但如果你真把它当普通行业预测报告来读,大概率会…

2026/10/3 5:15:10

GPT-6 Sol/Luna API降价与Astra下放:开发者接入指南与踩坑实录

GPT-6 Sol和Luna一上线,我朋友圈和几个技术群里就开始刷屏了。倒不是大家突然对官方公告这么热情,而是这两件事确实戳中了做AI应用的人的痛点:一是Astra能力下放到常规型号,二是API价格直接砍半。说实话,这两条放在一起…

2026/10/3 5:15:10

MQTT实战指南:从协议原理到Mosquitto部署与硬件接入

1. 为什么是MQTT?先搞懂协议到底解决了什么问题1.1 从一次设备联网折腾说起:HTTP为什么不够用大概在2018年,我接了一个智能网关的项目,十几个传感器节点通过串口、Modbus、4G DTU混着往上送数据。最开始图省事,直接用H…

2026/10/3 5:15:10

Unity热更新安全排查:CDN与本地缓存全链路防护方案

1. 项目概述:为什么热更新安全排查不是“锦上添花”,而是上线前的生死线你有没有遇到过这样的情况:游戏版本刚发出去,玩家反馈“进图黑屏”“UI错位”“技能特效消失”,回滚版本后一切正常?查日志发现报错是…

2026/10/3 5:10:09

游戏更新后闪退、卡死、掉帧?5步排查法,不用重装系统

先说结论:这次更新之后爆出来的闪退、开局卡死、人多掉帧,绝大部分不是电脑硬件不行,也不是系统坏了,而是更新文件、显卡驱动、反作弊组件和渲染缓存之间互相打架。我自己的机器也中招了,折腾了一晚上才摸清楚整个排查…

2026/10/2 8:16:46

东莞市品牌网站建设报价常见报错与解决

东莞品牌网站建设报价单背后:一份保姆级建站教程避坑实录 网站做好了没人访问,这大概是很多老板最头疼的事。花了大几万做的品牌站,上线后流量惨淡,比路边摊还冷清。别急着骂外包公司,很多“东莞品牌网站建设报价”里藏着不少猫腻,比如用模板站冒充定制…

2026/10/2 18:20:53

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解 【免费下载链接】spirula-studio Cross-vendor 3D Gaussian Splatting trainer - video to splat to mesh, Vulkan or CUDA. 项目地址: https://gitcode.com/GitHub_Trending/sp/spirula-studio Sp…

2026/10/1 10:48:55

SEO怎么推广速查手册新手避坑实战指南

SEO怎么推广速查手册新手避坑实战指南 模板网站太丑不够用?别急着加滤镜,那是治标不治本。很多老板盯着后台流量掉得眼红,却还在纠结首页Banner的圆角是不是3像素。这就像穿着西装去挖土,姿势不对,努力白费。我整理这份 速查手册…

2026/10/3 0:04:31

国内大学生必备的AI写作辅助软件是哪款?

国内高校学生在论文写作过程中,越来越依赖AI辅助工具提升效率,主流方案以本土化全流程工具为核心,结合通用大模型与专业插件,覆盖选题构思、框架搭建、初稿撰写、查重降重、格式调整等关键环节,本文将深入解析当前主流…

2026/10/3 0:04:31

Codex接入Jev模型完整指南:配置方法、本地部署与踩坑排查

最近不少人在讨论 Codex 搭配 Jev 这套玩法,我一开始没太当回事,直到自己把 Jev 接进 Codex跑了几轮编码任务之后,才明白那些说“直接起飞”的人是怎么想的。Codex 作为工具本身已经够能打了,但模型固定、上下文策略固定&#xff…

2026/10/3 0:04:31

GitHub 热门: NVIDIA/Model-Optimizer

👋 Hi,我擅长 AI 大模型应用落地、意识解码与 AI 开发工具链 。 💡 创业路上,用技术换时间,一起把 AI 变成生产力 🚀 >GitHub 热门: NVIDIA/Model-Optimizer 凌晨两点,你刚把跑通了的 Qwen3.…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑