AliExpress 是网络上最大的电商平台之一,单个搜索结果页面就包含驱动价格追踪、产品调研和供应商发现所需的数据:产品标题、价格、卖家评分、订单或销量,以及返回各个商品详情页的链接。提取某个关键词下的这些数据,你就能得到一个结构化视图,清晰展示哪些产品在卖、价格几何、评分如何,而这些都来自公开的商品信息。

本指南介绍如何使用 JavaScript 和 Node.js 抓取 AliExpress 搜索页面。你将构建一个小型可运行的爬虫,它接受一个关键词并构建对应的 AliExpress 搜索 URL,通过 Crawling API 获取渲染后的结果页面,用 cheerio 解析每张产品卡片,遍历分页,并将数据导出为 JSON 和 CSV。整个演示范围限定在公开搜索和商品数据,靠近文末的法律部分并非套话,请在将此工具指向任何实际体量之前仔细阅读。

你将构建的内容

一个 Node.js 脚本,它接受搜索关键词,构建 AliExpress 搜索 URL,通过 Crawling API 获取渲染后的 HTML,并为结果页面上的每个产品提取一条结构化记录。我们提取以下字段,与旧版 AliExpress SERP 爬虫返回的字段集相同:

  • 标题 商品名称,例如"Wireless Bluetooth Earbuds Noise Cancelling"。
  • 价格 卡片上显示的当前价格,如"$12.96"。
  • 评分 卖家或产品评分值,例如"4.9"。
  • 订单数 订单或销量数量,例如"600 sold"。
  • 产品 URL 各商品详情页的链接。

为什么普通请求在 AliExpress 上会失败

如果你用普通的 HTTP 客户端请求 AliExpress 搜索 URL,你会收到状态码 200 的响应,但正文中几乎没有可用的产品数据。有两个原因对你不利。其一,AliExpress 通过 JavaScript 在浏览器中构建搜索结果,因此初始 HTML 在页面脚本运行并渲染产品网格之前几乎是空壳。其二,AliExpress 能快速标记自动化流量:来自数据中心的 IP 以及看起来不像真实浏览器的请求模式,在到达渲染后的商品列表之前就会受到质询、限速或遭遇 CAPTCHA。

因此,一个可用的 AliExpress 搜索爬虫需要在一次请求中满足两点:一个能真正渲染页面的浏览器,以及一个平台认为是真实访客的 IP。你可以自己组合一个无头浏览器加上一批轮换住宅代理,但将这些拼合在一起并保持其正常运转是工作的大头。Crawling API 将两者合并到一次调用中:你发送带有 JavaScript token 的 URL,它在可信 IP 后渲染页面,并返回供你解析的完整 HTML。

为什么需要 JS token

Crawlbase 提供两种 token 类型。普通 token 获取静态 HTML;JavaScript(JS)token 会先在真实浏览器中渲染页面。AliExpress 在客户端构建其产品网格,因此 JS token 能让你在这里获得最完整的页面。使用普通 token 可能返回没有任何产品的空壳,让你无从解析。

前置条件

在编写任何代码之前,你需要准备好几样东西。这些都不需要花很长时间。

基础 JavaScript 和 Node.js 知识。你应该能够编写和运行 Node 脚本,并使用 npm 安装包。如果你是 Node 新手,关于如何用 Node.js 构建网络爬虫的演示涵盖了本教程所假设的基础知识。

Node.js 16 或更高版本。使用 node --version 确认你的版本。如果没有,请从 Node.js 官网安装,或通过 nvm 等版本管理器安装。

Crawlbase 账户和 JS token。注册账户,打开控制台,从账户文档页面复制你的 JavaScript(JS)token。请将 token 视为密码:它用于验证你的请求身份,请不要将其提交到版本控制中。

搭建项目

创建项目文件夹,初始化项目,并安装爬虫所需的两个库。

bash
node --version

mkdir aliexpress-search-scraper && cd aliexpress-search-scraper
npm init -y

npm install crawlbase cheerio

