# Douban (豆瓣) Movie & TV Trending Scraper (`foxlabs/douban-trending-scraper`) Actor

Discover trending and top-rated movies & TV on Douban (豆瓣) with their ratings — no login, no account, no cookies, no API key.

- **URL**: https://apify.com/foxlabs/douban-trending-scraper.md
- **Developed by:** [Berkan Kaplan](https://apify.com/foxlabs) (community)
- **Categories:** Social media, Marketing
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.50 / 1,000 discovered titles

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

## Douban (豆瓣) Movie & TV Scraper — Ratings, Reviews, Comments & Hot Lists

Scrape **Douban (豆瓣)** — China's most trusted movie & TV community — into clean datasets: **trending & top-rated lists, full detail (cast, crew, IMDb id, synopsis), Douban ratings, long-form reviews, and short comments with location** — all with **no login, no account, no cookies and no API key**.

### 🔥 What is it — and when should you use it?

Douban is China's IMDb + Letterboxd: the authoritative source for 豆瓣评分 (Douban ratings) on films and shows. This Actor gives you four things in one, keyless:

1. **Trending / top-rated discovery** — 18 curated movie & TV lists (hot, newest, top-rated, hidden gems, by region & type).
2. **Full title detail** — rating & vote count, directors, full cast, genres, countries, languages, runtime, **IMDb id**, alternate titles, synopsis.
3. **Long-form reviews** — author, title, rating, date, snippet, review URL.
4. **Short comments with location** — author, rating, date, **province/location**, useful votes, text.

Point it at trending lists, at specific Douban subject IDs/URLs, or turn on **Enrich trending** to do everything in one zero-config run. Use it for film/TV research, recommendation engines, sentiment & audience analysis, and market tracking.

### 🤖 Use with AI agents

**Pay-per-event** and agent-friendly: run with zero input, or pass subject IDs. Each result row is one clean record tagged with its `resultType`. Point any MCP-enabled assistant (Claude, ChatGPT, Cursor) at it on the Apify MCP server, or call the Apify API. You pay per delivered result; empty runs are free.

### 📋 Overview

| | |
|---|---|
| **Source** | movie.douban.com (discovery JSON + detail/review/comment pages) |
| **Auth** | None — no login, cookie, account or API key |
| **Method** | Pure HTTP over a rotating Apify proxy exit; anti-bot proof-of-work solved in-process (no browser) |
| **Output** | `hot`, `detail`, `review`, `comment` rows |
| **Billing** | Pay per delivered result (per type) |

### ✨ Features

- 🔓 **Keyless** — no login, no account, no cookies. The Douban "sec" anti-bot proof-of-work is solved in-process; no browser, no CAPTCHA service.
- 🎯 **Zero-config** — run empty for all trending lists; add `enrichTrending` for full detail + reviews + comments on everything discovered.
- ⭐ **Trusted ratings** — the 豆瓣评分 and vote count on every rated title.
- 🎬 **Rich detail** — directors, full cast, genres, countries, languages, runtime, **IMDb cross-id**, aka titles, synopsis.
- 💬 **Reviews & comments** — long-form reviews and short comments **with province/location**.
- 🧱 **Reliable** — a sticky exit holds anti-bot clearance (one proof-of-work unlocks many pages); blocked exits rotate.
- 🧭 **Honest scope** — every field is `null` when Douban did not carry it; never a fake value.

### 🎬 Quick Start

Trending + full enrichment (everything), zero-config:

```json
{ "categories": ["movie_hot", "movie_top"], "enrichTrending": true, "scrapeComments": true }
```

Deep-scrape specific titles:

```json
{ "subjectIds": ["1292052", "https://movie.douban.com/subject/37516455/"], "scrapeReviews": true, "scrapeComments": true }
```

Just the trending lists (cheapest):

```json
{ "categories": ["movie_hot", "tv_hot"], "maxResults": 500 }
```

### 📥 Input

| Field | Type | Description |
|---|---|---|
| `categories` | array | Trending lists (movie 9 + TV 9). Empty + no IDs = all. |
| `sort` | string | `recommend`, `time`, `rank`. |
| `maxResults` | integer | Cap on trending titles. Default `500`. |
| `subjectIds` | array | Douban subject IDs or URLs to deep-scrape. |
| `enrichTrending` | boolean | Deep-scrape every discovered trending title. Default `false`. |
| `scrapeDetail` | boolean | Fetch full detail per deep-scrape subject. Default `true`. |
| `scrapeReviews` | boolean | Fetch long-form reviews. Default `false`. |
| `scrapeComments` | boolean | Fetch short comments with location. Default `false`. |
| `maxReviewsPerTitle` / `maxCommentsPerTitle` | integer | Per-title caps. |
| `maxSubjects` | integer | Cap on deep-scraped subjects per run. Default `200`. |
| `proxyConfiguration` | object | Apify Proxy; switch to residential if exits are blocked. |

### 📤 Output

Each row carries a `resultType`. Examples:

**`detail`**

```json
{
  "resultType": "detail", "id": "1292052", "type": "movie",
  "url": "https://movie.douban.com/subject/1292052/",
  "title": "肖申克的救赎 The Shawshank Redemption",
  "ratingScore": 9.7, "ratingVotes": 3353472,
  "directors": ["弗兰克·德拉邦特 Frank Darabont"],
  "actors": ["蒂姆·罗宾斯 Tim Robbins", "摩根·弗里曼 Morgan Freeman"],
  "genres": ["剧情", "犯罪"], "countries": ["美国"], "languages": ["英语"],
  "releaseDates": ["1994-09-10(多伦多电影节)", "1994-10-14(美国)"],
  "runtimeMinutes": 142, "imdbId": "tt0111161",
  "aka": ["月黑高飞(港)", "刺激1995(台)"],
  "cover": "https://img.../p.jpg", "datePublished": "1994-09-10",
  "synopsis": "一场谋杀案使银行家安迪…", "scrapedAt": "2026-10-28T..."
}
```

**`comment`**

```json
{ "resultType": "comment", "subjectId": "37516455", "commentId": "32514679",
  "author": "如小果", "ratingStars": 5, "ratingText": "力荐",
  "time": "2024-02-27 21:43:23", "location": "北京", "votes": 265, "text": "…" }
```

**`review`**

```json
{ "resultType": "review", "subjectId": "1292052", "reviewId": "1000369",
  "url": "https://movie.douban.com/review/1000369/", "author": "大头绿豆",
  "title": "十年·肖申克的救赎", "ratingStars": 5, "time": "2005-05-12", "snippet": "…" }
```

**`hot`** (trending list item): `id`, `type`, `category`, `tag`, `rank`, `title`, `ratingScore`, `cover`, `url`, `isNew`.

Download as JSON, CSV, Excel or HTML.

### 🧠 How it works

Trending lists come from Douban's public `search_subjects` JSON. Detail / review / comment pages are guarded by Douban's "sec" anti-bot: a request without clearance gets a page carrying a sha512 proof-of-work. The Actor solves that proof-of-work in-process (pure Node, ~20 ms), submits it for a clearance cookie, and then fetches pages normally — one solve unlocks many pages on the same sticky exit. No browser, no CAPTCHA service.

### 🧪 Data quality — measured (2026-10-28)

- **Trending:** a 1,000-title sweep returned 1,000/1,000 unique, every field 100% filled, every title rated (median ≈ 8.1).
- **Detail:** on real titles, rating, votes, directors, full cast, genres, countries, languages, runtime, IMDb id, aka and synopsis all parse (verified against live pages).
- **Comments:** author, rating, time, votes and text 100%; **location fills on current titles** (older pre-location comments are honest `null`).
- **Reviews:** author, title, rating, date, snippet and URL 100%.
- **Anti-bot:** two subjects + five pages needed only **one** proof-of-work solve (clearance amortized).

### 💼 Use cases

- **Film/TV research** — ratings, cast/crew, IMDb cross-ids across trending and specific titles.
- **Recommendation engines** — rated discovery lists + full metadata.
- **Audience & sentiment** — comments with location and long-form reviews.
- **Market tracking** — watch a genre/region's momentum and reception over time.

### 🔗 Integration

Schedule it, connect to Make / Zapier / n8n, or call the Apify API. Each run's per-type counts are written to the `SOURCE_REPORT` key-value record.

### 📊 Pricing

**Pay per delivered result**, by type (trending title, detail, review, comment). Empty runs are free. See the pricing panel for current rates.

### ❓ FAQ

- **Does it need my Douban login or cookies?** No. It never logs in and never asks you for an account, cookie or proxy of your own.
- **How does it get past Douban's anti-bot?** By solving Douban's own proof-of-work in-process — no browser, no third-party CAPTCHA service.
- **Why is a field null?** Douban did not carry it (e.g. an unrated new title, or an old comment with no location). It is never faked.

### 🐛 Troubleshooting

- **A run returned little/nothing:** an exit was rate-limited — rerun (exits rotate) or switch to a residential proxy.
- **Deep scrape slow:** lower `maxCommentsPerTitle` / `maxReviewsPerTitle` or `maxSubjects`.

### 🚧 What it does not do

It reads publicly served pages. It does not log in, does not scrape private lists, and does not fabricate missing fields.

### ⚖️ Is it legal to scrape Douban?

The Actor reads only publicly served, non-personal data (titles, public ratings, public reviews/comments). Use the data in line with Douban's terms and applicable law; do not store personal data without a lawful basis.

### 🤝 Support & contact

Questions or a custom need? Open an issue on the Actor's Issues tab.

### Changelog

See `CHANGELOG.md`.

# Changelog

This Actor's version history is a separate document: https://apify.com/foxlabs/douban-trending-scraper/changelog.md

# Actor input Schema

## `categories` (type: `array`):

Keyless discovery lists to pull (movie/TV + Douban tag). Leave empty (and give no subject IDs) to sweep all. Each delivered title is a `hot` result.

## `sort` (type: `string`):

How Douban orders each discovery list.

## `maxResults` (type: `integer`):

Cap on unique trending (`hot`) titles across the run (deduplicated by subject id).

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

Pages (20 titles each) to walk per trending category.

## `subjectIds` (type: `array`):

Douban subject IDs or movie.douban.com/subject/<id>/ URLs to deep-scrape for full detail, reviews and/or comments. Works on its own (no trending needed).

## `enrichTrending` (type: `boolean`):

After the trending sweep, deep-scrape every discovered title for full detail (cast, crew, IMDb, synopsis) and the reviews/comments you enable below. This is the zero-config 'everything' mode.

## `scrapeDetail` (type: `boolean`):

For each deep-scrape subject, fetch the full detail row (rating & votes, directors, cast, genres, countries, languages, runtime, IMDb id, aka titles, synopsis).

## `scrapeReviews` (type: `boolean`):

For each deep-scrape subject, fetch long-form reviews (author, title, rating, date, snippet, review URL).

## `scrapeComments` (type: `boolean`):

For each deep-scrape subject, fetch short comments (author, rating, date, province/location where shown, votes, text).

## `maxReviewsPerTitle` (type: `integer`):

Cap on long-form reviews per subject.

## `maxCommentsPerTitle` (type: `integer`):

Cap on short comments per subject.

## `maxSubjects` (type: `integer`):

Safety cap on how many subjects are deep-scraped in one run (applies to subjectIds and enrichTrending).

## `maxRunSeconds` (type: `integer`):

Optional soft deadline. 0 means no time limit.

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

Apify Proxy with a fresh exit per request/session. Deep-scrape uses a sticky exit to keep its anti-bot clearance; if an exit is blocked it rotates. Switch to residential only if datacenter exits are blocked.

## Actor input object example

```json
{
  "categories": [
    "movie_hot",
    "movie_top",
    "tv_hot"
  ],
  "sort": "recommend",
  "maxResults": 500,
  "maxPages": 25,
  "subjectIds": [],
  "enrichTrending": false,
  "scrapeDetail": true,
  "scrapeReviews": false,
  "scrapeComments": false,
  "maxReviewsPerTitle": 20,
  "maxCommentsPerTitle": 40,
  "maxSubjects": 200,
  "maxRunSeconds": 0,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `dataset` (type: `string`):

No description

## `sourceReport` (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 = {
    "categories": [
        "movie_hot",
        "movie_top",
        "tv_hot"
    ],
    "maxResults": 500,
    "subjectIds": [],
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("foxlabs/douban-trending-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 = {
    "categories": [
        "movie_hot",
        "movie_top",
        "tv_hot",
    ],
    "maxResults": 500,
    "subjectIds": [],
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("foxlabs/douban-trending-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 '{
  "categories": [
    "movie_hot",
    "movie_top",
    "tv_hot"
  ],
  "maxResults": 500,
  "subjectIds": [],
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call foxlabs/douban-trending-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,foxlabs/douban-trending-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/YNSiBOf3VLjso9bRe/builds/yRY8mbGzPxonVxeRy/openapi.json
