# JD.com Scraper — Products, Prices, Stock & Variants (China) (`tortuga/jd-scraper`) Actor

Scrape JD.com (京东) products by keyword, SKU or URL: CNY prices, review counts, good-rate %, shop, self-operated flag, images, variants, stock, delivery and barcode. No login.

- **URL**: https://apify.com/tortuga/jd-scraper.md
- **Developed by:** [Trevor Ortega](https://apify.com/tortuga) (community)
- **Categories:** E-commerce
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.50 / 1,000 product from searches

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## JD.com Scraper — Products, Prices, Stock & Variants (China)

Scrape **JD.com (京东, Jingdong)**, China's second-largest online retailer. Search by **keyword** (Chinese or English) or paste **search URLs** to get products with their **CNY price**, review count (评价), good-rate %, review tags, shop, JD self-operated (自营) flag, badges and image. Add **SKU IDs or product URLs**, or turn on **product details**, to get the brand, model, all images, every color/size **variant with its SKU ID**, **stock and delivery estimate**, shop type, services, weight, size, barcode, origin, ranking and description images.

No JD account, no login and no browser: the Actor reads what JD shows a signed-out visitor.

### What data does JD.com Scraper extract?

| Field | Example | Notes |
|---|---|---|
| `skuId`, `url`, `mobileUrl` | `100266223099`, `https://item.jd.com/100266223099.html` | |
| `title`, `listingTitle` | `OPPO Reno16 12GB+512GB 白色 2亿像素实况神机 5G小直屏 ...` | Chinese, as JD lists it; with details `title` is the product name from the product page and `listingTitle` keeps the listing text when it differed (some listings show an ad line) |
| `price`, `currency` | `4198.0`, `CNY` | search results (see "Why do SKU products have no price?") |
| `commentCount`, `commentCountText` | `100000`, `10万+` | JD rounds review counts; `commentCount` is the lower bound |
| `goodRatePercent` | `98` | 好评率 |
| `reviewTags` | `["小巧精致", "手感一流", "时尚美观"]` | review keywords JD shows for the product |
| `shopId`, `shopName`, `venderId` | `1000004065`, `OPPO京东自营旗舰店` | |
| `selfOperated` | `true` | 京东自营 (sold by JD) vs. marketplace seller |
| `badges`, `installment`, `sellingPoints` | `["京东自营", "秒杀", "12期免息", "赠品"]` | as shown on the listing |
| `presale`, `flashSale`, `newArrival`, `crossBorder` | `false`, `true`, `false`, `false` | |
| `categoryIds`, `brandId`, `spuId` | `["9987", "653", "655"]` | JD category IDs (cat1/cat2/cat3) |
| `listedAt` | `2026-05-18` | date the product went on sale |
| `image` | `https://img14.360buyimg.com/n0/jfs/...jpg` | full size |
| `position`, `page`, `searchTerm` | `1`, `1`, `手机` | |

**With product details** (always for SKU IDs and product URLs):

| Field | Example |
|---|---|
| `brand`, `model`, `shortTitle` | `OPPO`, `Reno16`, `OPPO Reno16 实况手机 国家补贴` |
| `images`, `descriptionImages` | product photos, images of the description (商品介绍) |
| `variantDimensions`, `selectedVariant` | `["外观", "存储容量"]`, `{"外观": "白色", "存储容量": "12GB+512GB"}` |
| `variants`, `variantCount` | `[{"skuId": "100276662613", "attributes": {"外观": "白色", "存储容量": "12GB+256GB"}, "image": "...", "url": "..."}]`, `54` |
| `stockState`, `stockStatus`, `stockStatusText`, `inStock` | `33`, `in_stock`, `现货`, `true` |
| `deliveryPromise`, `deliveryArea`, `shippingNote` | `11:00前付款，预计今天(10月13日)送达`, `北京 朝阳区 麦子店街道` |
| `shopType`, `services` | `KA店铺`, `["211限时达", "7天无理由退货", "京东物流"]` |
| `weightKg`, `sizeMm`, `barcode`, `origin`, `warranty` | `0.504`, `{"length": 190, "width": 102, "height": 62}`, `6942675422760`, `贵州仁怀`, `1年质保` |
| `ranking`, `purchaseLimit`, `releasedAt` | `{"name": "手机热卖榜第10名", "rank": 10}`, `2`, `2026-05-19 00:00:03` |

### How to use JD.com Scraper

1. Enter **Search terms** (e.g. `蓝牙耳机`, `手机壳`, `iphone`), and/or paste **Start URLs** or **SKU IDs**.
2. Optionally set a price range in yuan or **Only JD Logistics**.
3. Set **Max items** (you pay per product) and turn on **Include product details** if you need variants, stock and delivery.
4. Run, then export JSON, CSV or Excel.

### Input example

```json
{
  "searchTerms": ["蓝牙耳机"],
  "minPrice": 100,
  "maxPrice": 500,
  "maxItems": 100,
  "includeDetails": false
}
```

```json
{
  "skus": ["100012043978", "100266223099"],
  "startUrls": [{ "url": "https://item.jd.com/10235624200564.html" }]
}
```

Start URLs can be product pages (`item.jd.com/<sku>.html`, `item.m.jd.com/product/<sku>.html`) or search pages (`search.jd.com/Search?keyword=...`, `re.jd.com/search?keyword=...`); the keyword and a price filter in the URL are used.

### Output example

```json
{
  "type": "product",
  "skuId": "100266223099",
  "title": "OPPO Reno16 12GB+512GB 白色 2亿像素实况神机 5G小直屏 智能 拍照 学生 旗舰店手机 新款 国家补贴",
  "url": "https://item.jd.com/100266223099.html",
  "image": "https://img14.360buyimg.com/n0/jfs/t1/436065/18/21206/35608/6a103191F544252f9/008332032073e42e.jpg",
  "price": 4198.0,
  "currency": "CNY",
  "commentCount": 100000,
  "commentCountText": "10万+",
  "goodRatePercent": 98,
  "reviewTags": ["小巧精致", "手感一流", "时尚美观", "尺寸适宜"],
  "shopId": "1000004065",
  "shopName": "OPPO京东自营旗舰店",
  "selfOperated": true,
  "categoryIds": ["9987", "653", "655"],
  "badges": ["京东自营", "秒杀", "12期免息", "赠品"],
  "flashSale": true,
  "listedAt": "2026-05-18",
  "position": 2,
  "page": 1,
  "searchTerm": "手机",
  "brand": "OPPO",
  "model": "Reno16",
  "variantCount": 54,
  "selectedVariant": { "外观": "白色", "存储容量": "12GB+512GB", "自定义": "国家补贴15%至高减500" },
  "stockStatus": "in_stock",
  "stockStatusText": "有货",
  "deliveryPromise": "付款后预计今天07:30-08:00间为您送达",
  "deliveryArea": "北京 朝阳区 麦子店街道",
  "barcode": "6942675422760",
  "weightKg": 0.504,
  "detailsScraped": true
}
```

### How much does it cost?

Pay per product: **$0.0035 per search result** (with price) and **$0.0017 per product page** — added to a search result when details are on, or alone for each SKU ID / product URL. A search result with details costs $0.0052. There is no start fee. Platform usage is small: the default Apify datacenter proxy adds no traffic cost, 1,000 search results take about 25 requests (well under $0.01 of compute) and 1,000 products with details about 2,000 requests and 15-20 minutes (roughly $0.03-0.06 of compute).

### How to scrape JD.com search results

Enter Chinese or English keywords. Results come from JD's public 京东热卖 product search (re.jd.com), the keyword search JD serves to signed-out visitors; 48 products per page with prices. Its order is JD's own (sorting cannot be changed), it favours promoted products and repeats some of them across pages, so the Actor removes duplicates and stops when pages add nothing new. The main search page (search.jd.com) sends signed-out visitors to a verification page, so search.jd.com URLs are run as the same keyword on the public listing. Price filters are applied by JD and checked again by the Actor.

### Why do SKU products have no price?

JD hides the price on product pages from signed-out visitors (it shows `¥4??8` and "登录查看价格", log in to see the price). The Actor does not log in and does not output masked values, so products scraped from a SKU ID or product URL have `price: null`. Search results carry the real price, and with details on a search result keeps its price and gets all product-page fields.

### Can it scrape JD reviews and specifications?

Not at the moment. JD serves reviews (评价), the specification table (规格与包装) and its other product APIs only to signed-in users or to requests signed by its in-browser anti-bot code, which this Actor does not imitate. You still get the review count, good-rate % and review tags of every search result.

### Monitor changes on a schedule

Turn on **Only new or changed items** and the Actor remembers what earlier runs of the same input returned: each run outputs only products that are new in the watched results or whose price (search results) or stock state (SKU products) changed. Unchanged products are dropped before any product page is opened and are not charged. **Max items** becomes the window checked on every run. Save the input as a task and add a Schedule to it in Apify Console (for example daily). Every output product carries `changeType` (`new` or `changed`); changed ones carry `previousValues`, e.g. `{"price": 4198.0}`. JD's keyword listing rotates promoted products, so a scheduled search also reports products that newly entered the watched window; products given by SKU report only stock changes. Use **Monitoring key** to keep several schedules on the same search separate.

### Does it work without login?

Yes. Everything comes from what JD shows a signed-out visitor: the public 京东热卖 product search and the mobile product pages. The Actor does not log in, does not solve captchas and does not bypass verification pages. Delivery estimates are for JD's default address (Beijing).

### Integrations and API

Use the results in Make, Zapier, n8n or Google Sheets, or call the Actor from Python or JavaScript with the Apify client. The **API** tab has ready-made snippets.

### Is it legal to scrape JD.com?

The Actor collects only product data JD shows publicly to signed-out visitors: listings, prices, review counts and the shop names sellers publish. It does not log in, does not reveal masked values and collects no personal data. You are responsible for how you use the data and for complying with JD's terms and applicable law.

### Support

Found a bug or need a field? Open an issue in the **Issues** tab.

# Actor input Schema

## `searchTerms` (type: `array`):

Keywords to search on JD.com, one search per line, e.g. 蓝牙耳机, 手机壳, iphone. Chinese keywords give the best results. Results come from JD's public 京东热卖 listing (re.jd.com), the keyword search JD shows to signed-out visitors, with CNY prices; its order is JD's own and cannot be changed.

## `startUrls` (type: `array`):

JD URLs: product pages (item.jd.com/<sku>.html or item.m.jd.com/product/<sku>.html, always scraped with details) and search pages (search.jd.com/Search?keyword=... or re.jd.com/search?keyword=...; the keyword and a price filter in the URL are used). Shop pages are not supported.

## `skus` (type: `array`):

JD product numbers (SKU IDs), e.g. 100012043978 from https://item.jd.com/100012043978.html. Each SKU is scraped from its product page with details. JD hides product-page prices from signed-out visitors, so these items have no price; search results do.

## `maxItems` (type: `integer`):

Stop after this many products in total (search results plus SKU / URL products). Keeps cost predictable. With 'Only new or changed items' on, this is how many products each run checks.

## `includeDetails` (type: `boolean`):

Open each search result's product page for brand, model, images, all color/size variants with their SKU IDs, stock and delivery estimate (default area Beijing), shop type, services, weight, size, barcode, origin, ranking and description images. Charged as an extra 'detail' event per product and slower (one page load per product).

## `minPrice` (type: `integer`):

Only search results priced at or above this many yuan.

## `maxPrice` (type: `integer`):

Only search results priced at or below this many yuan.

## `jdLogisticsOnly` (type: `boolean`):

Only search results shipped by JD Logistics (mostly JD self-operated stores), using JD's own listing filter.

## `onlyNewOrChanged` (type: `boolean`):

Remember what earlier runs of this search returned and output only new items or items whose price/status changed. Use with a Schedule; unchanged items are not charged.

## `monitoringKey` (type: `string`):

Name for this watch, so several schedules on the same search stay separate; defaults to a key derived from the search input

## `proxyConfiguration` (type: `object`):

JD's listing and product pages answer Apify datacenter proxies (the default, no extra traffic cost). If you see many 'not loaded' errors, switch to RESIDENTIAL with country CN (billed per GB: about 15-40 KB per 48-product search page and 50-80 KB per product page).

## Actor input object example

```json
{
  "searchTerms": [
    "蓝牙耳机"
  ],
  "maxItems": 100,
  "includeDetails": false,
  "jdLogisticsOnly": false,
  "onlyNewOrChanged": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `results` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "searchTerms": [
        "蓝牙耳机"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("tortuga/jd-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "searchTerms": ["蓝牙耳机"],
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("tortuga/jd-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "searchTerms": [
    "蓝牙耳机"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call tortuga/jd-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,tortuga/jd-scraper"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/46ZgJ6v3bzLH9FyHH/builds/estgZZRj7zFWWu78k/openapi.json