两个依赖包承担实际工作:crawlbase 是 Crawling API 的官方 Node 客户端,cheerio 以 jQuery 风格的 API 解析返回的 HTML,让你可以通过 CSS 选择器提取各个字段。如果选择器对你来说是新知识,关于 XPath 和 CSS 选择器的入门指南是一个好伴侣。

步骤 1:从关键词构建搜索 URL

AliExpress 将关键词搜索转化为可预测的 URL。批发搜索路径接受关键词(空格替换为连字符),这正是旧版爬虫使用的转换方式。将其封装成一个小辅助函数,让任意关键词都能变成有效的搜索 URL。

javascript
function searchUrl(keyword, page = 1) {
  const slug = keyword.trim().split(' ').join('-');
  return `https://www.aliexpress.com/w/wholesale-${slug}.html?page=${page}`;
}

console.log(searchUrl('wireless earbuds'));
// https://www.aliexpress.com/w/wholesale-wireless-earbuds.html?page=1

page 参数是你稍后用来遍历分页的参数。现在将其保持为 1,先让单页正常工作,再扩展规模。

步骤 2:获取渲染后的搜索页面

接下来,获取完整的页面。导入 CrawlingAPI 类,用你的 JS token 初始化它,然后请求搜索 URL。在解析前检查状态码,可以让失败请求显式报错,而不是静默失败。

javascript
const { CrawlingAPI } = require('crawlbase');

const api = new CrawlingAPI({ token: 'YOUR_CRAWLBASE_TOKEN' });

async function crawl(pageUrl) {
  const options = { ajax_wait: 'true', page_wait: 5000 };
  const response = await api.get(pageUrl, options);
  if (response.statusCode === 200) {
    return response.body;
  }
  console.error(`Request failed: ${response.statusCode}`);
  return null;
}

crawl(searchUrl('wireless earbuds')).then((html) => {
  console.log(html ? html.slice(0, 500) : 'No HTML returned');
});

两个等待选项对于像这样的客户端渲染目标至关重要。ajax_wait 告诉 API 等待异步内容加载完成,page_wait 则在加载后固定等待若干毫秒,让晚渲染的产品网格在捕获页面前出现。五秒是一个合理的起始值;如果产品返回为空,可以适当增大。用 node scraper.js 运行脚本,你应该会看到真实的产品标记,而不是简化的空壳。这证明渲染有效,然后再编写任何选择器。

Crawlbase AliExpress Scraper

AliExpress 在客户端构建其产品网格并向爬虫流量发起质询,因此你需要在一次调用中同时获得渲染后的页面和可信 IP。Crawling API 接受 JS token,在真实浏览器中运行页面,在服务端轮换住宅 IP,并将完整 HTML 返回给你,从而省去了自己运营无头浏览器集群和代理池的麻烦。先在免费套餐上将其指向一个公开搜索页面。

步骤 3:用 cheerio 解析每个产品

拿到渲染后的 HTML,将其加载到 cheerio 中并遍历产品卡片。AliExpress 将每个搜索结果布局在一个重复出现的卡片中,因此你选择所有卡片,然后从中读取标题、价格、评分、订单数和商品链接。对每个字段进行防御性读取,能防止单个缺失值让整次运行崩溃。

javascript
const cheerio = require('cheerio');

function parseSearch(html) {
  const $ = cheerio.load(html);
  const items = [];

  $('a.search-card-item').each((_, el) => {
    const card = $(el);
    const title = card.find('[title]').first().attr('title');
    if (!title) return;

    const href = card.attr('href') || '';
    const url = href.startsWith('//') ? `https:${href}` : href;

    items.push({
      title: title.trim(),
      price: card.find('.multi--price-sale--U-S0jtj').text().trim() || null,
      rating: card.find('.multi--starList--Fh2vqvr').attr('aria-label') || null,
      orders: card.find('.multi--trade--Ktbl2jB').text().trim() || null,
      url: url || null,
    });
  });

  return items;
}

