Bilibili Scraper: Videos, Search, Uploaders & Comments
Pricing
$2.00 / 1,000 item returneds
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
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
2 days ago
Last modified
Categories
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 JSONcodeof -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.comserves 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-352code, even with correct WBI signing. When that happens the actor reports arisk_controlstatus row instead of crashing, and — forusermode — 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/mainendpoint returns only its small "hot comments" set (a handful of rows) for both its "hot" and "recent" modes and reportsis_end: trueimmediately — full-thread pagination needs a logged in session, which this actor deliberately does not use.maxCommentscaps 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,buvid4andb_nuttokens via/x/frontend/finger/spibefore calling data endpoints:
import requestssession = 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
Refererand browser-likeUser-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 networkpnpm --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.