AliExpress 是网络上最大的消费者市场之一,每个商品页面都承载着那种驱动价格追踪、市场研究和竞品分析的结构化数据:一个标题、一个当前价格、一个评分、卖出了多少件、列表背后的店铺,以及配送条款。问题在于 AliExpress 在浏览器中渲染那些页面,并对自动化流量强力回击,所以一个普通的 HTTP 请求交给你的是一个近乎空白的外壳,而不是你想要的那些字段。
本指南将向你展示如何用可靠的方式用 Python 爬取 AliExpress。你会构建一个小巧、可运行的爬虫,它通过 Crawling API 抓取一个完全渲染好的商品页面,用 BeautifulSoup 解析你想要的字段,并打印一条干净的结构化记录。整个演练都限定在公开的商品数据上,而结尾附近的合法性部分并非套话,所以在你把它对准任何真实流量之前请先读一读。
你将构建什么
一个 Python 脚本,它接收一个公开的 AliExpress 商品 URL,通过 Crawling API 取回渲染好的 HTML,并提取该列表的一条结构化记录。我们以单个商品页面作为贯穿全文的示例,并抓取这些字段:
- 标题 列表上显示的完整商品名称。
- 价格 当前价格,例如 "US $3.45"。
- 评分 平均客户评分,比如 "4.8"。
- 已售订单 列表所报告的售出件数。
- 店铺名称 商品背后的卖家店铺。
- 配送 页面上显示的配送费用或条款。
为什么对 AliExpress 发起普通抓取会失败
如果你用一个裸的 HTTP 客户端去请求一个 AliExpress 商品 URL,你通常得到的是一个状态为 200、正文里几乎没有商品详情的响应。有两种力量在跟你作对。第一,AliExpress 用 JavaScript 在浏览器中构建它的商品内容,所以初始的 HTML 是一个骨架,只有在页面的脚本运行之后才会填上。第二,AliExpress 很快就会标记自动化流量:数据中心 IP 和看起来不像真实浏览器的请求模式,在它们还没触及渲染好的内容之前就会被挑战、被地理重定向,或者被封禁。
所以一个能用的 AliExpress 爬虫在一次请求中需要两样东西:一个真正渲染页面的浏览器,以及一个被平台读作真正购物者的 IP。你可以自己用一个无头浏览器加一池轮换的住宅代理来拼凑出那套方案,但把它们拼到一起并保持其健康才是工作的大头。Crawling API 把这两者折叠进了一次调用:你把带一个 JavaScript 令牌的 URL 发给它,它在一个受信任的 IP 背后渲染页面,并返回完成的 HTML 供你解析。如果你想先了解更宽泛的电商背景,请看我们对电商网络爬取的概览。
Crawlbase 提供两种令牌类型。普通令牌抓取静态 HTML;JavaScript (JS) 令牌先在一个真实浏览器中渲染页面。AliExpress 是客户端渲染的,所以这里你需要 JS 令牌。使用普通令牌返回的和一个普通抓取得到的大体是同一个骨架,里面几乎没有什么可解析的。
前置条件
在写任何代码之前,你需要准备好几样东西。它们都不会花很久。
基础的 Python。你应当能够熟练地编写并运行一个脚本,以及用 pip 安装包。如果你是解析 HTML 的新手,我们关于如何在 Python 中使用 BeautifulSoup 的入门讲解涵盖了本教程所倚靠的选择器基础。
Python 3.8 或更高版本。用 python --version 确认你的版本。如果你还没有,请从 python.org 或通过像 Anaconda 这样的发行版安装它。
一个 Crawlbase 账户和 JS 令牌。注册,打开你的仪表盘,并从账户文档页复制你的 JavaScript (JS) 令牌。请把令牌当作密码对待:它会对你的请求进行身份认证,所以别把它放进版本控制。
搭建项目
创建一个虚拟环境,让项目依赖保持隔离,然后安装这个爬虫需要的两个库。
python --version python -m venv aliexpress_env source aliexpress_env/bin/activate pip install crawlbase beautifulsoup4
在 Windows 上,用 aliexpress_env\Scripts\activate 来激活环境,而不是那行 source。两个依赖项承担了工作:crawlbase 是用于 Crawling API 的官方客户端,而 beautifulsoup4 解析返回的 HTML,让你能按 CSS 选择器抽出各个字段。
第 1 步:抓取渲染好的商品页面
先从拿到完成的页面开始。导入 CrawlingAPI 类,用你的 JS 令牌初始化它,并请求商品 URL。在解析之前检查状态码,能让失败保持响亮而不是悄无声息。
from crawlbase import CrawlingAPI api = CrawlingAPI({"token": "YOUR_CRAWLBASE_JS_TOKEN"}) def crawl(page_url): options = {"ajax_wait": "true", "page_wait": 8000, "country": "US"} 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://www.aliexpress.com/item/1005006597796136.html" html = crawl(page_url) print(html[:500] if html else "No HTML returned")
这些选项对于像这样一个客户端渲染的目标很重要。ajax_wait 告诉 API 等待异步内容完成加载,而 page_wait 在加载之后再保持固定的毫秒数,这样迟渲染的价格和配送块会在页面被捕获之前出现。对 AliExpress 来说八秒是一个合理的起点;如果字段返回为空就把它调高。country 选项把请求钉在一个地区上,这样价格和配送在一个稳定的区域设置里渲染,而不是随 IP 而变。用 python scraper.py 运行脚本,你应该会看到真实的商品标记,而不是一个普通抓取返回的骨架。这在你写下一个选择器之前就确认了渲染能工作。
AliExpress 在一次调用里需要一个在受信任的、钉在某地区的 IP 背后渲染好的页面。Crawling API 接收一个 JS 令牌,在一个真实浏览器里运行页面,在服务器端轮换住宅 IP,并把完成的 HTML 交给你,这样你就省去了自己运行一支无头浏览器队伍和一池代理。先在免费套餐上把它对准一个公开的商品页面。
第 2 步:用 BeautifulSoup 解析商品字段
手里有了渲染好的 HTML,就把它加载进 BeautifulSoup,并按各自的选择器抽出每个字段。AliExpress 把核心的商品详情铺在一个可预测的结构里,所以你能把标题、价格、评分、已售订单、店铺名称和配送映射到各个选择器上。把提取包进一个辅助函数里,这样一个缺失的字段不会让本次运行崩溃。
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 scrape_product(html): soup = BeautifulSoup(html, "html.parser") return { "title": text_of(soup, "h1[data-pl='product-title']"), "price": text_of(soup, ".product-price-current"), "rating": text_of(soup, "[data-pl='product-reviewer'] strong"), "orders_sold": text_of(soup, "[data-pl='product-reviewer'] span"), "store_name": text_of(soup, "a[data-pl='store-name']"), "shipping": text_of(soup, ".dynamic-shipping-line strong"), }
text_of 辅助函数一次做两件有用的事:它查询单个元素,并在元素缺失时返回 None,而不是对一个不存在的东西调用 .get_text() 时抛出异常。这让提取在一个字段在某个列表上缺席时保持稳健,而这很常见,因为不是每个商品都报告一个订单数或一行配送。已售订单和评分常常共用同一个评论者块,所以它们是从它内部的同级元素里读取的。
AliExpress 的类名和 data-pl 标记会毫无预告地更改,而且它们在不同的商品模板和区域设置之间也各不相同。把上面那些选择器当作一个起始模板,而不是一份契约。当一个字段返回为 None 时,在你浏览器的开发者工具里重新检查实时页面并更新选择器。定期的选择器维护对任何生产爬虫来说都是正常的,而不是有什么坏掉了的信号。
第 3 步:把它拼起来
现在把抓取和解析连进一个可运行的脚本。抓取渲染好的 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": 8000, "country": "US"} 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 scrape_product(html): soup = BeautifulSoup(html, "html.parser") return { "title": text_of(soup, "h1[data-pl='product-title']"), "price": text_of(soup, ".product-price-current"), "rating": text_of(soup, "[data-pl='product-reviewer'] strong"), "orders_sold": text_of(soup, "[data-pl='product-reviewer'] span"), "store_name": text_of(soup, "a[data-pl='store-name']"), "shipping": text_of(soup, ".dynamic-shipping-line strong"), } def main(): page_url = "https://www.aliexpress.com/item/1005006597796136.html" html = crawl(page_url) if not html: return data = scrape_product(html) print(json.dumps(data, indent=2)) if __name__ == "__main__": main()
输出长什么样
用 python scraper.py 运行完整的脚本,你会得到该商品的一条干净的结构化记录,准备好写入 JSON、CSV 或一个数据库。
{ "title": "Wireless Bluetooth Earbuds Noise Cancelling Touch Control", "price": "US $12.74", "rating": "4.7", "orders_sold": "3,210 sold", "store_name": "TechGear Official Store", "shipping": "Free shipping" }
扩展到许多商品
一个商品是一个演示;一个真实的任务会跑遍一份商品列表。形态保持一致:保留一份商品 URL 列表,通过 Crawling API 抓取每一个,用同一个函数解析它,并收集这些行。因为每个商品页面都共享同样的结构,你已经写好的解析器无需改动就能跨它们全部工作。要加上的那一个习惯是节奏控制,这样你就不会在一个紧密循环里把列表走完。
import time import random products = [ "https://www.aliexpress.com/item/1005006597796136.html", "https://www.aliexpress.com/item/1005005899876543.html", ] results = [] for url in products: html = crawl(url) if html: results.append(scrape_product(html)) time.sleep(random.uniform(2, 5)) with open("products.json", "w") as f: json.dump(results, f, indent=2)
请求之间那个随机化的 sleep 把你的流量摊开,而不是以一个可预测的节律发射。要在规模上收集商品 URL,就用同样的先抓取后解析的模式去爬取 AliExpress 的搜索和分类页面,收集商品链接,然后访问每一个。把量保持合理,并尊重下面讲到的速率限制。
保持不被封禁
即便渲染被处理好了,AliExpress 仍盯着形状像爬虫的流量。几个习惯能让一次运行保持健康,它们适用于任何强硬的商业目标。
- 给你的请求安排节奏。在一个紧密循环里猛敲商品页面是被限流最快的方式。把请求摊开,加入抖动,并让你的目标多样化,而不是全速爬取一条路径。
- 依靠轮换。一池住宅 IP 把请求分散到许多真实用户的地址上,这样没有任何单个 IP 会触发速率限制。Crawling API 替你处理这件事;如果你自建一套栈,这就是要做对的部分。
-
钉住地区。AliExpress 按位置更改价格、货币和配送。设定一个一致的
country让你的记录保持可比,并避开那些击中不匹配 IP 的重定向循环。 - 读状态码。一次开始返回挑战或错误的运行是在告诉你,当前的速率或 IP 层级已经不够了。把那当作退一步的信号,而不是可以忽略的噪音。
要了解更宽泛的攻略,请看如何爬取网站而不被封禁,以及关于在网络爬取时如何绕过验证码的更深入探讨。如果你想了解更多关于代理那一侧的内容,还有一篇关于使用 AliExpress 代理爬取的聚焦演练。如果你宁愿把自己的流量通过一个轮换池来路由,而不是使用这个托管 API,Smart AI Proxy(也叫 AI Proxy)会以一个即插即用的代理端点给你同样的住宅 IP 轮换。
爬取 AliExpress 合法吗?
爬取 AliExpress 是否被允许,取决于 AliExpress 的服务条款、你所在的司法管辖区,以及你用这些数据做什么。AliExpress 的条款限制自动化访问,所以无论你的工具多么谨慎,爬取都可能与那些条款相抵触。这里的任何代码都改变不了这一点;它只是让技术部分能跑起来。请阅读 AliExpress 的服务条款及其 robots.txt,并把两者都当作你采集内容的边界。
有几条值得坚守的底线。只采集公开的商品数据:标题、当前价格、评分、已售订单、店铺名称,以及任何人无需账户就能看到的配送条款。尊重 AliExpress 所声明的速率预期,并把你的请求量保持得足够低,使你不会给它的服务器造成压力。避免任何与可识别个人相关联的内容,包括除列表上公开店铺名称之外的买家或卖家个人数据。如果你打算把数据用于商业用途,就去取得许可或一份官方协议,而不是假定沉默即同意。
本指南有意把范围限定在公开的商品页面上,因为那正是让这项工作站得住脚的那条线。它不涉及任何登录之后的内容,买家或卖家个人数据,私密的订单或账户数据,或任何绕过身份认证的尝试。对于获得许可的或批量的访问,AliExpress 和更广的阿里巴巴平台提供了官方 API 和数据协议,当你需要大批量、有保证的结构或商业权利时,那才是正确的工具。如果你的项目需要的不止公开商品数据,那么一个官方 API 或一份数据协议才是正确的路径,而不是一个更聪明的爬虫。
核心要点
- AliExpress 是客户端渲染的。一个普通抓取返回一个近乎空白的骨架,所以你必须在解析之前渲染页面。
-
你需要渲染和一个受信任的 IP 一起。带一个 JS 令牌的 Crawling API 在一次调用里两件都做;
ajax_wait、page_wait和country控制它如何等待以及在哪里渲染。 - BeautifulSoup 负责提取。把标题、价格、评分、已售订单、店铺名称和配送映射到当前的选择器上,并预期那些选择器会漂移。
- 通过带节奏地循环 URL 来扩展。同一个解析器跨每个商品都能工作,所以一个真实的任务只是一份商品链接列表加上带抖动的延迟和轮换。
- 停留在公开数据上。尊重 AliExpress 的服务条款和 robots.txt,对于获得许可的或批量的数据优先用一个官方 API,绝不碰登录、订单数据或个人信息。
常见问题
为什么一个普通抓取从 AliExpress 返回不到商品数据?
因为 AliExpress 用 JavaScript 在浏览器中构建它的商品内容。初始的 HTML 是一个骨架,只有在页面的脚本运行之后才会填上,所以一个原始的 HTTP 请求返回状态 200,而价格、评分和配送都是空白。要拿到真实的数据,你必须先渲染页面,而这正是 Crawling API 的 JS 令牌替你处理的。
对于 AliExpress 我需要普通令牌还是 JS 令牌?
JS 令牌。普通令牌抓取静态 HTML,在 AliExpress 上那和一个普通抓取返回的大体是同一个骨架。JS 令牌在把 HTML 交回之前先在一个真实浏览器中渲染页面,所以当 BeautifulSoup 解析它们时商品字段都在场。
我的选择器返回 None。是什么变了?
几乎肯定是 AliExpress 的标记。它的类名和 data-pl 标记会毫无预告地更改,而且在不同的商品模板和区域设置之间各不相同,所以上个月还管用的选择器可能会崩掉。在你浏览器的开发者工具里重新检查一个实时商品页面并更新选择器。定期的选择器维护对任何生产爬虫来说都是正常的。
我该如何在不同运行之间让价格和配送保持一致?
在每次请求上用 country 选项钉住地区。AliExpress 按位置变化价格、货币和配送,所以一次未钉住、在各国之间轮换的运行会产出你无法比较的记录。设定一个一致的国家也能避开那些击中不匹配 IP 的地理重定向循环。
爬取 AliExpress 时我该如何避免被封禁?
让你的每 IP 请求速率保持低,在请求之间加入抖动,让你的目标多样化而不是循环一条路径,并通过轮换的住宅 IP 来路由,这样没有任何单个地址会触发速率限制。Crawling API 替你管理轮换和一池受信任的 IP;如果你自建一套栈,那就是要投入的部分。盯着状态码,并在你开始看到挑战时退一步。
我能爬取 AliExpress 的价格来给自己的商品定价吗?
把公开的价格数据用于市场分析是一个常见的用例,但它处在 AliExpress 的服务条款和你当地的法规之内,所以在你据此构建之前先确认两者。坚守公开的商品数据,把你的量保持适中,对于获得许可的或批量的访问使用一个官方 API 或一份数据协议,而不是在规模上爬取。
大规模爬取任何站点,无需与基础设施对抗。
Crawlbase 负责处理代理、指纹和 CAPTCHA,让你的团队专注于交付数据流水线,而非维护爬取管道。1,000 次请求免费,无需信用卡。
