前段时间有人问我:用 Python 抓 Zillow 数据,代理IP应该怎么接?
这类任务最容易踩的坑,不是代理地址填错,而是一上来就对着房源详情页写解析器。网页结构会调整,访问规则也可能变化,脚本今天能取到内容,过几天就可能只返回错误页面。
我的处理顺序一直是:先确认数据是否允许自动获取,再选择稳定的数据入口,最后才考虑要不要接代理IP。
如果目标是分析美国城市房价、租金和市场走势,可以优先使用 Zillow Research 公开的 CSV 数据。代理IP在这个流程里只负责管理网络出口,不能替代数据授权,也不能解决解析规则变化的问题。
先把数据入口选对
Zillow Research 提供了多类房地产市场数据,常见的有:
- ZHVI:观察不同区域典型房屋价值及其变化。
- ZORI:观察不同区域典型租金及其变化。
- 库存与成交指标:适合分析市场供需和成交节奏。
以都会区级 ZHVI 数据为例,公开 CSV 地址为:
https://files.zillowstatic.com/research/public_csvs/zhvi/Metro_zhvi_uc_sfrcondo_tier_0.33_0.67_sm_sa_month.csv
这种结构化文件比解析房源网页省心:字段明确,不需要维护 CSS 选择器,也不用处理页面里的动态组件。
不过,公开数据路径和字段都有可能调整。正式运行前,应核对 Zillow Research 数据页及其当前使用规则。请求返回 403、429 或人机验证内容时,脚本应立即停止,而不是继续提高频率。
Python环境准备
这次只用 requests 和 pandas:
pip install requests pandas
代理信息不要直接写进代码,建议通过环境变量传入:
export PROXY_URL="http://username:password@proxy-host:port"
如果代理不需要账号密码,也可以写成:
export PROXY_URL="http://proxy-host:port"
这样做有两个好处:代码可以安全地交给其他人使用,更换代理配置时也不用修改脚本。
通过代理下载公开CSV
完整下载代码如下:
import os
from pathlib import Path
import requests
DATA_URL = (
"https://files.zillowstatic.com/research/public_csvs/zhvi/"
"Metro_zhvi_uc_sfrcondo_tier_0.33_0.67_sm_sa_month.csv"
)
OUTPUT_FILE = Path("zillow_metro_zhvi.csv")
PROXY_URL = os.getenv("PROXY_URL")
proxies = None
if PROXY_URL:
proxies = {
"http": PROXY_URL,
"https": PROXY_URL,
}
headers = {
"User-Agent": "ResearchDataClient/1.0",
"Accept": "text/csv,*/*;q=0.8",
}
with requests.get(
DATA_URL,
headers=headers,
proxies=proxies,
timeout=(10, 60),
stream=True,
) as response:
if response.status_code in (403, 429):
raise RuntimeError(
f"服务端返回 {response.status_code},任务停止,请核对访问规则"
)
response.raise_for_status()
content_type = response.headers.get("Content-Type", "").lower()
print("Content-Type:", content_type)
with OUTPUT_FILE.open("wb") as file:
for chunk in response.iter_content(chunk_size=64 * 1024):
if chunk:
file.write(chunk)
print(f"下载完成:{OUTPUT_FILE.resolve()}")
这里没有加入高并发、地址轮换或无限重试。公开 CSV 一般下载一次就够了,频繁重复请求不会提高数据质量,反而会让任务状态更难判断。
别急着跑,先验证文件
有一次我写采集脚本,只判断了 HTTP 状态码。结果接口虽然返回 200,保存下来的却是一段 HTML 提示页,直到 pandas 报字段错误才发现。
更稳妥的做法是检查文件头:
from pathlib import Path
file_path = Path("zillow_metro_zhvi.csv")
with file_path.open("rb") as file:
first_bytes = file.read(200)
preview = first_bytes.decode("utf-8", errors="replace")
if "RegionID" not in preview or "RegionName" not in preview:
raise RuntimeError("文件内容不像目标CSV,请检查响应结果")
print("CSV基础校验通过")
这一步很简单,但很实用。网络请求成功,不等于数据获取成功,两者要分开判断。
宽表整理成长表
ZHVI 文件前几列是地区信息,后面每个月对应一列。做趋势分析前,可以把它转换成长表:
import pandas as pd
df = pd.read_csv("zillow_metro_zhvi.csv")
id_columns = [
"RegionID",
"SizeRank",
"RegionName",
"RegionType",
"StateName",
]
long_df = df.melt(
id_vars=id_columns,
var_name="date",
value_name="zhvi",
)
long_df["date"] = pd.to_datetime(long_df["date"], errors="coerce")
long_df["zhvi"] = pd.to_numeric(long_df["zhvi"], errors="coerce")
long_df = long_df.dropna(subset=["date", "zhvi"])
target = (
long_df[long_df["RegionName"] == "Seattle, WA"]
.sort_values("date")
.tail(24)
)
print(target[["date", "zhvi"]].to_string(index=False))
跑完以后,得到的是目标都会区最近24个月的房屋价值序列。后续计算同比、环比或移动平均,都可以在本地完成,不需要重复下载原文件。
代理IP到底解决什么
代理IP不是采集脚本的万能开关。我通常会同时记录下面三个指标:
| 指标 | 怎么看 | 能判断什么 |
|---|---|---|
| 连接耗时 | 从发起请求到建立连接 | 网络出口是否匹配 |
| 完整下载耗时 | 从请求开始到文件落盘 | 大文件传输是否稳定 |
| 状态码与内容类型 | 记录状态码和响应头 | 区分网络问题与数据入口问题 |
如果直连一次就能完整下载,额外增加代理链路未必有必要。如果接入代理后速度明显下降,应先检查协议、认证方式、出口地区和超时配置,不要只靠更换地址碰运气。
还要注意代理有效时间。假设代理只能保持几分钟,而文件下载和校验需要更长时间,中途连接变化就可能留下不完整文件。解决办法不是增加请求次数,而是估算单次任务时长,给下载、校验和落盘留足时间。
给脚本加一层日志
正式跑定时任务时,至少记录请求时间、代理状态、响应码、文件大小和耗时:
import time
started_at = time.time()
# 下载逻辑放在这里
elapsed = time.time() - started_at
file_size = OUTPUT_FILE.stat().st_size
print({
"status": "success",
"elapsed_seconds": round(elapsed, 2),
"file_size_bytes": file_size,
"proxy_enabled": bool(PROXY_URL),
})
数据会说话。连续跑几轮后,对比直连和代理的耗时、成功响应率及文件完整性,才能判断代理配置有没有实际价值。
常见报错怎么排
返回200,但文件无法解析
先检查 Content-Type 和文件前200个字符。拿到 HTML 提示内容时,停止任务并核对数据地址。
代理连接超时
分别测试直连和代理。直连正常而代理超时,通常是协议、认证信息或出口链路的问题。
CSV字段发生变化
不要按固定列号读取。使用 RegionName、StateName 等字段名定位,日期列通过日期转换动态识别。
读取文件时内存占用过高
可以分块读取:
import pandas as pd
for chunk in pd.read_csv(
"zillow_metro_zhvi.csv",
chunksize=100,
):
print(chunk.shape)
下载与分析也应拆成两个阶段。分析代码报错时,直接读取已经保存的文件,不要再次请求数据源。
到底怎么做?
抓取 Zillow 数据,第一步不是找代理IP,而是确认数据入口。
公开 CSV 能满足需求时,直接下载结构化文件,通常比维护网页解析器稳定。代理IP只在网络出口确实存在需求时接入,并通过环境变量管理,不要和业务代码绑死。
实操建议:先直连跑一轮,再使用代理跑一轮,分别记录连接耗时、完整下载耗时、文件大小和解析结果。哪种方式更适合当前网络环境,让真实任务的数据来判断。
FAQ
Q:可以直接用BeautifulSoup解析Zillow房源详情页吗?
从技术角度看,Python可以解析网页内容,但是否允许自动获取,应以平台当前规则和授权范围为准。没有明确依据时,优先处理公开 CSV 或经过许可的数据接口。
Q:为什么使用代理后速度反而更慢?
代理增加了一段网络链路,出口位置与目标数据源距离较远时,延迟可能上升。先对比直连与代理的连接耗时,再决定是否保留代理层。
Q:403和429出现后可以自动重试吗?
不建议直接循环重试。这两类状态通常需要先核对数据地址、访问频率和使用规则,确认请求方式没有问题后再恢复任务。
Q:定时采集应该每次都下载完整CSV吗?
月度数据没有必要高频重复下载。可以根据数据更新时间安排任务,并保存文件日期、大小和校验值,只有数据发生变化时再进入分析流程。
本文涉及的数据入口与访问说明以2026年8月公开信息为基础。数据路径、字段及使用规则可能调整,正式运行前请以Zillow最新公开页面和条款为准。