Bilibili (哔哩哔哩) Scraper - Videos, Comments & Replies avatar

Bilibili (哔哩哔哩) Scraper - Videos, Comments & Replies

Pricing

$4.99 / 1,000 results

Go to Apify Store
Bilibili (哔哩哔哩) Scraper - Videos, Comments & Replies

Bilibili (哔哩哔哩) Scraper - Videos, Comments & Replies

Search Bilibili videos by keyword or by link and collect engagement counts, tags and optionally comments with replies.

Pricing

$4.99 / 1,000 results

Rating

0.0

(0)

Developer

Lantern Lab

Lantern Lab

Maintained by Community

Actor stats

0

Bookmarked

1

Total users

1

Monthly active users

8 hours ago

Last modified

Categories

Share

Bilibili Video & Comment Scraper

Search Bilibili (哔哩哔哩) videos by keyword, or hand it video links, and get one row per video with the full engagement counts Bilibili shows on the page: views, likes, coins, favourites, shares, danmaku and comment count, plus the description, tags, duration, publish time, cover and author. Turn comments on and it collects the comments and the replies under them as well. No Bilibili login, no cookies, no account of your own. $4.99 per 1,000 results (a video or a comment row), no start fee. See Pricing.

Input:

{
"keywords": ["美食"],
"maxVideosPerKeyword": 20,
"includeComments": false
}

Output - one row per video (type: "video"); keyword- and video-summary rows are free. Sample from a real run; channel name partially masked, cover link shortened, tags trimmed:

{
"type": "video",
"bvid": "BV1q6nb6cE4P",
"aid": "117488947892299",
"title": "与众09沿海而行,邂逅悠然青岛",
"description": "追风逐浪,与众09载着海风向前 \n纯电静谧,恰与大海的沉静相融…",
"url": "https://www.bilibili.com/video/BV1q6nb6cE4P",
"coverUrl": "http://i1.hdslb.com/bfs/archive/…",
"durationSec": 60,
"publishedAt": "2026-10-23T07:06:35.000Z",
"author": { "mid": "3546679701670263", "name": "大众***" },
"stats": {
"views": 22, "likes": 1, "coins": 0, "favorites": 1,
"shares": 1, "danmaku": 0, "comments": 0
},
"tags": ["#大众安徽", "#大众09大众最美智能纯电轿跑", "…"],
"keyword": "与众09",
"collectedAt": "2026-10-23T08:04:48.468Z",
"partial": false,
"partialReason": null,
"commentsRequested": false,
"commentStatus": "not_requested"
}

Limits:

  • Public data only. Reads what Bilibili shows a signed-out visitor; the Actor never logs in. No danmaku, no IP region on comments (Bilibili does not return it signed out), no downloads.
  • Every keyword gets a summary row saying whether its videos were collected in full, and every video says whether its comments were. A video or keyword that could not be read is marked failed with the reason - never "0 results". Bilibili's own search stops at 1,000 videos per keyword.
  • Your limits stop collection and appear in the row: maxVideosPerKeyword, maxCommentsPerVideo, the maxUpstreamRequests request ceiling and the maximum charge per run (see Pricing).

What it does

  • Searches each keyword and reads the result pages until your limit or the end of what Bilibili returns. Bilibili's own search stops at 1,000 videos per keyword.
  • Reads each video's own detail page, so coins and shares are real numbers rather than blanks - the search results alone do not carry them.
  • Collects comments in the order the video page opens with (hot first), together with the replies under each comment. A comment page already carries up to three replies per comment; the reply endpoint is only called when a comment shows more than came with it.
  • Takes video links, short links (b23.tv), share text copied from the app, BV IDs and av numbers. A line that is none of these stops the run at once - nothing is collected or charged.
  • Compares what it collected with what Bilibili claims: per keyword (results reported vs. collected) and per video (comment count vs. comments collected).

What it does not do

  • No danmaku (the on-screen comments), no channel follower lists, no video or audio downloads, no anything that needs a logged-in account.
  • No IP region on comments. Bilibili does not return it on signed-out reads, so author.ipLocation is null rather than filled in from elsewhere.
  • No multi-part handling: durationSec is the whole video's length, as Bilibili reports it.
  • No scheduling or monitoring built in; use Apify schedules.

Input

