# Bilibili Comments & Danmaku Scraper API, No Login – B站 哔哩哔哩 (`deadc0dex/bilibili-scraper`) Actor

Bilibili scraper API, no login: video comments, replies, danmaku (弹幕), search videos, video details, user profiles, creator videos, followings, popular & hot videos, weekly must-watch, precious, ranking, hot search (热搜), live rooms from B站/哔哩哔哩 as JSON. Lean AI-agent output, dry run. $0.005/video.

- **URL**: https://apify.com/deadc0dex/bilibili-scraper.md
- **Developed by:** [AsiaData](https://apify.com/deadc0dex) (community)
- **Categories:** Videos, Social media, AI
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

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

## Bilibili Comments & Danmaku Scraper API, No Login – B站 哔哩哔哩

**Bilibili scraper and API for Bilibili comments, danmaku (弹幕 bullet comments) and videos, no login, no cookies from you.** One Actor covers all public B站 / 哔哩哔哩 data: video search, video details, comments + reply threads, danmaku, UP主 creator profiles and uploads, related videos, creator search, trending (热门), Weekly Must-Watch (每周必看), All-time Must-Watch (入站必刷), rankings (排行榜), hot search (热搜) and live rooms. Output is flat JSON, one row per item, with a free summary row at the end. You decide what is fetched (`operation`, `include`, filters, limits, `maxCostUsd`, `dryRun`, `deltaKey`) and what comes back (`fields`, `outputMode`); **`outputMode: "lean"` cuts LLM tokens per row by 64–84 % (median 77 %)**. **$0.005 per video, $0.001 per comment, $0.0001 per danmaku.**

### For AI agents (MCP, tool calling, API)

- **MCP tool:** `deadc0dex--bilibili-scraper` (via `https://mcp.apify.com`). API: `POST https://api.apify.com/v2/acts/deadc0dex~bilibili-scraper/run-sync-get-dataset-items`.
- **Every input is optional.** Fill `keywords`, `urls`, `users` or `ids`; `operation` is auto-detected (users → userProfile, urls → videoDetails, keywords → search, nothing → popular). Arrays everywhere: many keywords/videos/creators in one call.
- **Fast:** default calls (10 rows) finish in ~2–3 s on the platform (prefill median ~2 s), 200 search results or 200 comments in ~4–6 s – well inside the 30 s MCP wait.
- **Only what you ask for is fetched:** `fields` also limits the requests. `{"operation":"popular","maxItemsPerInput":50,"fields":["title","views"]}` makes 1 request instead of 51 (no tag lookups), so it is faster and less likely to be rate-limited.
- **Token-efficient:** `"outputMode":"lean"` returns `type` + `id` + a few key fields per row, no nulls, envelope once in the summary row (median 77 % fewer tokens than compact); `"leanFormat":"table"` also puts one TSV block (header once) in the summary row. See [Token-efficient mode](#token-efficient-mode-for-llm-agents).
- **Rows:** every row has `type`, `operation`, `input`, `queryUsed`, `id`, `url`, `fetchedAt`, `rank`, then kind-specific flat fields (always the same keys per kind; `null` when unknown). The **last row is `type: "summary"`** (counts, cost, stop reason, `nextSteps` with ready-to-use inputs). Problems come back as `type: "error"` rows with `errorCode`, `errorMessage`, `suggestedFix`. Error, summary, plan and capabilities rows are **free**.

#### Operations

| operation | input | returns (`type`) | price per row |
|---|---|---|---|
| `search` | `keywords` | video | $0.005 |
| `keywordComments` | `keywords` | research workflow: top `maxVideos` videos per keyword → comment + reply rows → free insights row | $0.005 per video, $0.001 per comment |
| `videoDetails` | `urls` (links, BV, av, b23.tv) | video (stats, tags, parts, owner) | $0.005 |
| `comments` | `urls` | comment (sortBy `hot` or `newest`, paginated) | $0.001 |
| `replies` | `ids` `"BV…:commentId"` | comment (isReply=true) | $0.001 |
| `danmaku` | `urls` (`?p=2` for part 2; `allParts`; `danmakuSource: segments` for a fuller track) | danmaku (text, video second, sent time) | $0.0001 |
| `related` | `urls` | video | $0.005 |
| `userProfile` | `users` (mid, space URL, name) | user (followers, following, likes, videos, verification) | $0.003 |
| `userVideos` | `users` | video (creator uploads, newest first or `sortBy: views`) | $0.005 |
| `searchUsers` | `keywords` | user | $0.003 |
| `followings` | `users` | user (accounts the creator follows, 关注列表: name, verification, `followedAt`; newest 250) | $0.003 |
| `popular` | – | video (热门) | $0.005 |
| `weekly` | – (`weeklyIssue`, 0 = latest) | video (每周必看) | $0.005 |
| `precious` | – | video (入站必刷, ~100 all-time classics) | $0.005 |
| `ranking` | – (`rankingCategory`: id or name, e.g. `gaming`) | video (排行榜) | $0.005 |
| `hotSearch` | – | trend (热搜 term, heat score) | $0.001 |
| `liveRoom` | `users` (mid or live.bilibili.com link) | liveRoom (status, title, online, area) | $0.003 |
| `capabilities` | – | capabilities manifest | free |

Plus the `apify-actor-start` event ($0.00005 per run).

#### include (opt-in enrichments)

`tags` (on by default) · `details` (full stats for search/list rows; 1 batched request per 50 videos in compact/lean mode) · `owner` (ownerFollowers) · `parts` (parts list) · `topComments` (3 hot comments nested in the video row, free) · `comments` (comment rows after each video, `commentsPerItem`, billed) · `replies` (reply rows under each comment, `repliesPerComment`, billed) · `danmaku` (danmaku rows per video, `danmakuPerItem`, billed) · `author` (commenter name/mid/level/IP region, off by default for privacy) · `liveRoom` (live status on creator rows). An enrichment is only fetched when its field is in `fields` (or `fields` is empty).

#### Main fields

- **video:** bvid, aid, cid, title, description, durationSeconds, publishedAt, thumbnailUrl, categoryName, ownerName, ownerMid, ownerFollowers, views, likes, coins, favorites, shares, danmaku, replies, tags, isOriginal, partsCount, parts, recommendReason, weeklyIssue, topComments
- **comment:** videoBvid, commentId, parentId, rootId, isReply, text, likes, replyCount, publishedAt, isPinned, isUpLiked (+ authorName, authorMid, authorLevel, ipLocation with include `author`)
- **danmaku:** videoBvid, cid, part, text, videoSecond, videoTime, sentAt, displayMode, fontSize, color
- **user:** mid, name, sign, level, followers, following, videosCount, likesTotal, isVerified, verificationTitle, avatarUrl, isLive, liveRoomId (+ followingOf, followedAt on `followings` rows)
- **trend:** keyword, heatScore, isCommercial (promoted term), rank · **liveRoom:** roomId, ownerMid, title, liveStatus, online, followers, areaName

`fields: ["title","url","views"]` returns only those (plus `type`). Dates (`publishedAt`, `sentAt`, `liveStartedAt`) are UTC ISO 8601; `*Timestamp` fields are unix seconds. `categoryId` is Bilibili's v1 zone id (same id space as search filters and the app ranking) and `categoryName` its Chinese name. `isOriginal`: true = original (自制), false = repost (转载), null = not declared (common for uploads since 2025). `outputMode: "full"` adds the original API record as `raw`. `operation: "capabilities"` returns the full machine-readable list for free.

#### Control and cost

| input | effect |
|---|---|
| `fields` | return only these fields; enrichment requests for fields you did not ask for (tags, ownerFollowers, topComments, view-only stats) are skipped |
| `maxItemsPerInput` | rows per keyword/URL/creator (default 10; comments 20, danmaku 100, hotSearch 50) |
| `maxItems` | total billable rows per run (default 1000) |
| `maxCostUsd` | stop before charges would exceed this (e.g. `0.05`) |
| `dryRun: true` | free plan row: operation per input, Chinese query used, estimated rows and cost; nothing fetched |
| `dateFrom` / `dateTo` | `YYYY-MM-DD`, ISO, unix or relative `7d` / `24h` (videos, comments, danmaku) |
| `minViews` / `minLikes`, `sortBy`, `durationFilter`, `dedupe` | filters applied before billing; filtered rows are free |
| `outputMode` / `leanFormat` / `maxTextChars` | `compact` (default), `lean` (token-efficient), `full` (+ raw API record); `table` adds one TSV block; cut long text to N chars |
| `deltaKey` | monitoring: only rows not returned by earlier runs with the same key (skipped rows free) |
| `expandQuery` (default true) | English → Chinese: `BYD` → 比亚迪, `Lei Jun` → 雷军, `Black Myth Wukong` → 黑神话悟空 (curated ~900-entry dictionary, deterministic); `queryUsed` shows what was searched |

Typical cost: 10 search results $0.05 · 100 comments $0.10 · 1,000 danmaku $0.10 · 10 creator profiles $0.03 · top 50 hot search terms $0.05.

#### Copy-paste input for every operation

Each line is a complete input (also returned as `exampleInput` per operation by `{"operation":"capabilities"}`):

| operation | example input |
|---|---|
| `search` | `{"operation":"search","keywords":["原神","BYD"],"maxItemsPerInput":10,"outputMode":"lean"}` |
| `keywordComments` | `{"operation":"keywordComments","keywords":["gaming laptop review"],"maxVideos":5,"commentsPerItem":20,"replyDepth":1,"repliesPerComment":2,"sortBy":"views","dateFrom":"180d","maxCostUsd":0.3}` |
| `videoDetails` | `{"operation":"videoDetails","urls":["https://www.bilibili.com/video/BV17x411w7KC"],"include":["owner","topComments"]}` |
| `comments` | `{"operation":"comments","urls":["BV17x411w7KC"],"maxItemsPerInput":50,"sortBy":"newest"}` |
| `replies` | `{"operation":"replies","ids":["BV17x411w7KC:1353715029"],"maxItemsPerInput":20}` |
| `danmaku` | `{"operation":"danmaku","urls":["BV17x411w7KC"],"maxItemsPerInput":500}` |
| `related` | `{"operation":"related","urls":["BV17x411w7KC"],"maxItemsPerInput":20}` |
| `userProfile` | `{"operation":"userProfile","users":["946974","https://space.bilibili.com/2"]}` |
| `userVideos` | `{"operation":"userVideos","users":["946974"],"maxItemsPerInput":50,"dateFrom":"30d"}` |
| `searchUsers` | `{"operation":"searchUsers","keywords":["影视飓风"],"maxItemsPerInput":5}` |
| `followings` | `{"operation":"followings","users":["2"],"maxItemsPerInput":50}` |
| `popular` | `{"operation":"popular","maxItemsPerInput":20,"fields":["title","url","views"]}` |
| `weekly` | `{"operation":"weekly","weeklyIssue":0}` |
| `precious` | `{"operation":"precious","maxItemsPerInput":20}` |
| `ranking` | `{"operation":"ranking","rankingCategory":"gaming","maxItemsPerInput":20}` |
| `hotSearch` | `{"operation":"hotSearch","maxItemsPerInput":50}` |
| `liveRoom` | `{"operation":"liveRoom","users":["https://live.bilibili.com/21452505","946974"]}` |
| `capabilities` | `{"operation":"capabilities"}` |

#### 3 example calls

```json
{"keywords": ["BYD", "Xiaomi SU7"], "maxItemsPerInput": 5, "fields": ["title","url","views","likes","publishedAt","queryUsed"]}
```

```json
{"operation": "comments", "urls": ["https://www.bilibili.com/video/BV17x411w7KC"], "maxItemsPerInput": 50, "sortBy": "newest", "include": ["replies"], "repliesPerComment": 3, "maxCostUsd": 0.2}
```

```json
{"users": ["946974"], "include": ["liveRoom"]}
```

Then e.g. `{"operation":"userVideos","users":["946974"],"dateFrom":"30d"}` – the summary row's `nextSteps` suggests such follow-ups.

#### Error codes (type = error rows, never billed)

| errorCode | meaning | typical fix |
|---|---|---|
| MISSING_INPUT | operation needs keywords/urls/users/ids | add the input shown in `suggestedFix` |
| INVALID_INPUT / INVALID_URL | value not recognised | use a BV id, video URL, mid or `BV…:commentId` |
| NOT_FOUND | deleted, private, region-locked, unknown creator name | check the id; HK residential proxy for region locks |
| NO_RESULTS | nothing returned, or every row filtered out | loosen filters, try the Chinese term |
| BLOCKED | Bilibili risk control after all retries | retry, or `proxyConfiguration` RESIDENTIAL |
| UPSTREAM_ERROR / INTERNAL_ERROR | unexpected Bilibili response / Actor bug | retry / report in Issues |
| NOT_SUPPORTED | needs a Bilibili login | not available here |

Input problems end the run **SUCCEEDED** with error rows; the status message names the code and the fix. Only a run where Bilibili blocked every request ends FAILED.

### Bilibili comment research by keyword (`keywordComments`, new in 2.0)

One call does the whole pipeline: **keyword → top videos → comments + replies → insights**. `{"operation":"keywordComments","keywords":["机械键盘"],"maxVideos":2,"commentsPerItem":5,"repliesPerComment":1}` returned 2 videos + 19 comment rows + 1 free insights row in 3 Bilibili requests (1.7 s locally).

- **Controls:** `maxVideos` (videos per keyword, default 5, max 50), `commentsPerItem` (default 10, max 500), `replyDepth` (0 or 1; Bilibili threads have 2 levels), `repliesPerComment` (default 2 here), `commentSort` (`hot` default, or `newest`), plus the search filters `sortBy`, `dateFrom`/`dateTo`, `minViews`, `durationFilter`, `expandQuery` (English → Chinese) and `maxCostUsd`.
- **`matchTerms`** keeps only top-level comments (and danmaku) containing any term; replies of kept comments stay as thread context. It filters **after** fetching: fewer billed rows, not fewer requests.
- **Rows:** each video row (input = keyword) is followed by its comment rows (`videoBvid`, `videoTitle`); one insights row per keyword and the summary come last. Without keywords but with `urls`, it runs `comments` on those videos with the same settings.
- **Insights row (free, `include: ["insights"]` on any operation, default on here):** top terms (CJK bigrams merged into trigrams when that explains every use, e.g. 评论区; no word segmentation), emotes, `matchTerms` counts, most-liked comments, top videos by views, and a lexicon sentiment count labelled **heuristic** (no LLM; wrong on sarcasm and memes). With danmaku rows: peak minute and a per-video danmaku profile (`timelinePerMinute`, `peakMinute`, `poolFetched` vs `returned`, `uniqueSenders` with `include: ["author"]`). Everything is computed from the rows returned in the run only.

### Trust fields, computed metrics and snapshots (2.0)

- **Every row:** `isPartial` (a requested enrichment failed), `unavailableFields[]`, `collectionWarnings[]`. Null means unknown, 0 means Bilibili said zero. The summary row adds `requested` vs `perInput[].returned`, `pagesFetched`, `stopReason` and `isPartial`.
- **Computed video fields (marked in `capabilities`):** `likesPer1kViews`, `commentsPer1kViews`, `engagementRate` (% of views: likes+coins+favorites+shares+replies+danmaku, unknown counts left out and listed), `danmakuPerMinute`, `detailLevel` (`basic` list row vs `enriched` full record).
- **Snapshots:** `deltaKey` + `trackMetrics: true` → video and creator rows always come back with `viewsDelta`, `likesDelta`, `commentsDelta`, … `followersDelta`, `snapshotAt`, `previousSnapshotAt`, `hoursSincePrevious` vs the previous run with the same key (only compact numbers are stored).

### Token-efficient mode for LLM agents

`"outputMode": "lean"` is built for agents that read the rows into a context window:

- each row keeps `type`, `id` and a curated field set (video: title, ownerName, views, likes, replies, publishedAt, durationSeconds; comment: text, likes, replyCount, publishedAt; danmaku: text, videoSecond, sentAt; user: name, followers, videosCount, likesTotal, verificationTitle; trend: heatScore; liveRoom: title, liveStatus, online, followers, areaName); `fields` still overrides it;
- null, empty and false values are omitted; `operation`, `input`, `queryUsed` and `fetchedAt` appear once in the summary row's `envelope`; `url` is dropped because it follows from `id` (`envelope.urlPatterns`, e.g. `https://www.bilibili.com/video/{id}`);
- text is cut to `maxTextChars` (default 300; cut text ends with … and the row gets `truncated: true`); dates are `YYYY-MM-DDTHH:MMZ` (UTC);
- enrichment requests the lean fields do not need (e.g. tags) are skipped, so lean runs are also faster;
- `"leanFormat": "table"` additionally writes all rows as TSV (one block per row kind, header line once) into the summary row (`leanTable`, if under 20 KB) and key-value record `LEAN_TABLE`. Rows are still returned and billed exactly the same.

Measured on real runs (tiktoken cl100k_base, tokens per row, 2026-10-13):

| row kind | compact | lean | lean table |
|---|---|---|---|
| video (search) | 441 | 103 (−77 %) | 80 (−82 %) |
| video (creator uploads) | 526 | 86 (−84 %) | 62 (−88 %) |
| comment | 238 | 86 (−64 %) | 69 (−71 %) |
| danmaku | 198 | 56 (−72 %) | 39 (−80 %) |
| creator profile | 252 | 66 (−74 %) | 51 (−80 %) |
| hot search term | 184 | 29 (−84 %) | 18 (−90 %) |

```json
{"keywords": ["BYD"], "maxItemsPerInput": 20, "outputMode": "lean"}
{"operation": "comments", "urls": ["BV17x411w7KC"], "maxItemsPerInput": 100, "leanFormat": "table"}
```

### Bilibili video comments and replies (B站评论)

`{"operation":"comments","urls":["BV17x411w7KC"],"maxItemsPerInput":200}` returns the full, paginated public comment list of each video (hot or newest first, 30 per request), with likes, reply count, pinned and uploader-liked flags. Add `include: ["replies"]` for reply threads, or `{"operation":"replies","ids":["BV17x411w7KC:<commentId>"]}` for one thread. Commenter names, mid and level only with include `author`. $0.001 per comment or reply.

### Bilibili danmaku (B站弹幕, bullet comments)

`{"operation":"danmaku","urls":["https://www.bilibili.com/video/BV17x411w7KC?p=2"],"maxItemsPerInput":500}` returns the public bullet-comment pool of a video part: text, the video second it appears at (`videoSecond`, `videoTime`), send time, display mode, colour. When you ask for fewer rows than exist they are sampled evenly across the timeline. `"allParts": true` reads every part of a multi-part video; `"danmakuSource": "segments"` adds Bilibili's 6-minute protobuf segments to the XML pool (deduplicated) for a much fuller track on busy videos (e.g. 2,943 instead of 1,200 rows on a 3-minute part). $0.0001 per danmaku.

### Bilibili search videos (keyword video search)

`{"operation":"search","keywords":["原神"]}`: sort by relevance, views, newest, danmaku, favorites or comments; `dateFrom`/`dateTo`, `durationFilter`, `minViews`. English names are searched in Chinese automatically (`BYD` → 比亚迪). $0.005 per video.

### Bilibili video details and video stats

`{"urls":["BV17x411w7KC"]}` for any list of video links, BV / av ids or b23.tv short links. Rows carry views, likes, coins, favorites, shares, danmaku count, comment count, tags, parts, resolution and original-vs-repost. On search and list operations, `include: ["details"]` adds the same stats (one batch request per 50 videos). $0.005 per video.

### Bilibili related videos

`{"operation":"related","urls":["BV17x411w7KC"]}`: the up to 40 videos Bilibili recommends next to a video, with full stats. $0.005 per video.

### Bilibili user profile (UP主 creator profile)

`{"operation":"userProfile","users":["946974"]}`: followers, following, total likes, video count, article count, level, verification and live room. Creators can be given as mid, `mid:946974`, space.bilibili.com link or exact name. $0.003 per profile.

### Bilibili creator videos (user uploads)

`{"operation":"userVideos","users":["946974"],"maxItemsPerInput":200}`: a creator's uploads, newest first or most viewed with `sortBy: views`, full stats, up to 100 per request. $0.005 per video.

### Bilibili followings (following list, 关注列表)

`{"operation":"followings","users":["2"]}`: the accounts a creator follows, with name, verification and the date they were followed (`followedAt`). Bilibili shows logged-out visitors the newest 250; creators who hide the list return a NO_RESULTS row. Follower (fan) lists need a login and are not available. $0.003 per account.

### Bilibili search users (find UP主 creators)

`{"operation":"searchUsers","keywords":["Lei Jun"]}`: creators matching a keyword, with follower and video counts. $0.003 per creator.

### Bilibili popular videos (热门 trending videos)

`{"operation":"popular","maxItemsPerInput":50}`: the current Popular feed, up to 50 videos per request. $0.005 per video.

### Bilibili weekly must-watch (每周必看) and precious all-time must-watch (入站必刷)

`{"operation":"weekly"}` (`weeklyIssue` 0 = latest issue) and `{"operation":"precious"}` (~100 all-time classics), both with full stats. $0.005 per video.

### Bilibili ranking (排行榜, category top 100)

`{"operation":"ranking","rankingCategory":"gaming"}`: category Top-100; `rankingCategory` as id or name: all, film, entertainment, music, dance, animation, kichiku, gaming, knowledge, tech, cars, fashion, sports, food, animals. $0.005 per video.

### Bilibili hot search (B站热搜, trending search terms)

`{"operation":"hotSearch"}`: top 50 trending search terms with heat score and `isCommercial` for promoted terms. $0.001 per term.

### Bilibili live rooms

`{"operation":"liveRoom","users":["https://live.bilibili.com/21452505","946974"]}`: live status, title, online count, area, followers, start time. $0.003 per room.

### Monitoring: only new rows (`deltaKey`)

Give a run a name, e.g. `{"operation":"userVideos","users":["946974"],"deltaKey":"ysjf-uploads"}`, and schedule it: every later run with the same `deltaKey` returns only videos, comments, danmaku, creators or trends it has not returned before. Already-seen rows are skipped and not billed. The state lives in the named key-value store `bilibili-scraper-delta` of your own Apify account.

### Input examples

```json
{"keywords": ["原神"]}
{"urls": ["BV17x411w7KC", "https://b23.tv/xxxx"], "include": ["owner", "topComments", "parts"]}
{"operation": "danmaku", "urls": ["https://www.bilibili.com/video/BV17x411w7KC?p=2"], "maxItemsPerInput": 500}
{"operation": "ranking", "rankingCategory": "1012", "maxItemsPerInput": 20}
{"operation": "hotSearch"}
{"keywords": ["黑神话悟空"], "include": ["comments", "danmaku"], "commentsPerItem": 20, "danmakuPerItem": 50, "dryRun": true}
```

Older inputs keep working: `mode`, `searchKeywords`, `videoUrls`, `searchOrder`, `searchDuration`, `fetchDetails`, `includeComments`, `includeTags`, `maxCommentsPerVideo`, `includeCommentAuthor`. `maxItems` without `maxItemsPerInput` still means "per keyword" as in v0.x.

### Output example (compact)

```json
{"type":"video","operation":"search","input":"BYD","queryUsed":"比亚迪","id":"BV1eKpR6TEPQ","url":"https://www.bilibili.com/video/BV1eKpR6TEPQ","fetchedAt":"2026-10-12T17:40:00.000Z","rank":2,"bvid":"BV1eKpR6TEPQ","title":"升级成筷子悬架！比亚迪大海鸥会卖多少钱呢？","ownerName":"…","views":120345,"likes":3456,"danmaku":210,"replies":512,"durationSeconds":798,"publishedAt":"2026-10-12T08:43:16.000Z","tags":["比亚迪","汽车"]}
{"type":"summary","operation":"search","counts":{"video":5},"billedEvents":{"result":5},"chargedUsd":0.025,"stopReason":null,"nextSteps":["Comments: {\"operation\":\"comments\",\"urls\":[\"BV1QbHm65EaB\"]}"]}
```

### Pricing (pay per event)

| event | price | charged for |
|---|---|---|
| `result` | $0.005 | each video row |
| `comment` | $0.001 | each comment or reply row |
| `danmaku` | $0.0001 | each danmaku row |
| `profile` | $0.003 | each creator profile or live room row |
| `trend` | $0.001 | each hot search term row |
| `apify-actor-start` | $0.00005 | once per run |

Error, summary, plan and capabilities rows, nested top comments, tags and filtered-out rows are free. `maxCostUsd` and the platform's max cost per run are both respected.

### Limits and notes

- Public, logged-out data only. **Not available without a login (re-checked 2026-10-13):** subtitles / AI summaries (Bilibili answers `need_login_subtitle: true` and an empty subtitle list), follower (fan) lists (`-352` / `-101` on every public route), the IP region of commenters (`ipLocation` stays null: Bilibili omits it for guests) and the full danmaku history. The list of accounts a creator *follows* is available (`followings`, newest 250).
- Danmaku come from Bilibili's public pool for each part, which Bilibili caps (the `maxlimit`, e.g. 1,000 for a short video). `danmakuSource: segments` adds the 6-minute segment pools and returns several times more, but not the complete history of very busy videos.
- `weekly` uses the app's weekly list plus the issue's public media list (the web endpoint is risk-controlled for guests); `ranking` falls back to the app ranking when the web ranking is blocked; since v1.3 coins, shares, description, width, height and partsCount of those rows are filled from a public batch video-info call (2 requests per 100 rows), and the summary says so.
- `heatScore` (hot search) is Bilibili's own number and has no second public source; `likesTotal` comes only from the creator card; `videosCount` is the card's archive count (can differ slightly from the space page).
- Region-locked or deleted videos return NOT_FOUND; set `proxyConfiguration` to a RESIDENTIAL group with country HK for region locks.
- `outputMode: "full"` rows carry Bilibili's raw record; for videos in a collection it includes the whole collection list (`ugc_season`), up to several MB per row. Compact or lean output is much smaller and faster.
- Requests go direct first (fastest, up to 16 in parallel) and slow down and switch to Apify Proxy automatically on blocks. Default run memory is 256 MB.
- Commenter and danmaku sender identities are omitted unless you add include `author`; use the data in line with Bilibili's terms and data-protection law.

### FAQ

**Is scraping Bilibili legal?** This Actor reads only public, logged-out pages and API answers, the same data any visitor sees. It is unofficial and not affiliated with Bilibili. Personal data (commenter identities) is off by default; use the data in line with Bilibili's terms and data-protection law.
**Do I need a Bilibili account or cookies?** No.
**How many comments per video can I get?** All public top-level comments (paginated, `maxItemsPerInput` up to 5,000) plus reply threads with include `replies`.
**Can I get danmaku with timestamps?** Yes: every danmaku row has the video second it appears at and the time it was sent.
**Can I search in English?** Yes: brand, company, person, game and topic names are searched in Chinese automatically (see `queryUsed`); set `expandQuery: false` to search the literal text.
**How do I get comments for many videos at once?** `{"operation":"comments","urls":[…]}` or add `include: ["comments"]` to a search.
**How do I know the cost before running?** Add `"dryRun": true` (free).

Changelog: see the Actor's CHANGELOG. Issues and feature requests: the Issues tab.

# Changelog

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

# Actor input Schema

## `operation` (type: `string`):

auto (default) picks from inputs: users→userProfile, urls→videoDetails, keywords→search, nothing→popular. search, searchUsers: keywords. keywordComments (alias keyword_comments): research workflow keyword→top maxVideos videos→comments+replies→free insights row. videoDetails, comments, danmaku, related: urls. replies: ids "BV…:commentId". userProfile, userVideos, followings, liveRoom: users. No input: popular, weekly, precious, ranking, hotSearch (热搜). capabilities = free manifest.

## `keywords` (type: `array`):

Search terms, one per item, Chinese or English (原神, 黑神话悟空, BYD, iPhone 16). Used by search (videos) and searchUsers (creators). English brand/person/topic names are also searched in Chinese (BYD→比亚迪) unless expandQuery is false; rows show queryUsed. A video/creator link put here is routed to the right operation.

## `urls` (type: `array`):

Videos, one per item: https://www.bilibili.com/video/BV17x411w7KC (also m.bilibili.com, ?p=2 for part 2), bare BV ids, av ids (av170001), b23.tv links. Used by videoDetails (default when filled), comments, danmaku and related. Bad ids return an error row (not billed).

## `users` (type: `array`):

Creators, one per item: numeric mid (946974), "mid:946974", https://space.bilibili.com/946974, or an exact creator name (影视飓风, resolved via search). Live rooms: https://live.bilibili.com/173551. Used by userProfile (default when filled), userVideos, followings and liveRoom.

## `ids` (type: `array`):

Any mix of ids, auto-routed by shape: "BV17x411w7KC:1353715029" (video:commentId) → replies; BV/av ids → videos; "mid:946974" or space links → creators; live links → liveRoom. Bare numbers are treated as av ids; prefix creators with mid:.

## `maxItemsPerInput` (type: `integer`):

Rows per keyword / URL / creator (per feed for popular, weekly, ranking, hotSearch). Default by operation: 10 (videos, creators), 20 (comments, replies), 100 (danmaku), 50 (hotSearch). Range 1-5000; out-of-range values are clamped.

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

Total billable rows for the whole run, all kinds together (videos + comments + danmaku + …). Default 1000, max 20000. Legacy: if maxItemsPerInput is not set, maxItems is used per input as in v0.x.

## `maxCostUsd` (type: `number`):

Stop before the run's charges would exceed this amount (e.g. 0.05). Rows are priced per kind: video $0.005, comment $0.001, danmaku $0.0001, creator/live room $0.003, hot search term $0.001. Error, summary, plan and capabilities rows are free. The platform "max cost per run" is also respected.

## `include` (type: `array`):

tags: video tags (always on unless includeTags=false). details: full stats for search/list rows. owner: ownerFollowers. parts: parts list. topComments: 3 hot comments nested (free). comments / danmaku: extra rows after each video (commentsPerItem / danmakuPerItem, billed). replies: reply rows under comments. author: commenter name/mid/level/IP region (off for privacy). liveRoom: live status on creator rows. insights: free heuristic insights row (see insights).

## `fields` (type: `array`):

Return only these fields (type is always kept), e.g. \["title","url","views","likes","publishedAt"]. Empty = all fields of each row kind. Video: bvid, title, description, ownerName, ownerMid, views, likes, coins, favorites, shares, danmaku, replies, tags, durationSeconds, publishedAt. Comment: text, likes, replyCount, publishedAt, videoBvid. Fewer fields = fewer requests: e.g. without tags no tag request per video. Full list: operation capabilities.

## `outputMode` (type: `string`):

compact (default): every field of the row kind, null when unknown, descriptions cut to 300 chars. lean: token-efficient for LLM agents: type + id + a few key fields, nulls/empty values omitted, operation/input/fetchedAt stated once in the summary row, text cut to maxTextChars (default 300), dates YYYY-MM-DDTHH:MMZ UTC. fields still overrides. full: complete text plus the raw Bilibili API record.

## `maxVideos` (type: `integer`):

keywordComments only: how many top videos per keyword get their comments read (after sortBy, dateFrom/dateTo and minViews filters). Default 5, max 50. Other operations use maxItemsPerInput.

## `sortBy` (type: `string`):

search + keywordComments (video order): relevance (default), views (most played), newest, danmaku (most bullet comments), favorites, comments. comments: hot (default) or newest (or use commentSort). userVideos: newest (default) or views. Ignored by feeds.

## `dateFrom` (type: `string`):

Keep only videos / comments / danmaku published on or after this date: YYYY-MM-DD (Beijing time), ISO time, unix seconds, or relative "7d", "24h", "2w". Search passes it to Bilibili; other operations filter before billing (filtered rows are free).

## `dateTo` (type: `string`):

Keep only items published on or before this date. Same formats as dateFrom.

## `minViews` (type: `integer`):

Videos only: drop videos with fewer plays (filtered before billing).

## `minLikes` (type: `integer`):

Videos and comments: drop rows with fewer likes (filtered before billing).

## `matchTerms` (type: `array`):

Optional: keep only top-level comments and danmaku whose text contains any of these terms (case-insensitive, e.g. \["续航","battery"]). Replies under a kept comment are kept as context. Filters AFTER fetching: fewer billed rows, not fewer requests; per video at most 10x the wanted comments (max 3000) are scanned.

## `dryRun` (type: `boolean`):

true: fetch nothing and return one free plan row: operation per input, Chinese query used, estimated rows and estimated cost. Use it to check an input and its price before running.

## `commentsPerItem` (type: `integer`):

Comment rows per video for keywordComments and include \["comments"] (aliases maxCommentsPerItem, maxCommentsPerVideo). Default 10, max 500.

## `replyDepth` (type: `integer`):

0 = top-level comments only, 1 = also replies under each top-level comment (repliesPerComment each). Bilibili threads have 2 levels, so 1 is the maximum. keywordComments default 1; elsewhere include \["replies"] does the same.

## `repliesPerComment` (type: `integer`):

Reply rows under each top-level comment that has replies (with replyDepth 1 or include \["replies"]). Default 5 (keywordComments: 2), max 200. Billed as comment rows.

## `commentSort` (type: `string`):

Order of comment rows (comments, keywordComments, include comments): hot = most liked/replied first (default), newest = newest first. Empty: comments uses newest when sortBy is newest, otherwise hot.

## `insights` (type: `boolean`):

Adds free insights row(s): top terms (CJK bigrams + words), emotes, matchTerms counts, lexicon sentiment labelled heuristic (no LLM), most-liked comments, top videos, danmaku peak minute and a per-video danmaku profile (per-minute timeline, peak minute, pool size, unique senders with include author); comment rows get sentimentHeuristic. Default on for keywordComments, off elsewhere.

## `trackMetrics` (type: `boolean`):

With deltaKey: video and creator rows always come back with viewsDelta, likesDelta, commentsDelta, danmakuDelta, favoritesDelta, coinsDelta, sharesDelta, engagementRateDelta (creators: followersDelta…) and snapshotAt vs the previous run with the same key. Only compact numbers are stored. Default off.

## `deltaKey` (type: `string`):

Monitoring mode: give a name (e.g. byd-daily) and every later run with the same name returns only rows (videos, comments, danmaku, creators, trends) it has not returned before. Already-seen rows are skipped and free. State is kept in the named key-value store bilibili-scraper-delta of your account. Empty = normal run. With trackMetrics, video/creator rows return with deltas instead of being skipped.

## `expandQuery` (type: `boolean`):

On (default): Latin-script keywords are matched against a curated dictionary (~900 brands, companies, people, games, anime, topics) and searched in Chinese first, e.g. BYD→比亚迪, Black Myth Wukong→黑神话悟空; the original keyword fills any shortfall. Deterministic, no machine translation. Rows show queryUsed.

## `leanFormat` (type: `string`):

Only with outputMode lean. rows (default): lean JSON rows. table: also one TSV text block per row kind (header line once, tab-separated) in the summary row (leanTable, if under 20 KB) and in key-value record LEAN_TABLE: the most token-efficient form for an LLM. Rows are still returned and billed the same.

## `danmakuPerItem` (type: `integer`):

With include \["danmaku"]: danmaku rows per video, spread evenly over the video timeline. Default 100, max 5000.

## `durationFilter` (type: `string`):

search only: any (default), short (<10 min), medium (10-30 min), long (30-60 min), verylong (>60 min).

## `rankingCategory` (type: `string`):

ranking only. 0 or all (default), 1001 film (Film & TV), 1002 entertainment, 1003 music, 1004 dance, 1005 animation, 1007 kichiku (remix), 1008 gaming, 1010 knowledge, 1012 tech, 1013 cars, 1014 fashion, 1018 sports, 1020 food, 1024 animals. Numeric id or English name.

## `weeklyIssue` (type: `integer`):

weekly only. Issue number of 每周必看; 0 = latest issue.

## `dedupe` (type: `boolean`):

true (default): a video/comment/creator found by several inputs is returned (and billed) once.

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

Requests go direct first (fastest) and switch to Apify Proxy automatically when Bilibili blocks them. A proxy group (e.g. RESIDENTIAL, country HK for region-locked videos) or your own proxy URLs are used from the first request.

## `maxRequestRetries` (type: `integer`):

Retries with a fresh session/IP on rate-limit or risk-control (-352/412) responses. 0-10.

## `requestDelayMs` (type: `integer`):

Minimum delay between API requests in ms (0-10000). Default 0: up to 8 parallel requests, and the Actor slows itself down to 250 ms automatically after the first rate-limit/risk-control answer.

## `maxTextChars` (type: `integer`):

Cut title, description, comment/danmaku text and creator sign to this many characters (cut text ends with … and lean rows get truncated: true). Default: 300 in lean; compact cuts only descriptions at 300; full is unlimited. Range 20–100000.

## `allParts` (type: `boolean`):

danmaku only. Read every part (P1, P2, …) of multi-part videos instead of the first one (or the ?p= part in the link). maxItemsPerInput is split evenly over the parts.

## `danmakuSource` (type: `string`):

xml (default): the part's newest danmaku pool, 1 request (up to a few thousand rows). segments: the XML pool plus every 6-minute protobuf segment of the part, deduplicated: a fuller track for busy videos (1 extra request per 6 minutes of video).

## Actor input object example

```json
{
  "operation": "auto",
  "keywords": [
    "原神"
  ],
  "outputMode": "compact",
  "dryRun": false,
  "expandQuery": true,
  "durationFilter": "any",
  "rankingCategory": "0",
  "weeklyIssue": 0,
  "dedupe": true,
  "proxyConfiguration": {
    "useApifyProxy": true
  },
  "maxRequestRetries": 4,
  "requestDelayMs": 0,
  "allParts": false
}
```

# Actor output Schema

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

All rows of the run (videos, comments, danmaku, creators, trends, live rooms, error rows, summary).

## `runSummary` (type: `string`):

JSON: counts per kind, billedEvents, chargedUsd, stopReason, isPartial, perInput completeness, pagesFetched, fieldsReturned, warnings, notes, nextSteps, requests.

## `leanTable` (type: `string`):

Only with outputMode lean + leanFormat table: one TSV block per row kind, header once. The most token-efficient form for LLMs.

# 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 = {
    "keywords": [
        "原神"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("deadc0dex/bilibili-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 = {
    "keywords": ["原神"],
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("deadc0dex/bilibili-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 '{
  "keywords": [
    "原神"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call deadc0dex/bilibili-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,deadc0dex/bilibili-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/wfhTEKLdeEra4K6Lp/builds/2b3BXeb1ZiBAj7dkO/openapi.json
