Zalando 是欧洲最大的时尚零售商之一,其公开商品页面包含驱动价格监控、商品跟踪和时尚趋势研究所需的结构化数据:商品名称、品牌、价格、可选尺码和颜色。问题在于,Zalando 使用 JavaScript 渲染页面,并对机器人实施严密防护,因此普通 HTTP 请求只会返回一个空壳或验证挑战页,而非您需要的商品目录。
本指南将向您展示如何以可靠的方式用 Python 构建 Zalando 爬虫。您通过 Crawling API 使用 JavaScript token 获取完整渲染后的商品页面,再用 BeautifulSoup 解析标记并提取所需字段。整个流程仅涉及公开商品数据,文末的合法性部分并非套话,请在大规模爬取前务必阅读。
您将构建的内容
一个 Python 脚本,接受公开的 Zalando 商品 URL,通过 Crawling API 获取渲染后的 HTML,并提取商品的结构化记录。我们将以单个商品页面为示例,提取以下字段:
- 商品名称:商品标题,例如"Leather Handbag"。
- 品牌:商品背后的品牌标签,例如"Zign"。
- 价格:当前售价,含货币符号。
- 可选尺码:页面显示为有库存的尺码。
- 颜色:所列变体的配色方案。
一旦单个页面运行正常,我们便可循环处理商品 URL 列表,并对请求进行限速,使真实任务保持稳定。时尚目录是经典的 电商网络爬取目标,这里的模式可迁移至大多数零售商。
为什么普通请求在 Zalando 上会失败
如果您使用普通 HTTP 客户端请求 Zalando 商品 URL,将得到两种无效响应之一:状态码 200 但正文中几乎没有商品数据,或者是机器人验证挑战。两个因素对您不利。首先,Zalando 在浏览器中通过 JavaScript 渲染商品内容,因此初始 HTML 只是一个空壳,只有在页面脚本运行后才会填充内容。其次,Zalando 能迅速识别自动流量:来自数据中心 IP 且不像真实浏览器的请求模式会在到达渲染内容之前就被挑战或屏蔽。
因此,一个可用的 Zalando 爬虫需要在单次请求中实现两件事:真正渲染页面的浏览器,以及平台视为真实访客的 IP。您可以自己组合无头浏览器和 轮换住宅代理池,但将它们组合并保持运行正常才是最大的工作量。Crawling API 将两者整合进一次调用:您发送带有 JavaScript token 的 URL,它在可信 IP 后渲染页面,并为您返回可解析的完整 HTML。如需了解客户端渲染如何破坏简单爬虫的背景知识,请参阅 如何爬取 JavaScript 网站。
Crawlbase 提供两种 token 类型。普通 token 获取静态 HTML;JavaScript(JS)token 则先在真实浏览器中渲染页面。Zalando 是客户端渲染的,因此您需要在此使用 JS token。使用普通 token 会返回与普通请求相同的空壳,其中没有可解析的有用内容。
前提条件
在编写代码之前,您需要准备几样东西,都不会花太长时间。
基础 Python 知识。您应当能够编写和运行 Python 脚本,并使用 pip 安装包。如果您不熟悉 BeautifulSoup,我们的 BeautifulSoup in Python 指南涵盖了本教程所需的解析基础知识。
Python 3.8 或更高版本。使用 python --version 确认您的版本。如果尚未安装,请从 python.org 或通过 Anaconda 等发行版安装。
Crawlbase 账户和 JS token。注册后,打开您的控制台,从账户文档页面复制 JavaScript(JS)token。请像对待密码一样保管 token:它用于验证您的请求,因此请勿将其纳入版本控制。
搭建项目
创建虚拟环境以隔离项目依赖,然后安装爬虫所需的两个库。
python --version python -m venv zalando_env source zalando_env/bin/activate pip install crawlbase beautifulsoup4
在 Windows 上,请使用 zalando_env\Scripts\activate 代替 source 命令来激活环境。两个依赖项各司其职:crawlbase 是 Crawling API 的官方客户端,beautifulsoup4 解析返回的 HTML,让您可以通过 CSS 选择器提取各个字段。
步骤一:获取渲染后的商品页面
首先获取完整页面。导入 CrawlingAPI 类,用您的 JS token 初始化,并请求商品 URL。在解析之前检查状态码,可以让失败信息清晰呈现而非被忽略。
from crawlbase import CrawlingAPI api = CrawlingAPI({"token": "YOUR_CRAWLBASE_JS_TOKEN"}) def crawl(page_url): options = {"ajax_wait": "true", "page_wait": 5000} response = api.get(page_url, options) if response["status_code"] == 200: return response["body"].decode("utf-8") print(f"Request failed: {response['status_code']}") return None if __name__ == "__main__": page_url = "https://en.zalando.de/zign-handbag-black-zi151h08a-q11.html" html = crawl(page_url) print(html[:500] if html else "No HTML returned")
两个等待选项对于这类客户端渲染目标至关重要。ajax_wait 告知 API 等待异步内容加载完成,page_wait 则在加载后额外等待固定毫秒数,以便延迟渲染的元素在页面被捕获前出现。五秒是合理的起点;如果商品字段返回为空,可适当延长。运行 python scraper.py,您应该能看到真实的商品标记,而非普通请求返回的空壳。这表示渲染在您编写任何选择器之前就已正常工作。
Zalando 需要在可信 IP 后获取渲染页面,通过一次调用完成。Crawling API 接受 JS token,在真实浏览器中运行页面,在服务器端轮换住宅 IP,并为您返回完整 HTML,让您无需自行运行无头浏览器集群和代理池。先在免费套餐上指向公开商品页面进行测试。
步骤二:使用 BeautifulSoup 解析商品字段
拿到渲染后的 HTML 后,将其加载到 BeautifulSoup 中,并通过选择器提取各字段。Zalando 商品页面以相当规律的结构排列核心信息,因此您可以将名称、品牌、价格、尺码和颜色映射到各自的选择器。将提取逻辑封装为辅助函数,这样单个字段缺失也不会导致程序崩溃。
from bs4 import BeautifulSoup def text_of(soup, selector): el = soup.select_one(selector) return el.get_text(strip=True) if el else None def all_text(soup, selector): return [el.get_text(strip=True) for el in soup.select(selector)] def scrape_product(html): soup = BeautifulSoup(html, "html.parser") sizes = all_text(soup, "[data-testid='pdp-size-picker'] [role='option']") return { "name": text_of(soup, "span.EKabf7.R_QwOV"), "brand": text_of(soup, "span.OBkCPz.Z82GLX"), "price": text_of(soup, "span.voFjEy.Km7l2y"), "color": text_of(soup, "[data-testid='color-name']"), "sizes": [s for s in sizes if s], }
text_of 辅助函数同时完成两件事:查询单个元素,并在元素缺失时返回 None,而非对空值调用 .get_text() 时抛出异常。all_text 辅助函数则收集所有匹配的元素,适用于重复出现的字段(如尺码选项)。这使得提取逻辑在某个字段在特定页面上缺失时仍能正常运行,这种情况很常见,因为并非每件商品都列出了所有信息。
Zalando 的类名(如 EKabf7 和 voFjEy 这样的哈希 token)是自动生成的,会在不通知的情况下更改。请将上述选择器视为起始模板,而非固定合约。当某个字段返回 None 或空列表时,请在浏览器开发者工具中重新检查实时页面并更新选择器。稳定的 data-testid 属性通常比哈希类名存活更久,因此建议优先使用它们。定期维护选择器是任何生产爬虫的正常工作,并不意味着出了什么问题。
步骤三:整合代码
现在将获取和解析整合到一个可运行的脚本中。获取渲染后的 HTML,传入解析器,并打印结构化记录。
import json from crawlbase import CrawlingAPI from bs4 import BeautifulSoup api = CrawlingAPI({"token": "YOUR_CRAWLBASE_JS_TOKEN"}) def crawl(page_url): options = {"ajax_wait": "true", "page_wait": 5000} response = api.get(page_url, options) if response["status_code"] == 200: return response["body"].decode("utf-8") print(f"Request failed: {response['status_code']}") return None def text_of(soup, selector): el = soup.select_one(selector) return el.get_text(strip=True) if el else None def all_text(soup, selector): return [el.get_text(strip=True) for el in soup.select(selector)] def scrape_product(html): soup = BeautifulSoup(html, "html.parser") sizes = all_text(soup, "[data-testid='pdp-size-picker'] [role='option']") return { "name": text_of(soup, "span.EKabf7.R_QwOV"), "brand": text_of(soup, "span.OBkCPz.Z82GLX"), "price": text_of(soup, "span.voFjEy.Km7l2y"), "color": text_of(soup, "[data-testid='color-name']"), "sizes": [s for s in sizes if s], } def main(): page_url = "https://en.zalando.de/zign-handbag-black-zi151h08a-q11.html" html = crawl(page_url) if not html: return data = scrape_product(html) print(json.dumps(data, indent=2, ensure_ascii=False)) if __name__ == "__main__": main()
在 JSON 转储时设置 ensure_ascii=False,可以保持欧元符号和重音字符的可读性,而不会将其转义。运行 python scraper.py,即可得到该商品的整洁结构化记录。
输出示例
脚本打印出一条记录,可直接写入 JSON、CSV 或数据库。
{ "name": "LEATHER - Handbag", "brand": "Zign", "price": "49,99 €", "color": "black", "sizes": ["One Size"] }
对于服装商品,sizes 列表将包含真实的尺码,例如 ["XS", "S", "M", "L"],如果您在尺码选择器的可用状态上进行过滤,售罄的尺码会被排除。
扩展至批量商品
单页是演示;真实任务需要处理商品列表。结构保持不变:维护一个商品 URL 列表,通过 Crawling API 逐一获取,使用相同的函数解析,并收集数据行。由于每个商品页面共享相同的结构,您已编写的解析器无需修改即可在所有商品上使用。关键的新增点是限速:请求之间的短暂停顿可以避免爆发式机器人流量。
import time products = [ "https://en.zalando.de/zign-handbag-black-zi151h08a-q11.html", "https://en.zalando.de/anna-field-handbag-black-an651h0x2-q11.html", ] results = [] for url in products: html = crawl(url) if html: results.append({"url": url, **scrape_product(html)}) time.sleep(2) with open("zalando_products.json", "w", encoding="utf-8") as f: json.dump(results, f, indent=2, ensure_ascii=False)
若要批量获取商品 URL,可使用相同的获取解析模式爬取 Zalando 的公开目录页面(例如 https://en.zalando.de/catalogue/?q=handbags),收集商品链接,再逐一访问。请将请求量控制在合理范围内,并遵守下文提到的速率限制。如果价格是您的最终目标,收集的记录可直接输入 价格情报流水线。
保持不被屏蔽
即使渲染问题已解决,Zalando 仍会监测爬虫特征的流量。以下几个习惯可以保持任务健康运行,适用于任何防护严密的商业目标。
-
限制请求速率。在紧密循环中猛烈请求页面是最快被限速的方式。上面的
time.sleep可以分散请求;不要以全速爬取一条路径,而应变换目标。 - 依赖 IP 轮换。住宅 IP 池将请求分散到众多真实用户地址,使任何单个地址都不会触发速率限制。Crawling API 为您处理这些;如果您自己搭建技术栈,这是最关键的部分。
- 读取状态码。当运行开始返回挑战或错误时,说明当前速率或 IP 等级已不够用。将其视为退让的信号,而非可以忽略的噪声。
更广泛的防屏蔽策略,请参阅 如何在不被屏蔽的情况下爬取网站,以及关于 网络爬取中如何绕过 CAPTCHA 的深度解析。如果您更希望通过轮换池路由自己的流量而非使用托管 API,Smart AI Proxy(也称 AI Proxy)可为您提供与下拉式代理端点相同的住宅 IP 轮换。同样的方法也适用于 AliExpress 和 Walmart 等相邻目录。
爬取 Zalando 是否合法?
爬取 Zalando 是否被允许,取决于 Zalando 的服务条款、您所在的司法管辖区以及您对数据的用途。Zalando 的条款限制自动访问,因此无论您的技术手段多么谨慎,爬取都可能违反这些条款。这里的代码无法改变这一点,它只是让技术部分得以实现。请阅读 Zalando 的服务条款及其 robots.txt,并将两者视为您采集内容的边界。
以下几条值得遵守。仅采集公开商品数据:任何人无需账号即可看到的商品名称、品牌、价格、可选尺码和颜色。遵守 Zalando 的速率预期,将请求量控制在不给其服务器造成负担的水平。避免个人数据,包括任何与可识别个人相关的信息,例如评论者资料或账户信息。如果您计划将数据用于商业目的,请获得许可或正式协议,而非默认沉默即为同意。
本指南刻意将范围限定在公开商品页面,因为这是使工作具有可辩护性的边界。它不涵盖任何登录后的内容、账户或订单数据、个人数据、需要登录的页面,以及任何绕过身份验证的尝试。对于大规模或商业用途,请优先选择官方 API 或与 Zalando 签订数据协议,而非更复杂的爬虫。仅采集公开商品数据是使您在条款和法律两方面都处于正确立场的规则。
核心要点
- Zalando 是客户端渲染的。普通请求会返回空壳或挑战,因此您必须在解析之前先渲染页面。
-
您需要渲染和可信 IP 同时具备。带 JS token 的 Crawling API 在一次调用中同时实现两者;
ajax_wait和page_wait控制等待内容的时长。 -
BeautifulSoup 负责提取。将商品名称、品牌、价格、尺码和颜色映射到当前选择器,优先使用稳定的
data-testid属性,并预期哈希类名会发生漂移。 - 通过带限速的 URL 循环进行扩展。相同的解析器适用于每件商品,因此真实任务只是一个链接列表加上请求之间的短暂停顿。
- 坚守公开数据。遵守 Zalando 的服务条款和 robots.txt,对于批量或商业用途优先选择官方 API,绝不触碰账户、需要登录的页面或个人信息。
常见问题
为什么普通请求无法从 Zalando 获取数据?
因为 Zalando 使用 JavaScript 在客户端渲染商品内容。初始 HTML 只是一个空壳,只有在浏览器中运行页面脚本后才会填充,因此原始 HTTP 请求返回状态码 200 但商品字段为空,或者返回机器人挑战而非页面。要获取真实数据,您必须先渲染页面,这正是 Crawling API 的 JS token 为您处理的事情。
Zalando 需要普通 token 还是 JS token?
JS token。普通 token 获取静态 HTML,在 Zalando 上这与普通请求返回的空壳相同。JS token 在返回 HTML 之前先在真实浏览器中渲染页面,因此当 BeautifulSoup 解析时,商品名称、品牌、价格、尺码和颜色都已存在。
我的选择器返回 None 或空列表。是什么发生了变化?
几乎可以肯定是 Zalando 的标记发生了变化。其哈希类名(如 EKabf7 和 voFjEy)是自动生成的,会在不通知的情况下更改,因此上个月有效的选择器现在可能已失效。请在浏览器开发者工具中重新检查实时商品页面并更新选择器。优先使用稳定的 data-testid 属性,它们在重新设计后比哈希类名存活更久。
我可以用 Python 代替 Puppeteer 或 Node.js 来爬取 Zalando 吗?
可以。由于 Crawling API 在服务器端渲染页面并返回完整 HTML,您根本不需要在本地运行无头浏览器。一个使用 crawlbase 客户端和 BeautifulSoup 的小 Python 脚本就足够了,这正是本指南的全部方法。这使爬虫轻量且易于调度。
如何在不被屏蔽的情况下爬取大量 Zalando 商品?
保持较低的单 IP 请求速率,在请求之间添加短暂停顿,变换目标而非循环爬取同一路径。通过轮换住宅 IP 路由流量,这样没有单个地址会触发速率限制;Crawling API 为您管理轮换和可信 IP 池。监控状态码,当您开始看到挑战时及时退让。
爬取 Zalando 商品数据是否合法?
这取决于 Zalando 的服务条款、您所在的司法管辖区以及您对数据的用途。本指南仅涉及公开商品数据(名称、品牌、价格、尺码、颜色),并要求您遵守 robots.txt 和服务条款。它不涵盖账户数据、个人数据、需要登录的页面或绕过身份验证。对于批量或商业用途,官方 API 或数据协议才是正确路径,而非爬虫。
大规模爬取任何站点,无需与基础设施对抗。
Crawlbase 负责处理代理、指纹和 CAPTCHA,让你的团队专注于交付数据流水线,而非维护爬取管道。1,000 次请求免费,无需信用卡。