有几个细节保证了代码的健壮性。标题从卡片的 title 属性中读取,而非其文本内容,因为 AliExpress 会截断可见名称,但在属性中保留完整字符串。AliExpress 上的产品 URL 通常是协议相对路径(以 // 开头),因此辅助函数在前面加上 https: 使其变为绝对路径,这与旧版输出一致(裸 https: 链接是已知的粗糙边界情况)。当元素缺失时,每个字段都回退到 null,这很常见,因为并非每张卡片都显示评分或订单数。

选择器会发生变化

AliExpress 对其类名进行哈希处理(如 multi--price-sale--U-S0jtjmulti--starList--Fh2vqvr 等),并在部署时重新生成这些哈希值,因此它们会在没有任何通知的情况下更改。请将上面的选择器视为起始模板,而非契约。当某个字段返回 null 时,在浏览器的开发者工具中重新检查实时页面并更新选择器。定期维护选择器对于任何生产爬虫来说都是正常的,而不是出了问题的迹象。

步骤 4:组合在一起

现在将 URL 构建器、获取逻辑和解析逻辑组合成一个可运行的脚本。构建 URL,获取渲染后的 HTML,将其传递给解析器,并打印结构化记录。

javascript
const { CrawlingAPI } = require('crawlbase');
const cheerio = require('cheerio');

const api = new CrawlingAPI({ token: 'YOUR_CRAWLBASE_TOKEN' });

function searchUrl(keyword, page = 1) {
  const slug = keyword.trim().split(' ').join('-');
  return `https://www.aliexpress.com/w/wholesale-${slug}.html?page=${page}`;
}

async function crawl(pageUrl) {
  const options = { ajax_wait: 'true', page_wait: 5000 };
  const response = await api.get(pageUrl, options);
  if (response.statusCode === 200) return response.body;
  console.error(`Request failed: ${response.statusCode}`);
  return null;
}

function parseSearch(html) {
  const $ = cheerio.load(html);
  const items = [];
  $('a.search-card-item').each((_, el) => {
    const card = $(el);
    const title = card.find('[title]').first().attr('title');
    if (!title) return;
    const href = card.attr('href') || '';
    const url = href.startsWith('//') ? `https:${href}` : href;
    items.push({
      title: title.trim(),
      price: card.find('.multi--price-sale--U-S0jtj').text().trim() || null,
      rating: card.find('.multi--starList--Fh2vqvr').attr('aria-label') || null,
      orders: card.find('.multi--trade--Ktbl2jB').text().trim() || null,
      url: url || null,
    });
  });
  return items;
}

async function main() {
  const html = await crawl(searchUrl('wireless earbuds'));
  if (!html) return;
  const items = parseSearch(html);
  console.log(JSON.stringify(items.slice(0, 3), null, 2));
}

main();

输出结果示例

node scraper.js 运行完整脚本,你将获得一个整洁的记录数组,每条记录对应一个产品,可直接写入 JSON、CSV 或数据库。

json
[
  {
    "title": "Wireless Bluetooth Earbuds Noise Cancelling Touch Control",
    "price": "$12.96",
    "rating": "4.9",
    "orders": "600 sold",
    "url": "https://www.aliexpress.com/item/1005005690275912.html"
  },
  {
    "title": "TWS Gaming Earphones Low Latency Long Battery Life",
    "price": "$8.31",
    "rating": "4.7",
    "orders": "2000 sold",
    "url": "https://www.aliexpress.com/item/1005005123456789.html"
  }
]

循环遍历结果页面

一页结果只是演示;真正的任务需要遍历分页。AliExpress 通过 page 查询参数暴露页码,而 searchUrl 辅助函数已经接受这个参数,因此你在循环中构建每个页面的 URL,通过 Crawling API 获取它,用同一函数解析,然后收集所有数据行。由于每个结果页面共享相同的卡片结构,你已经编写好的解析器可以无需任何修改地跨所有页面工作。

javascript
async function scrapePages(keyword, totalPages) {
  const all = [];
  for (let page = 1; page <= totalPages; page++) {
    const html = await crawl(searchUrl(keyword, page));
    if (html) all.push(...parseSearch(html));
  }
  return all;
}

scrapePages('wireless earbuds', 3).then((rows) => {
  console.log(`Collected ${rows.length} products`);
});

如果你想为每一行补充完整的详细信息(包括每张图片、完整描述、配送选项和完整的卖家资料),从每张卡片中取出 url,通过同一个 crawl 函数获取该商品详情页,然后为产品页面布局编写一个小型解析器。模式完全相同:先渲染,再解析。关于这项工作在另一种语言中的产品页面版本,可参考如何使用 Python 抓取 AliExpress 产品

导出为 JSON 和 CSV

在内存中收集数据行对于演示来说没问题,但通常你需要将它们保存到磁盘。Node 内置的 fs 模块一行代码就能写入 JSON,而一个小辅助函数能将同一数组转换为 CSV 格式,方便导入电子表格或快速查看。

javascript
const fs = require('fs');

function toCsv(rows) {
  const headers = ['title', 'price', 'rating', 'orders', 'url'];
  const escape = (v) => `"${(v ?? '').toString().replace(/"/g, '""')}"`;
  const lines = rows.map((r) => headers.map((h) => escape(r[h])).join(','));
  return [headers.join(','), ...lines].join('\n');
}

scrapePages('wireless earbuds', 3).then((rows) => {
  fs.writeFileSync('aliexpress-products.json', JSON.stringify(rows, null, 2));
  fs.writeFileSync('aliexpress-products.csv', toCsv(rows));
  console.log(`Saved ${rows.length} products to JSON and CSV`);
});

CSV 辅助函数对每个字段加引号并对内嵌引号进行转义,这样产品标题中的逗号就不会破坏列结构。从这里开始,JSON 可以馈入数据库或 notebook,而 CSV 可以直接在电子表格中打开,快速扫描价格。

保持不被封锁

即使渲染问题已经解决,AliExpress 仍然会监视爬虫形态的流量。一些良好习惯能让运行保持健康,这些习惯同样适用于任何防御严密的商业目标。

  • 控制请求速率。在紧密循环中密集请求页面是被限速或遭遇 CAPTCHA 的最快方式。分散请求,并在不同关键词之间轮换,而不是以全速爬取同一路径。
  • 依赖 IP 轮换。一批住宅 IP 将请求分散到众多真实用户地址上,这样单个地址就不会触发速率限制。Crawling API 会为你处理这个问题;如果你自己搭建技术栈,这是最需要做好的部分。
  • 关注状态码。一次运行开始返回质询或错误,说明当前速率或 IP 级别已不够用。将这视为退后的信号,而不是可以忽略的噪声。

更广泛的操作手册可参考如何在不被封锁的情况下爬取网站。如果你希望通过轮换池路由自己的流量,而不是使用托管 API,Smart AI Proxy 以即插即用代理端点的形式提供与之相同的住宅 IP 轮换;以代理为先的方式处理该站点可参考 AliExpress 代理抓取。AliExpress 也是更广泛的电商网络爬取工作的常见目标,相同的获取-解析模式可以跨站点使用,而你在此收集的价格字段可以直接馈入价格情报分析。

抓取 AliExpress 是否合法?

抓取 AliExpress 是否被允许,取决于 AliExpress 的服务条款、你所在的司法管辖区以及你对数据的使用方式。AliExpress 的条款限制自动化访问,因此无论你的工具多么谨慎,爬取行为都可能违反这些条款。本文中的代码没有改变这一点,它只是让技术部分得以实现。请阅读 AliExpress 的使用条款和其 robots.txt,并将两者视为你采集内容的边界。

以下几条原则值得坚守。仅采集公开搜索数据:任何人无需账户即可看到的产品标题、价格、评分、订单数和商品链接。尊重 AliExpress 声明的速率预期,保持请求量足够低,不要给其服务器造成压力。避免采集个人数据,包括任何与可识别买家或卖家相关联的信息(超出卡片上公开显示的店铺名称之外),也不要批量转载产品图片或描述,因为这些是卖家的版权媒体。如果你计划将数据用于商业目的,请获得许可或签署官方数据协议,而不是假设沉默即为同意。

对于批量或商业用途,AliExpress 通过其母公司阿里巴巴提供官方联盟和开放平台 API,这才是你需要大量数据、有保障的数据结构或商业权利时的正确工具。本指南刻意将范围限定在公开搜索和商品页面,因为这是让工作保持在可辩护范围内的边界线。它不涵盖登录墙后的任何内容、买家或卖家的个人数据、用户之间的私信、需要登录才能访问的订单或账户数据,也不涵盖任何绕过身份验证的尝试。如果你的项目需要的不仅仅是公开商品数据,官方 API 或数据协议是正确的路径,而不是更巧妙的爬虫。

回顾

核心要点

  • AliExpress 在客户端构建其产品网格。普通请求返回空壳,因此必须先渲染搜索页面再进行解析。
  • 渲染和可信 IP 缺一不可。带 JS token 的 Crawling API 在一次调用中同时完成两者;ajax_waitpage_wait 控制等待产品网格加载的时长。
  • cheerio 完成数据提取。选择每张搜索卡片,然后将标题、价格、评分、订单数和产品 URL 映射到当前选择器,并预期 AliExpress 的哈希类名会发生变化。
  • 通过循环 page 参数实现扩展。page 查询参数用于翻页,同一解析器适用于每一页,然后将数据行导出为 JSON 和 CSV。
  • 坚守公开数据范围。尊重 AliExpress 的服务条款和 robots.txt,对于批量或商业用途优先使用官方阿里巴巴 API,绝不触碰登录信息、个人数据或你会转载的版权媒体。

常见问题

为什么普通请求在 AliExpress 上返回的不是产品?

因为 AliExpress 通过 JavaScript 在浏览器中构建其搜索结果。初始 HTML 在页面脚本运行并渲染产品网格之前几乎是空壳,因此原始 HTTP 请求返回状态码 200 但没有任何可用的产品数据。要获取完整页面,必须先渲染它,这正是 Crawling API 的 JS token 为你处理的事情。

AliExpress 需要普通 token 还是 JS token?

使用 JS token。普通 token 获取静态 HTML,而在 AliExpress 上这意味着不含产品的页面。JS token 在返回 HTML 之前先在真实浏览器中渲染页面,因此当 cheerio 解析时,产品卡片都已经存在。

如何抓取 AliExpress 搜索结果的多个页面?

AliExpress 通过批发搜索 URL 上的 page 查询参数暴露页码。在循环中递增它,通过 Crawling API 获取每一页,并对每一页运行同一个解析器。卡片结构在所有页面上都是相同的,因此一个解析器就能收集所有数据行,然后你将它们写入 JSON 或 CSV。

我的选择器返回 null,发生了什么?

几乎可以肯定是 AliExpress 的标记发生了变化。其产品卡片使用哈希类名,如 multi--price-sale--U-S0jtj,网站在部署时会重新生成这些哈希值,因此上个月有效的选择器可能已经失效。在浏览器的开发者工具中重新检查实时页面并更新选择器。定期维护选择器对于任何生产爬虫来说都是正常的。

我可以从 AliExpress 抓取买家或卖家的个人数据吗?

不可以,本指南也不涵盖这方面内容。买家详情、私信和账户数据位于登录墙后面,因此不属于公开数据。卡片上公开显示的店铺名称可以记录,但抓取需要登录的内容、个人数据,或绕过身份验证来访问这些内容,超出了本文的讨论范围,也违反了 AliExpress 的条款。如需获批访问,正确途径是官方阿里巴巴 API 或许可协议。

我应该使用官方 API 还是直接抓取网站?

如果你需要大量数据、有保障的数据结构或商业再利用权利,请使用官方阿里巴巴开放平台或联盟 API。这些工具正是为此而生的,也能让你遵守 AliExpress 的条款。使用本指南中的方法抓取公开搜索页面适合无法获取 API 访问权限的小规模公开数据研究,但前提是你必须尊重服务条款、robots.txt 和速率限制。

开始构建

大规模爬取任何站点,无需与基础设施对抗。

Crawlbase 负责处理代理、指纹和 CAPTCHA,让你的团队专注于交付数据流水线,而非维护爬取管道。1,000 次请求免费,无需信用卡。

自助开通 · 无需销售通话 · 提供企业级爬取量