抓取汽车列表:Cars.com、Autotrader 和 CarGurus 的价格情报

经销商的价格情报分布在 Cars.com、Autotrader 和 CarGurus 上——相同的汽车,根据邮政编码定价不同,并在各处交叉发布。以下是如何抓取它们,通过 VIN 去重,并突破反爬墙。

经销商的价格情报不集中在一个地方。相同的二手车同时在 Cars.com、Autotrader 和 CarGurus 上列出,根据买家的邮政编码定价不同,每个网站都用反爬保护来保护其页面。成功抓取不仅仅是解析页面,更在于三件事:过滤搜索以实际访问每个列表,通过 VIN 在来源间去重相同车辆,以及在不烧毁大量 IP 的情况下突破墙。这份指南涵盖了所有三点,并提供可适应任何大型列表网站的代码。

汽车列表能给你什么

每个车辆列表都是一个密集的记录,一旦你解析它:年份、品牌、型号和配置;价格和里程;VIN;车身类型、驱动系统、燃料、变速器、气缸和车门数;内外颜色;库存编号;功能列表;图片;以及经销商详情加上某些网站计算的交易评级。这是每行的完整估值数据集。你构建管道的核心字段是价格、里程、VIN 和经销商——其他都是丰富信息。

先过滤:访问每个列表

列表网站以固定页面大小分页(通常每页 20 个),并限制单次搜索的深度——通常总共约 1,000 个结果。如果搜索匹配的汽车超过这个数量,额外的部分通过分页无法访问。解决方法是分段:将广泛的搜索按品牌、型号、年份范围、价格区间或邮政编码分成更窄的搜索,以便每个搜索都在限制内,然后合并结果。Cars.com 有用地在 URL 中编码了所有这些,因此你可以以编程方式构建搜索。

from urllib.parse import urlencode

def search_url(zip_code, make="", model="", max_price="", year_min=""):
    params = {
        "stock_type": "used",
        "makes[]": make,
        "models[]": model,
        "list_price_max": max_price,
        "year_min": year_min,
        "maximum_distance": "all",
        "zip": zip_code,
        "page_size": 20,
        "sort": "listed_at_desc",
    }
    return "https://www.cars.com/shopping/results/?" + urlencode(params)

print(search_url("10001", make="toyota", model="camry", year_min=2020))
汽车列表抓取的统计图:每页 20 个列表,每次搜索可达 1000 个,2-5 秒延迟,VIN 作为跨站去重键
单次搜索接近 1,000 个结果的上限——按品牌、年份或邮政编码分段以访问其余部分,并调整请求速度以避免检测。

突破墙:住宅代理

Cars.com 位于 Cloudflare 之后;其他汽车网站使用 Imperva,伴随 hCaptcha 或 reCAPTCHA,在负载下触发。数据中心 IP 快速访问列表页面会很快受到挑战。来自真实 ISP 的住宅代理看起来像普通购物者,轮换它们分散请求,以免单个地址触发速率限制。保持请求之间 2-5 秒的延迟——节奏与 IP 一样重要。对于小规模、偶尔的抓取,数据中心池就足够;对于大规模的持续监控,住宅代理是完成运行与卡在 CAPTCHA 之间的区别。

import requests, time, random

PROXY = "http://USER:PASS@gate.quantumproxies.io:8000"
proxies = {"http": PROXY, "https": PROXY}
HEADERS = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"}

def fetch(url):
    r = requests.get(url, proxies=proxies, headers=HEADERS, timeout=20)
    r.raise_for_status()
    time.sleep(random.uniform(2, 5))   # polite, and harder to fingerprint
    return r.text

如果目标使用 JavaScript 渲染列表或抛出持续的 CAPTCHA,携带真实浏览器指纹并为你解决反爬层的 Scraper API 比维护自己的浏览器农场更稳定。我们的 2026 年突破 Cloudflare 的指南 涵盖了这一界限。

获取汽车列表网站的住宅代理

通过 VIN 在来源间去重

汽车数据中最有用的列是 VIN。因为经销商将同一辆车交叉发布到每个市场,你的原始抓取充满了看似不同列表的重复项。VIN 是物理车辆的全球唯一标识符,因此以它为键可以将这些重复项合并为一个记录——并让你比较同一辆车在 Cars.com、Autotrader 和 CarGurus 上的定价,或由哪个经销商定价。根据你测量的内容,保留每个 VIN 的最低价格,或保留所有标记来源的价格。

def dedupe_by_vin(rows):
    best = {}
    for r in rows:
        vin = r.get("vin")
        if not vin:
            continue
        price = int(r["price"])
        if vin not in best or price < int(best[vin]["price"]):
            best[vin] = r          # keep the cheapest listing per car
    return list(best.values())