FieldDefaultMeaning
keywords-One search term per line.
videoUrls-One video per line: https://www.bilibili.com/video/BV..., https://b23.tv/..., share text from the app, a BV ID such as BV1xx411c7mD, or an av number such as av2. Collected before the keywords.
maxVideosPerKeyword20Videos to collect per keyword (1-1000).
sortrelevanceSearch order: relevance, newest, mostPlayed or mostDanmaku. Does not affect videoUrls.
includeCommentsfalseAlso collect each video's comments and their replies.
maxCommentsPerVideo50Comments and replies together per video (1-2000).
maxUpstreamRequestsderivedHard ceiling on requests to Bilibili for the whole run. Leave empty and the Actor works one out from the rest of your input.

At least one of keywords and videoUrls is required. Example:

{
"keywords": ["美食", "旅行"],
"videoUrls": ["https://www.bilibili.com/video/BV1xx411c7mD"],
"maxVideosPerKeyword": 20,
"sort": "relevance",
"includeComments": true,
"maxCommentsPerVideo": 50
}

The same video entered twice, or found under two keywords, is collected and charged once; the repeat gets a video_summary row with stopReason: "duplicate".

maxUpstreamRequests gives you a known upper bound before the run starts. It counts every request the run sends to Bilibili - search pages, video details, comment pages, reply pages, the signing-key read and every retry. Leave it empty and the Actor derives a ceiling from your keywords, video links, maxVideosPerKeyword and comment settings, so a run is never unbounded. When the ceiling is reached, what was being collected is marked partial with stopReason: "upstream_request_cap", anything after it is reported as not collected, and the run ends normally. This is a limit of yours, not a problem at Bilibili, which may have more.

Output

One dataset; type tells the rows apart. Four table views are predefined: Videos, Comments and replies, Keyword summaries, and Videos not collected. A RUN_SUMMARY record in the key-value store carries the run totals, the status of each keyword, the request counts and why collection stopped.

type: "video"

FieldMeaning
bvid, aidBilibili's two IDs for the video.
title, descriptionAs Bilibili shows them.
urlhttps://www.bilibili.com/video/<bvid>.
coverUrlCover image.
durationSecLength in seconds.
publishedAtWhen it was published on Bilibili (UTC).
author{ mid, name } - the channel that published it.
stats{ views, likes, coins, favorites, shares, danmaku, comments }. A number Bilibili did not return is null, never 0.
tagsThe tags on the video page.
keywordThe search term it was found under; null for a video given by link.
collectedAtWhen we collected the row (UTC).
commentsRequestedWhether this run asked for comments.
commentsCollected, repliesCollectedHow many were written; null when comments were not requested.
commentStatuscomplete, partial, failed, none, platform_gap or not_requested.
commentStopReasonMachine-readable reason the comments ended, for example limit_reached, risk_control, end_of_comments.
partial, partialReasontrue with a sentence when this video's collection was cut short.

type: "comment"

FieldMeaning
commentIdBilibili comment ID (rpid), as a string: these are 64-bit.
bvidThe video it belongs to.
level1 for a top-level comment, 2 for a reply.
parentCommentIdThe comment this one answers - a top-level comment or another reply. null on a top-level comment.
rootCommentIdThe top-level comment the whole thread hangs off. null on a top-level comment.
textThe comment text. Emoji appear as Bilibili codes such as [笑哭].
likesLikes at collection time.
replyCountReplies Bilibili counts under it.
publishedAtWhen it was posted (UTC).
author{ mid, name, ipLocation }. Only what the page prints next to the comment; ipLocation is null on signed-out reads.
collectedAtWhen we collected the row (UTC).
partial, partialReasontrue on a comment whose replies were cut short, with the reason.

type: "keyword_summary" and type: "video_summary"

One keyword_summary per keyword: videosRequested, videosCollected, resultsSeen, duplicatesSkipped, searchPagesRead, resultsReportedByBilibili, collectionStatus (complete, partial, empty or failed), stopReason, statusReason and partial / partialReason.

A video_summary row appears for every video the run was asked for but wrote no video row for: a duplicate (skipped), a video Bilibili no longer serves (not_found), or one the request limit or an error cut off (failed). A keyword that returns nothing is empty with partial: false; a keyword Bilibili refused to serve is failed with partial: true and says so. The two are never mixed up.

Blocking is reported, not hidden

Bilibili sometimes answers a comment request with a three-comment preview and "the list is finished", while its own counter says there are tens of thousands. That is Bilibili withholding the list. This Actor recognises it, retries once from a different egress, and if the list is still withheld marks the video partial with commentStopReason: "risk_control". It never writes a withheld preview out as "this video has 3 comments". RUN_SUMMARY carries riskControlHits, the egress the run ended on and every switch it made.

Pricing

Pay per result: every video row and every comment row is one charged result. Summary rows are free. Comments are the expensive part of a run - one video with 50 comments is 51 results, not 1 - which is why includeComments is off by default.