Bilibili Scraper: Videos, Search, Uploaders & Comments avatar

Bilibili Scraper: Videos, Search, Uploaders & Comments

Pricing

$2.00 / 1,000 item returneds

Go to Apify Store
Bilibili Scraper: Videos, Search, Uploaders & Comments

Bilibili Scraper: Videos, Search, Uploaders & Comments

Search Bilibili, export video details and stats, an uploader's videos and profile, or a video's comments — via the public api.bilibili.com web API. No Bilibili login required.

Pricing

$2.00 / 1,000 item returneds

Rating

0.0

(0)

Developer

Changefeeds Tools

Changefeeds Tools

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

2 days ago

Last modified

Share

A Bilibili scraper and Bilibili API client in one actor. Search Bilibili by keyword, pull full stats for specific videos, export an uploader's video list and profile, or grab a video's comments — all through the same public api.bilibili.com web API a logged-out browser on bilibili.com uses. No Bilibili account, cookie, or login required.

Modes

search — videos matching a keyword

{ "mode": "search", "keywords": ["minecraft"], "maxItems": 20, "order": "totalrank" }

Each keyword is searched separately and paginated until maxItems videos are collected (or results run out). order is one of totalrank (comprehensive ranking, default), click (most viewed), pubdate (newest), dm (most danmaku) or stow (most favorited).

videos — details for specific videos

{ "mode": "videos", "urls": ["BV1m5aY69E8D", "av117342986110880", "https://b23.tv/BV1m5aY69E8D"], "includeTags": true }

Accepts BV ids (BV1xxxxxxxxx), av ids (av123456 or a bare number), full bilibili.com/video/... URLs, and b23.tv short links (the redirect is followed for you).

user — an uploader's videos, profile and follower count

{ "mode": "user", "urls": ["686127", "https://space.bilibili.com/686127"], "maxItems": 50 }

Accepts a bare numeric mid, a space.bilibili.com/<mid> URL, or a b23.tv short link. Emits the uploader's recent videos plus one profile row with name, bio, level, follower/following counts and avatar.

comments — a video's comments

{ "mode": "comments", "urls": ["BV1m5aY69E8D"], "maxComments": 100 }

Same video-reference formats as videos mode. See Limits below: in practice this returns Bilibili's own small "hot comments" preview, not a full comment thread — that's a limit of the logged-out API itself, not a bug.

Sample output

A video row (live run, 2026-09-30):

{
"type": "video",
"bvid": "BV1m5aY69E8D",
"aid": 117342986110880,
"url": "https://www.bilibili.com/video/BV1m5aY69E8D",
"title": "十四年的等待,我的世界终于迎来全新第四维度:筛界 Minecraft Live2026",
"description": "",
"owner_name": "籽岷",
"owner_mid": 686127,
"published_at": "2026-09-27T12:29:08.000Z",
"duration_seconds": 531,
"views": 1194280,
"likes": 71174,
"coins": null,
"favorites": 13774,
"shares": null,
"danmaku": 2267,
"reply_count": 4684,
"tags": ["筛界", "籽岷", "方块制片局", "新维度", "像素风", "沙盒游戏", "新版本", "我的世界", "LIVE", "MINECRAFT"],
"cover_url": "https://i0.hdslb.com/bfs/archive/39e6cfdf143c830aaf3685bb0c2b15e6d51fb030.jpg",
"category": "单机游戏",
"scraped_at": "2026-09-30T04:27:15.499Z"
}

coins and shares are only available from videos mode (the full /view endpoint); search and user mode results don't carry them, so they're null there.

A user row:

{
"type": "user",
"mid": 686127,
"name": "籽岷",
"sign": "十四年的等待...",
"level": 6,
"followers": 5454479,
"following": 855,
"videos_count": 30,
"face_url": "https://i0.hdslb.com/bfs/face/7efb679569b2faeff38fa08f6f992fa1ada5e948.webp",
"scraped_at": "2026-09-30T04:28:08.401Z"
}

A comment row:

{
"type": "comment",
"video": "BV1m5aY69E8D",
"rpid": 318812679792,
"author_name": "空悟明理",
"author_mid": 1759281120,
"text": "岷叔这种新内容介绍真不用写这么公式的稿子...",
"likes": 521,
"reply_count": 7,
"created_at": "2026-09-27T12:36:39.000Z"
}

A failed input gets a free status row instead, e.g.:

{ "type": "status", "input": "686127", "mode": "user", "status": "risk_control", "error": "HTTP 412: request was banned (risk control)", "checked_at": "2026-09-30T04:28:08.401Z" }

status is one of:

  • not_found — the keyword/id resolved to nothing.
  • invalid — the input entry isn't a recognised BV id, av id, mid or URL.
  • risk_control — Bilibili's anti-scraping check rejected the request (HTTP 412, or a JSON code of -352/-412). See Limits.
  • error — any other HTTP/network failure.