汽车列表管道流程图:构建过滤搜索 URL,通过住宅代理突破 Cloudflare,解析列表字段,通过 VIN 去重
过滤,通过住宅出口获取,解析,然后通过 VIN 合并重复项,以便你比较汽车而不是重复计算列表。

地理定价:同一辆车,不同邮政编码

汽车价格是本地化的。根据你搜索的邮政编码,相同的车型显示不同的价格和库存,因为经销商和需求因地区而异。为了捕捉这种差异,扫描一组邮政编码,并在网站根据访问者的位置个性化时,通过匹配地区的出口路由每个请求。具有 国家和城市定位 的住宅池让你看到当地买家看到的价格——这对于套利、经销商基准测试或构建不偏向某个市场的估值模型至关重要。

zips = ["10001", "90001", "60601", "77001"]  # NY, LA, Chicago, Houston
spread = {}
for z in zips:
    url = search_url(z, make="toyota", model="camry", year_min=2021)
    rows = parse_listings(fetch(url))          # exit geo-matched to the ZIP
    spread[z] = [int(r["price"]) for r in rows]

# now compare median price by market
for z, prices in spread.items():
    prices.sort()
    print(z, "median", prices[len(prices)//2])

这与 竞争对手价格监控房地产数据收集 背后的相同位置优先模式——无论价格取决于买家的位置,地理定位出口都是不可协商的。

拍卖和批发来源

零售列表网站告诉你经销商的要价;像 Copart 这样的拍卖平台告诉你汽车在批发层面实际成交的价格——定价模型的另一半。这些网站的防护更严:例如,Copart 运行 Imperva 网络保护,带有行为指纹识别,并在较高请求量下出现 hCaptcha 或 reCAPTCHA 挑战。分页也更严格——每页 20 辆车,硬性限制约 50 页,因此单次搜索最多约 1,000 个批次。要达到完整库存,需要按品牌、型号、年份范围、拍卖场或条件分段查询,正如在零售网站上一样,并为每个分段单独运行。

因为这些平台使用 JavaScript 加载结果和分页,并挑战可疑流量,它们需要住宅 IP 和请求之间至少 2-5 秒的间隔。数据中心代理处理小规模、偶尔的抓取;任何持续的操作都应使用住宅出口。回报是真实信号:投标历史、销售状态和批次条件提供的需求预测和进出口分析是零售要价无法单独提供的。

监控,而不仅仅是一次性抓取

在列表每日更新的市场中,一次性数据转储会立即过时。持久的模式是计划抓取,快照目标搜索并比较连续运行的差异——新列表、价格下降和已售出的汽车。以 VIN 为每行的键,以便同一车辆的价格变化明确无误,给每个快照加时间戳,你就拥有了可趋势的时间序列:特定车型贬值的速度、哪些经销商降价、库存在哪里积压。通过轮换住宅 IP 路由这些计划的运行,以免同一地址的每日任务慢慢被封锁。

常见问题解答

你能抓取 Cars.com 和 Autotrader 吗?

可以——列表页面显示的是公开可用的车辆数据。实际的挑战是反爬保护:Cars.com 使用 Cloudflare,其他使用 Imperva 和 CAPTCHA。住宅代理、真实的请求头和请求之间 2-5 秒的延迟保持抓取运行。尊重每个网站的服务条款,避免收集个人数据。

如何避免在抓取汽车列表时被封锁?

轮换住宅 IP,以免单个地址发出过多请求,随机化请求之间的 2-5 秒延迟,发送真实的浏览器 User-Agent,并将大型搜索分段为较小的搜索,而不是分页数千深。如果 CAPTCHA 持续出现,切换到处理反爬层和 JavaScript 渲染的 Scraper API。

为什么抓取时会得到重复的汽车?

经销商将同一辆车交叉发布到多个市场,因此一辆实体车会显示为多个列表。通过 VIN 去重,VIN 无论在哪个网站上都能唯一标识车辆。以 VIN 为键将重复项转化为同一辆车在不同来源的价格比较,而不是夸大计数。

汽车价格真的会因地区而变化吗?

是的。库存和定价因地区而异,许多网站根据搜索者的邮政编码个性化结果。为了捕捉真实的差异,搜索多个邮政编码,并通过匹配地区的出口路由每个请求,使用地理定位的住宅代理,以便看到当地价格,而不是一个偏向全国的视图。

抓取汽车列表归结为访问每辆车(分段超过约 1,000 个结果的上限),突破反爬墙(轮换住宅 IP,礼貌的节奏),通过 VIN 合并重复项,并通过位置定位的出口捕捉地理差异。围绕价格、里程、VIN 和经销商构建管道,你就拥有了所有主要市场的经销商价格情报。

使用 QuantumProxies 开始抓取汽车列表