# Bilibili Video Scraper (`maximedupre/bilibili-video-scraper`) Actor

Find public Bilibili videos by keyword, URL or ID, popular category, or creator. Get titles, descriptions, tags, dates, creator details, engagement counts, media links, and available comments, danmaku, and sentiment in structured data.

- **URL**: https://apify.com/maximedupre/bilibili-video-scraper.md
- **Developed by:** [Maxime Dupré](https://apify.com/maximedupre) (community)
- **Categories:** Social media, Videos, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$9.00 / 1,000 video metadata

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?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

### 🎬 Turn Bilibili video pages into usable data

This Bilibili video scraper is for researchers, content teams, and developers who need public Bilibili data. Find videos by keyword, URL or ID, popular category, or creator UID. Each saved row gives you video identity and metadata, creator details, engagement counts, and available media links, comments, danmaku, and sentiment in a structured dataset.

- Find public videos for a topic with **[Bilibili Video Search](https://apify.com/maximedupre/bilibili-video-scraper/examples/bilibili-video-search)**.
- Check a submitted video's fields with **[Bilibili Video Metadata](https://apify.com/maximedupre/bilibili-video-scraper/examples/bilibili-video-metadata)**.
- Review time-linked audience messages with **[Bilibili Danmaku](https://apify.com/maximedupre/bilibili-video-scraper/examples/bilibili-danmaku)**.
- Export structured fields for a video with **[Bilibili Video Data](https://apify.com/maximedupre/bilibili-video-scraper/examples/bilibili-video-data)**.
- Collect a focused list of public videos with **[Bilibili Videos](https://apify.com/maximedupre/bilibili-video-scraper/examples/bilibili-videos)**.

#### 📦 Bilibili video rows you can use

Each successful match is saved as one video row. A row can include the video's title, description, category, tags, length, thumbnail, publication time, creator details, engagement counts, source-hosted media links, comments, a timeline-spread danmaku sample, and sentiment fields when available. Optional fields are omitted when the source does not provide them.

The Actor reads public Bilibili content. Private, deleted, restricted, or otherwise inaccessible content is outside scope. It does not download, mirror, or permanently store source video or audio files.

#### ▶️ Find and collect Bilibili videos

1. Select one discovery method: `Keyword`, `Video URLs or IDs`, `Popular or trending videos`, or `Creator`.
2. Fill in the fields for that choice. Fields for other choices are ignored.
3. Add keyword sorting, duration or date filters when you need them, and set a result limit if you want a bounded run.
4. Run the Actor and open the default dataset to view the saved rows.

Leave `Maximum items` empty to return all available results until the source is exhausted. This limit applies to Keyword, Popular or trending videos, and Creator. It does not limit submitted Video URLs or IDs. The Actor processes submitted URLs or IDs separately, so one bad item does not stop the others.

#### ⚙️ Input

**Input fields**

| Field | Type | What it does |
| --- | --- | --- |
| `discoveryMethod` | string | Required. Selects keyword search, video URLs or IDs, popular or trending videos, or a creator. |
| `keyword` | string | One keyword for matching public Bilibili videos. Used with Keyword. |
| `sortBy` | string | Orders keyword results by relevance, recency, views, comments, favorites, or danmaku. |
| `durationFilter` | object | Optional length range for keyword results. Leave either bound empty for no limit. |
| `durationFilter.minSeconds` | integer | Minimum video length in seconds. Leave empty for no lower limit. |
| `durationFilter.maxSeconds` | integer | Maximum video length in seconds. Leave empty for no upper limit. |
| `dateRange` | object | Optional publication date range for keyword results. Dates use UTC. |
| `dateRange.startDate` | string | Includes videos published on or after this `YYYY-MM-DD` date. |
| `dateRange.endDate` | string | Includes videos published on or before this `YYYY-MM-DD` date. |
| `videoUrlsOrIds` | array of strings | One or more public Bilibili video URLs or identifiers. Each item is processed separately, so one bad item does not stop the others. |
| `popularCategory` | string | Optional Bilibili category for Popular or trending videos. Leave empty to include all categories. |
| `creatorUid` | string | One numeric Bilibili creator UID for that creator's recent public videos. |
| `newOnly` | boolean | For Keyword and Popular or trending videos, returns only videos not seen in an earlier run with the same monitoring input. Ignored for Video URLs or IDs and Creator. |
| `maxItems` | integer | Optional positive limit for Keyword, Popular or trending videos, and Creator. Leave it empty to return all available results until the source is exhausted. It does not limit submitted Video URLs or IDs. |

Only `discoveryMethod` is required by the schema. Use one keyword per run, numeric digits for `creatorUid`, and whole seconds for duration limits. The date fields use `YYYY-MM-DD` and are read in UTC.

**Input example**

This example is copied from a successful current-beta keyword run.

```json
{
  "discoveryMethod": "keyword",
  "keyword": "Bilibili",
  "sortBy": "relevance",
  "newOnly": false,
  "maxItems": 1
}
```

#### 🧾 Output

**Output fields**

Every output row uses the video shape below. Nested groups and fields are optional unless noted. A missing optional field means that value was not returned for that video.

| Field | Type | What it does |
| --- | --- | --- |
| `videoId` | string | Stable Bilibili identifier for the video. |
| `url` | URI string | Canonical Bilibili page URL for the video. |
| `title` | string | Title shown for the video. |
| `description` | string, optional | Description provided on the Bilibili video page. |
| `category` | string | Bilibili category assigned to the video. |
| `tags` | array of strings, optional | Tags listed for the video. |
| `durationSeconds` | integer | Video duration in whole seconds. |
| `thumbnailUrl` | URI string | Source URL for the video thumbnail. |
| `publishedAt` | ISO 8601 date-time string | Time when the video was published. |
| `creator` | object | Creator information shown for the video. |
| `creator.uid` | integer | Numeric Bilibili UID of the creator. |
| `creator.name` | string | Creator name shown for the video. |
| `creator.avatarUrl` | URI string, optional | Source URL for the creator avatar. |
| `metrics` | object, optional | Engagement counts reported for the video. |
| `metrics.views` | integer, optional | Number of views reported by Bilibili. |
| `metrics.likes` | integer, optional | Number of likes reported by Bilibili. |
| `metrics.coins` | integer, optional | Number of coins reported by Bilibili. |
| `metrics.favorites` | integer, optional | Number of favorites reported by Bilibili. |
| `metrics.shares` | integer, optional | Number of shares reported by Bilibili. |
| `metrics.comments` | integer, optional | Number of comments reported for the video. |
| `metrics.danmaku` | integer, optional | Number of danmaku messages reported for the video. |
| `media` | object, optional | Source-hosted media links and available stream choices. |
| `media.videoUrl` | URI string, optional | Direct source URL for a video stream, when available. |
| `media.audioUrl` | URI string, optional | Direct source URL for an audio stream, when available. |
| `media.streams` | array of objects, optional | Available source-hosted video or audio stream choices. |
| `media.streams[].url` | URI string | Direct source URL for the stream. |
| `media.streams[].mediaType` | string | Kind of media. The value is `video` or `audio`. |
| `media.streams[].quality` | string | Quality label reported for the stream. |
| `media.streams[].width` | integer, optional | Video width in pixels, when reported. |
| `media.streams[].height` | integer, optional | Video height in pixels, when reported. |
| `media.streams[].frameRate` | number, optional | Video frame rate in frames per second, when reported. |
| `media.streams[].bitrateKbps` | integer, optional | Stream bitrate in kilobits per second, when reported. |
| `media.streams[].codec` | string, optional | Codec reported for the stream. |
| `media.streams[].container` | string, optional | Container format reported for the stream. |
| `comments` | array of objects, optional | Comments returned for the video, with optional reply and sentiment data. |
| `comments[].commentId` | string | Stable Bilibili identifier for the comment. |
| `comments[].text` | string | Text written in the comment. |
| `comments[].author` | object | Author information shown for the comment. |
| `comments[].author.uid` | integer | Numeric Bilibili UID of the comment author. |
| `comments[].author.name` | string | Name shown for the comment author. |
| `comments[].author.avatarUrl` | URI string, optional | Source URL for the comment author's avatar. |
| `comments[].likes` | integer, optional | Number of likes reported for the comment. |
| `comments[].replyCount` | integer, optional | Number of replies reported for the comment. |
| `comments[].parentCommentId` | string, optional | Parent comment identifier when the comment is a reply. |
| `comments[].sentiment` | object, optional | Sentiment fields for the comment text. |
| `comments[].sentiment.polarity` | string | `positive`, `neutral`, or `negative` sentiment polarity. |
| `comments[].sentiment.score` | number | Signed sentiment score from -1 to 1. |
| `danmaku` | object, optional | A timeline-spread sample of danmaku text and reactions. |
| `danmaku.sample` | array of objects | Representative danmaku messages spread across the video timeline. |
| `danmaku.sample[].timeSeconds` | number | Time in the video when the message appears. |
| `danmaku.sample[].text` | string | Text shown in the danmaku message. |
| `danmaku.sample[].likes` | integer, optional | Number of reactions reported for the danmaku message. |
| `sentiment` | object, optional | Sentiment fields for the video's title and description. |
| `sentiment.polarity` | string | `positive`, `neutral`, or `negative` sentiment polarity. |
| `sentiment.score` | number | Signed sentiment score from -1 to 1. |

**Example row from the current beta build**

The row below comes from a successful current-beta Creator run. It is shortened. The source media URLs, remaining stream choices, and remaining comments use the JSON string `"..."` as an omission marker. The other shown values are copied from the real row.

```json
{
  "videoId": "BV1p4th6PExX",
  "url": "https://www.bilibili.com/video/BV1p4th6PExX",
  "title": "9月单机游戏杀疯了🔥大作扎堆！千万别错过！【9月游戏推荐】",
  "description": "大家如果有比较犹豫要不要购入的游戏可以来C酱小肉包直播间：live.bilibili.com/213 看看让我帮你排雷~\n文案：傲慢的小肉包\n配音：傲慢的小肉包\n后期：菜菜\n出镜：傲慢的小肉包\n感谢关注~嗷！",
  "category": "单机游戏",
  "tags": [
    "金刚狼",
    "寂静岭",
    "空之轨迹",
    "单机游戏",
    "鬼武者剑之道",
    "黎明行者之血",
    "火焰纹章千丝万缕",
    "C酱",
    "PS5",
    "游戏推荐"
  ],
  "durationSeconds": 620,
  "thumbnailUrl": "http://i0.hdslb.com/bfs/archive/08b7e8edc4c797dd08f0d291ddc20d57faad9109.jpg",
  "publishedAt": "2026-09-01T09:10:00.000Z",
  "creator": {
    "uid": 67141,
    "name": "傲慢的小肉包",
    "avatarUrl": "https://i1.hdslb.com/bfs/face/361274190d08a36ed12c58b55dd4063cde3391eb.jpg"
  },
  "metrics": {
    "views": 154816,
    "likes": 9135,
    "coins": 3055,
    "favorites": 1356,
    "shares": 553,
    "comments": 382,
    "danmaku": 647
  },
  "media": {
    "videoUrl": "...",
    "audioUrl": "...",
    "streams": [
      {
        "url": "...",
        "mediaType": "video",
        "quality": "32",
        "width": 852,
        "height": 480,
        "frameRate": 30,
        "bitrateKbps": 655,
        "codec": "avc1.64001F",
        "container": "mp4"
      },
      "..."
    ]
  },
  "comments": [
    {
      "commentId": "312724324833",
      "text": "小肉包怎么感觉越活越小了，她真的是宝宝吗[微笑]",
      "author": {
        "uid": 1272995,
        "name": "天火封不住~",
        "avatarUrl": "https://i2.hdslb.com/bfs/face/e801331f5dbfdc2250e36ce06d109beaf2c33033.jpg"
      },
      "sentiment": {
        "polarity": "neutral",
        "score": 0
      },
      "likes": 6,
      "replyCount": 0
    },
    "..."
  ],
  "danmaku": {
    "sample": [
      {
        "timeSeconds": 0.551,
        "text": "ciallo",
        "likes": 0
      },
      {
        "timeSeconds": 212.695,
        "text": "可爱捏",
        "likes": 0
      },
      {
        "timeSeconds": 617.949,
        "text": "可爱可爱",
        "likes": 0
      }
    ]
  },
  "sentiment": {
    "polarity": "neutral",
    "score": 0
  }
}
```

#### 💳 Pricing

This Actor uses pay-per-event pricing. The primary event is `bilibili-video-metadata` at `$0.009` for each successful video metadata row saved to the dataset. The event covers the video fields present in that saved row, including available optional fields. The Apify pricing panel is the source of truth for current charges.

#### 🔌 Integrations

Use the default dataset link in Apify to view and export your rows, or read the dataset through the Apify API. For a related video guide, see:

https://www.youtube.com/watch?v=bNACk1\_S\_6w\&list=PLObrtcm1Kw6MUrlLNDbK9QRg8VDJg0gOW\&index=4

#### ❓ FAQ

##### What happens if one submitted URL or ID is invalid?

Each submitted URL or ID is processed separately. One bad item does not stop the other submitted items.

##### Can I leave Maximum items empty?

Yes. For Keyword, Popular or trending videos, and Creator, leaving it empty returns all available results until the source is exhausted. It does not limit submitted Video URLs or IDs.

##### How does New-only monitoring work?

On recurring Keyword or Popular or trending runs, it returns videos not seen in an earlier run with the same monitoring input. It is ignored for Video URLs or IDs and Creator.

##### Do the duration and date filters apply to every discovery method?

No. The duration and publication date filters apply to Keyword results. Duration uses seconds. Dates use `YYYY-MM-DD` and UTC.

##### Does this Actor download or permanently store Bilibili media?

No. It returns source-hosted video or audio links when available. It does not download, mirror, or permanently store the source media.

##### Do I need a Bilibili login, cookies, or API key?

No buyer login, cookies, or source API keys are needed for public Bilibili content. Private or inaccessible content is outside scope.

##### Why might a field be missing from a video row?

Some fields are optional because Bilibili may not provide them for every public video. The row keeps the fields that are available.

##### What does each video row contain?

Every row has video identity, title, category, duration, thumbnail, publication time, and creator details. It can also include the description, tags, engagement counts, media links, comments, danmaku samples, and sentiment fields.

### 📝 Changelog

**v0.0** (03-09-2026)

- Initial release.

### 🆘 Support

For issues, questions, or feature requests, [file a ticket](https://console.apify.com/actors/maximedupre~bilibili-video-scraper/issues) and I'll fix or implement it in less than 24h 🫡

### 🔗 Related Actors

- [YouTube Trending Videos Scraper](https://apify.com/maximedupre/youtube-trending-videos-scraper): Compare Bilibili popular videos with ranked regional YouTube category pages.
- [YouTube Channel Scraper](https://apify.com/maximedupre/youtube-channel-scraper): Track public creator channels and recent videos on YouTube.
- [YouTube Tags Extractor](https://apify.com/maximedupre/youtube-tags-extractor): Audit public YouTube video tags alongside Bilibili titles and tags.
- [Bilibili Scraper — Videos, Danmaku, Comments & Creator Search](https://apify.com/zhorex/bilibili-scraper): Compare another public Bilibili workflow for video, danmaku, comments, and creator search.
- [Bilibili Video Scraper](https://apify.com/resourceful_mandate/bilibili-video-scraper): Try another focused Bilibili workflow for video metadata and search.

**Made with ❤️ by Maxime Dupré**

# Actor input Schema

## `discoveryMethod` (type: `string`):

Choose keyword search, video URLs or IDs, popular or trending videos, or a creator.

## `keyword` (type: `string`):

Enter one keyword to find matching public Bilibili videos. Use one keyword in each run.

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

Choose how keyword results are ordered.

## `durationFilter` (type: `object`):

Optionally set a video length range in seconds. Leave the minimum or maximum blank to set no limit.

## `dateRange` (type: `object`):

Optionally filter by publication date. Use YYYY-MM-DD. Dates are read in UTC.

## `videoUrlsOrIds` (type: `array`):

Enter one or more public Bilibili video URLs or identifiers. Each item is processed separately, so one bad item does not stop the others.

## `popularCategory` (type: `string`):

Optionally keep popular or trending videos from one Bilibili category. Leave blank to include all categories.

## `creatorUid` (type: `string`):

Enter one numeric Bilibili creator ID (UID) to find that creator's recent public videos.

## `newOnly` (type: `boolean`):

Use this for recurring runs. In Keyword and Popular or trending videos, it returns only videos not seen in an earlier run with the same monitoring input. It is ignored for Video URLs or IDs and Creator.

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

Optional positive limit for Keyword, Popular or trending videos, and Creator. Leave it empty to return all available results until the source is exhausted. This does not limit submitted Video URLs or IDs.

## Actor input object example

```json
{
  "discoveryMethod": "keyword",
  "keyword": "Bilibili",
  "sortBy": "relevance",
  "newOnly": false,
  "maxItems": 1
}
```

# Actor output Schema

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

Open the video results in the default dataset.

# 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 = {
    "discoveryMethod": "keyword",
    "keyword": "Bilibili",
    "maxItems": 1
};

// Run the Actor and wait for it to finish
const run = await client.actor("maximedupre/bilibili-video-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 = {
    "discoveryMethod": "keyword",
    "keyword": "Bilibili",
    "maxItems": 1,
}

# Run the Actor and wait for it to finish
run = client.actor("maximedupre/bilibili-video-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 '{
  "discoveryMethod": "keyword",
  "keyword": "Bilibili",
  "maxItems": 1
}' |
apify call maximedupre/bilibili-video-scraper --silent --output-dataset

```

## MCP server setup

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