The key-value store record OUTPUT holds a per-run summary (counts, HTTP stats, stopped_reason, charged_events). Every run leaves at least one dataset row, even one where every input fails, so a quiet run is never mistaken for a broken one.

Pricing

Pay per event, nothing else: $0.002 per item returned ($2 per 1,000 video/uploader/comment rows). Failed inputs (not_found, invalid, risk_control, error) are never charged. If you set a maximum total charge for the run, the actor stops cleanly once it's reached and says so in OUTPUT.stopped_reason ("max_total_charge_reached").

Limits, stated plainly

  • Public data only, no login. This reads exactly what api.bilibili.com serves a logged-out browser. No private messages, no member-only content, no video/audio downloads.
  • Bilibili's risk control is real and IP-dependent. The uploader video-listing endpoint (/x/space/wbi/arc/search) and the profile endpoint (/x/space/wbi/acc/info) can reject requests from some IPs (including some datacenter ranges) with HTTP 412 or a -352 code, even with correct WBI signing. When that happens the actor reports a risk_control status row instead of crashing, and — for user mode — still emits whatever it could get (e.g. the follower count from /x/relation/stat, which is far more reliable, even when the profile or video list is blocked).
  • Comments are capped by Bilibili itself, not by this actor. The logged-out /x/v2/reply/main endpoint returns only its small "hot comments" set (a handful of rows) for both its "hot" and "recent" modes and reports is_end: true immediately — full-thread pagination needs a logged in session, which this actor deliberately does not use. maxComments caps what you get; it can't make Bilibili return more than it's willing to.
  • View/like/coin counts are a snapshot. They change between your run and the next one, same as on the site.
  • It stays polite: at most 2 requests in flight, ~300 ms between requests, HTTP 429/5xx retried with backoff (Retry-After honoured, capped at 60 s, up to 3 retries), a realistic desktop Chrome User-Agent and Referer https://www.bilibili.com (what the site's own web client sends — this is not evasion, it's what the public API expects of a browser client).

FAQ

Do I need a Bilibili account or cookie? No — this uses only the public, logged-out api.bilibili.com endpoints.

Can it download videos? No, never. Only metadata (title, stats, tags, cover URL).

Why did I get a risk_control status instead of data? Bilibili's anti-scraping layer rejected that specific request from this run's IP. Retry later, or lower request volume — the actor already backs off and won't burn your run.

Can I search in English? Yes, keywords are passed straight to Bilibili's own search; results follow whatever that returns for the term.

How is this a "bilibili api" client? Every mode is a thin export of a few Bilibili web-API endpoints (search, view, space listing, comments) — this actor exists so you don't have to reimplement WBI request signing yourself.

Troubleshooting: Bilibili v_voucher / -352 / 412 risk control

If you're calling Bilibili's logged-out web endpoints from a server and occasionally (or always) get a response with code: 0 but no real payload — just a v_voucher field where your data should be — you've hit Bilibili's risk control system (风控), not a bug. The same family of errors shows up as HTTP 412 or a -352 error code.

Why it happens

Bilibili doesn't publish an official third-party API. Community libraries reverse-engineer the same endpoints the website and apps use. Bilibili's risk-control layer inspects request volume, IP reputation, and whether the client presents cookies a real browser session would have. When suspicious, it doesn't return an error — it returns a 200 OK with code: 0 and a v_voucher token instead of your data. That token is meant for a captcha flow that a scraper can't complete.

Free fixes

  • Send visitor cookies before making API calls. Bilibili's frontend sets buvid3, buvid4 and b_nut tokens via /x/frontend/finger/spi before calling data endpoints:
import requests
session = requests.Session()
resp = session.get("https://api.bilibili.com/x/frontend/finger/spi")
data = resp.json()["data"]
session.cookies.set("buvid3", data["b_3"])
session.cookies.set("buvid4", data["b_4"])
  • Set a real Referer and browser-like User-Agent. A bare Python default user agent with no referer is an easy tell.
  • Throttle and randomize request timing. Risk control weighs request velocity heavily; add delay and jitter between calls.
  • Rotate sessions across proxy IPs for volume. A single IP making many requests gets flagged eventually.

Bilibili tightens its rules periodically, so whatever works today may need adjusting later.

This actor handles it

This actor manages visitor-token handshake, rotating residential proxy, and retries. Failed or risk-controlled inputs are not charged.

Local development

pnpm --filter @mmnm/bilibili test # unit tests, no network
pnpm --filter @mmnm/bilibili build

node src/main.ts runs the actor locally with Apify's local storage (./storage); ACTOR_TEST_PAY_PER_EVENT=true ACTOR_MAX_TOTAL_CHARGE_USD=1 exercises the charging path with the SDK's $1 local test price.