# 人人车 Renrenche Used Car (`songd/renrenche-scraper`) Actor

Scrape used car listings from renrenche.com (Renrenche / 58.com) by city, brand/model, price, mileage, age, body type, transmission, color and more. Decoded prices (font-encrypted on the site), full detail pages with specs, photos and seller info — per-event pricing.

- **URL**: https://apify.com/songd/renrenche-scraper.md
- **Developed by:** [Singed](https://apify.com/songd) (community)
- **Stats:** 2 total users, 1 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $4.00 / 1,000 listing enriches

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## Renrenche Used Car Scraper / 人人车二手车采集 (Apify Actor)

Scrape used car listings from **Renrenche / 人人车** ([renrenche.com](https://www.renrenche.com/), part of 58.com) across 683 Chinese cities — by city, brand/model, price, mileage, age, displacement, body type, transmission and color. The actor solves renrenche's antibot wall (58.com + Yidun captcha) in pure code, decodes the site's rotating font-encrypted prices at runtime, and can enrich every listing with full detail-page data: VIN (masked), spec tables, photo gallery, seller info and the owner's description. **Pay-per-event pricing** — you pay only for the results you get.

[![Apify Store](https://img.shields.io/badge/Apify-Store-blue)](https://apify.com) [![Python](https://img.shields.io/badge/Python-3.12-blue)](https://docs.apify.com/actors/development/python)

### Why scrape Renrenche?

- **China used-car market data** — prices (in 万 CNY, the site's own unit), mileage, registration year, tags (验真 verified, 0次过户 0-owners, 原厂质保 warranty) for any city, brand or model.
- **Per-city inventory** — Beijing alone lists ~370,000 cars; every city has its own inventory and price level.
- **Detail-page enrichment** — VIN (masked), first registration, displacement, emission standard, spec tables, full original-size photo gallery, seller stats, new-car price and the owner's free-text description.
- **Decoded prices** — Renrenche renders prices with custom rotating "digit" fonts; the actor extracts the current font from every page and decodes prices to numbers, cross-checked against the plain-text price in each detail page title.

### Features

| Category | Capabilities |
|---|---|
| **Search** | City (683, Chinese name or URL slug), brand/model (auto-resolved to the site's slug pages), or ready-made renrenche URLs |
| **Filters** | Price (万 CNY), mileage (万公里), car age, displacement, body type, transmission, exterior colors (multi-select = union), insured-checks / video / new-energy toggles |
| **Enriched data** | Detail price cross-check, new-car price, color, first registration, VIN (masked), spec tables, full photo gallery, seller info, owner description — fetched per listing |
| **Antibot** | The 58.com verifycode wall (Yidun slide captcha) is solved in-process, once per exit IP; the sequential pagination gate (server-minted `reentries` token, one page after another on one session) is walked exactly like a real user; hard antibot denies trigger automatic rotation to a fresh IP/session |
| **Price fonts** | The site's rotating price-encryption fonts are decoded at runtime from the font embedded in each page (never stale) |
| **Reliability** | De-duplication across the whole run, pagination-gate recovery (same-page retry → chain rebuild → page skip), graceful stop at your spending limit, clear fail-fast messages when the site cannot be reached |

### Pricing (pay-per-event)

You are charged only for what you receive, event by event:

- **`listing`** — charged for **every listing saved to the dataset** (the listing-card data: decoded price, mileage, year, tags, photo, URL, …).
- **`listing-detail`** — charged **in addition** for every **enriched listing** (enrichment is controlled by `maxDetails`; `0` = unlimited, i.e. every listing is enriched by default). Enriched listings include much more content, so they cost more than a plain listing.

**Not charged:** duplicate listings (de-duped across the whole run), unavailable pages, empty results, and detail pages that are gone (the listing is still returned with its search fields, and no `listing-detail` is charged).

**Maximum cost per run.** You can set a spending limit in the Apify Console or via the API (`maxTotalChargeUsd`). The actor checks the limit, caps its own work so it fits the budget, and **stops gracefully**, keeping everything scraped so far.

Exact prices are configured by the actor owner in Apify Console and are intentionally **not** listed here — check the pricing on the Apify Store page.

### Input

| Field | Type | Default | Description |
|---|---|---|---|
| `city` | string | `bj` | City to scrape: the URL slug (`bj`, `sh`, `gz`, …) or the Chinese name (`北京`, `上海`). 683 cities supported; validated and auto-resolved. Ignored when `startUrls` is set. |
| `startUrls` | URL list | – | One or more renrenche listing/brand/series URLs. When set, **all other search fields are ignored** — city slugs, brand/series path slugs, `pve_<code>_<values>` filter segments, `pn<N>` page numbers and the `refundable` / `param112691` / `xnycar` query toggles are all understood (see [Start-URL example](#start-url-example)). |
| `brand` | string | – | Brand in Chinese as shown on the site (e.g. `大众`, `宝马`) or the site slug (`dazhong`, `baoma`); resolved to the brand page `/<city>/<brand>/`. |
| `model` | string | – | Model/series name or slug (e.g. `卡罗拉`, `kaluola`); resolved to the series page `/<city>/<series>/`. Falls back to the whole brand when not found. |
| `priceMin` / `priceMax` | number | 0 | Price range in **万 CNY** (10,000 CNY units — how the site quotes prices). `3` = ¥30,000. Max `0` = no limit. |
| `mileageMin` / `mileageMax` | number | 0 | Mileage range in **万公里** (10,000 km units — the site's filter unit). `3` = 30,000 km. Max `0` = no limit. |
| `ageMin` / `ageMax` | integer | 0 | Car age in years since first registration. Max `0` = no limit. |
| `displacementMin` / `displacementMax` | number | 0 | Engine displacement range in liters. Max `0` = no limit. |
| `bodyType` | select | `any` | Sedan / SUV / MPV / Sports / Van / Pickup / New energy / Any. |
| `transmission` | select | `any` | Automatic / Manual / Any. |
| `colors` | string list | – | Exterior colors (black, white, red, gray, blue, yellow, brown, green, purple, pink, other). Multiple colors are OR-combined. |
| `refundable` | boolean | false | Only listings with the 检测保障 insured-inspection guarantee. |
| `videoOnly` | boolean | false | Only listings that include a video. |
| `newEnergy` | boolean | false | Only new-energy (electric / hybrid) vehicles. |
| `maxPages` | integer | 0 | Result pages (~50 listings each) to scrape per search or start URL. **`0` = all available pages (default)**, up to the site's cap of 70. |
| `maxItems` | integer | 300 | Stop after pushing this many listings in total. **`0` = unlimited** (`maxPages` still applies). |
| `maxDetails` | integer | 0 | Enrich this many listings with the full detail-page data (see [Enriched fields](#enriched-fields-when-maxdetails-covers-the-listing)). **`0` = unlimited** — every listing is enriched. Each enriched listing is additionally charged as a `listing-detail` event. |

#### Start-URL example

```text
https://www.renrenche.com/bj/ershouche/pve_5864_3_5/pn2/
```

(Beijing, price 3–5万, page 2.) Start URLs are copied straight from [renrenche.com](https://www.renrenche.com/bj/ershouche/) or built by hand — the actor parses every supported filter:

- **Filters** (`pve_<code>_<values>` segments, joined by `/`): `pve_5864` price (万), `pve_5865` mileage (万公里), `pve_112848` age (years), `pve_2451` displacement (L), `pve_2539` body type, `pve_11287` transmission, `pve_4917` color (repeat the segment for multiple colors)
- **Brand/series**: the path slug after the city (`/bj/dazhong/`), composable with pve segments
- **`pn<N>`** — the page to start from
- **Toggles** (query): `?&refundable=1`, `?&param112691=1` (video), `?&xnycar=1` (new energy)

Multiple start URLs are scraped as separate searches and de-duplicated across the whole run.

### Results limit per search (site cap)

Renrenche caps **every search at 70 pages** (~50 listings per page, ≈ 3,500 listings) regardless of how many cars match — pages beyond `pn70` return an empty list. The site also gates pagination itself: page N+1 only serves to the browser session (a server-minted `reentries` token plus its cookies) that just served page N, so the actor scrapes each search's pages strictly in order on one session, exactly like a real user paging through the results. A gated page is retried and recovered automatically (same-page retry, chain rebuild, page skip); genuinely empty pages end the search cleanly, and empty pages are never charged.

Beijing alone has ~370,000 listings, so to collect more of the inventory, narrow the filters (brand, price range, …) and run several searches — each gets its own 70-page budget, de-duplicated across the run.

### Output (default dataset)

Every listing is pushed as one dataset item, in platform page order:

| Field | Description |
|---|---|
| `id` | Renrenche listing id (`data-entid`, unique key) |
| `url` | Clean detail-page URL |
| `title` | Listing title: brand + model + year + trim |
| `priceWan` / `priceCny` | Decoded price in 万 CNY and plain CNY |
| `registrationYear` | First-registration year from the card |
| `mileageKm` / `mileageText` | Mileage in km and as displayed |
| `tags` | Card labels (验真, 新上架, 0次过户, 原厂质保, …) |
| `image` | Card photo URL |
| `postTimeText` | Posted time as displayed (今天 = today) |
| `city` / `searchUrl` | City slug and the listing page the item was found on |
| `scrapedAt` | UTC timestamp |

#### Enriched fields (when `maxDetails` covers the listing)

| Field | Description |
|---|---|
| `detailTitle` | Full detail-page title (h1): brand + model + year + trim |
| `detailPriceWan` | Price from the detail page (cross-check of `priceWan`) |
| `newCarPriceWan` | New-car price incl. tax, when shown |
| `color` | Exterior color (Chinese) |
| `firstRegistrationDate` / `registrationTime` | First registration (`2017.12` / `2017年12月`) |
| `mileageText` | Mileage as shown on the detail page (表显里程) |
| `displacement` / `transmission` / `emissionStandard` | From the detail meta row |
| `vinMasked` | VIN as masked by the site (`LGBR******R043737`) |
| `specifications` | Detail-page spec tables grouped by section (基本参数 / 发动机参数 / 车身参数), empty `--` values omitted |
| `images` / `imageCount` | Full original-size photo gallery, de-duplicated |
| `address` | Where the car can be seen (the detail page's location line) |
| `postDateText` | Detail-page update time as displayed (今天更新 = updated today) |
| `seller` | `{name, phoneAnswerRate, imReplyRate, avatar}` |
| `serviceTags` | Detail-page guarantee tags |
| `description` / `descriptionSections` | The owner's free-text description (joined + per-topic sections) |

### Support & Feature Requests 📬

If you encounter any issues or have ideas for new features, please don't hesitate to open an issue. We value your feedback and will do our best to improve the scraper based on your suggestions.

### Legal note

Scraped data is provided as-is for personal and commercial use at your own risk. Respect renrenche.com's terms of service and applicable laws in your jurisdiction.

***

**SEO Keywords**: renrenche scraper, renrenche.com scraper, 人人车 scraper, used car scraper, china used cars, 58.com used cars, used car price data, car VIN scraper, apify car actor, china car market data

# Actor input Schema

## `city` (type: `string`):

City to scrape, as the site writes it in its URLs: the pinyin slug (e.g. bj, sh, gz, cd) or the Chinese name (e.g. 北京, 上海). 683 cities are supported; the actor validates and resolves the input. Default bj (Beijing). Ignored when startUrls is set.

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

One or more renrenche.com listing URLs to scrape, e.g. https://www.renrenche.com/bj/ershouche/pve_5864_3_5/pn2/ (price 3-5万, page 2), https://www.renrenche.com/bj/dazhong/ (Volkswagen brand page). City, brand/series path slugs, pve\_<code>\_<values> filter segments, pn<N> page numbers and the refundable / param112691 / xnycar query toggles are all understood. When provided, these URLs take priority and all other search fields below are ignored.

## `brand` (type: `string`):

Brand name in Chinese as shown on renrenche.com (e.g. 大众, 宝马, 奥迪) or the site's brand slug (e.g. dazhong, baoma). Resolved to the brand page /<city>/<brand-slug>/. Ignored when startUrls is set.

## `model` (type: `string`):

Model/series name or slug (e.g. 卡罗拉 or kaluola). Resolved to the series page /<city>/<series-slug>/. Requires a brand whose pages contain that series; if the series is not found the whole brand page is scraped.

## `priceMin` (type: `number`):

Minimum price in 万 CNY (10,000 CNY units — the site quotes prices this way). 3 = 30,000 CNY.

## `priceMax` (type: `number`):

Maximum price in 万 CNY. 0 = no limit.

## `mileageMin` (type: `number`):

Minimum mileage in 万公里 (10,000 km units — the site filters this way). 3 = 30,000 km.

## `mileageMax` (type: `number`):

Maximum mileage in 万公里. 0 = no limit.

## `ageMin` (type: `integer`):

Minimum car age in years since first registration.

## `ageMax` (type: `integer`):

Maximum car age in years. 0 = no limit.

## `displacementMin` (type: `number`):

Minimum engine displacement in liters.

## `displacementMax` (type: `number`):

Maximum engine displacement in liters. 0 = no limit.

## `bodyType` (type: `string`):

Body type filter (site pve_2539 codes, verified from the live filter UI).

## `transmission` (type: `string`):

Transmission filter (site pve_11287 codes, verified).

## `colors` (type: `array`):

Exterior color filter (site pve_4917 codes, verified). One of: black, white, red, gray, blue, yellow, brown, green, purple, pink, other. Leave empty for all colors. Multiple colors are OR-combined (black + white = both).

## `refundable` (type: `boolean`):

Only listings with the 检测保障 (insured inspection) guarantee.

## `videoOnly` (type: `boolean`):

Only listings that include a video.

## `newEnergy` (type: `boolean`):

Only new-energy (electric / hybrid) vehicles.

## `maxPages` (type: `integer`):

How many result pages (~50 listings each) to scrape per search (or per start URL). 0 = all available pages. The site itself caps every search at 70 pages no matter how many cars match. The run also stops earlier when results run out.

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

Stop after pushing this many listings in total. Default 300; 0 = unlimited (maxPages still applies).

## `maxDetails` (type: `integer`):

Enrich this many listings with full detail-page data: detail price cross-check, new-car price, color, full spec tables, VIN (masked), original photo gallery, seller info and the owner's description. 0 = unlimited: every scraped listing is enriched. Each enriched listing is additionally charged as a 'listing-detail' event because it requires an extra detail-page fetch.

## Actor input object example

```json
{
  "city": "bj",
  "startUrls": [],
  "brand": "",
  "model": "",
  "priceMin": 0,
  "priceMax": 0,
  "mileageMin": 0,
  "mileageMax": 0,
  "ageMin": 0,
  "ageMax": 0,
  "displacementMin": 0,
  "displacementMax": 0,
  "bodyType": "any",
  "transmission": "any",
  "colors": [],
  "refundable": false,
  "videoOnly": false,
  "newEnergy": false,
  "maxPages": 0,
  "maxItems": 300,
  "maxDetails": 0
}
```

# Actor output Schema

## `listings` (type: `string`):

One item per unique Renrenche listing in the default dataset. Always present: id, url, title, decoded price (万 CNY), mileage, registration year, tags, image, post time. Present when the listing was enriched (maxDetails): color, city, new-car price, VIN (masked), spec tables, full photo gallery, seller info, owner description. Rows for invalid input carry error/errorMessage instead.

# 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 = {
    "city": "bj",
    "startUrls": [],
    "brand": "",
    "model": "",
    "bodyType": "any",
    "transmission": "any",
    "refundable": false,
    "videoOnly": false,
    "newEnergy": false,
    "maxPages": 0,
    "maxItems": 300
};

// Run the Actor and wait for it to finish
const run = await client.actor("songd/renrenche-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 = {
    "city": "bj",
    "startUrls": [],
    "brand": "",
    "model": "",
    "bodyType": "any",
    "transmission": "any",
    "refundable": False,
    "videoOnly": False,
    "newEnergy": False,
    "maxPages": 0,
    "maxItems": 300,
}

# Run the Actor and wait for it to finish
run = client.actor("songd/renrenche-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 '{
  "city": "bj",
  "startUrls": [],
  "brand": "",
  "model": "",
  "bodyType": "any",
  "transmission": "any",
  "refundable": false,
  "videoOnly": false,
  "newEnergy": false,
  "maxPages": 0,
  "maxItems": 300
}' |
apify call songd/renrenche-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,songd/renrenche-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/o92frnMmL1X4m1Fe7/builds/geaZqrOkibiC1NB6v/openapi.json
