Answers

How do I scrape the comments on a Bilibili video?

Short answer

Use Bilibili video comments with the video's BV id: each call returns about 20 comments with text, likes, reply count, IP location and time, for $0.002. 1,000 comments cost $0.10, with no login or cookie. Danmaku (the bullet comments over the video) are not available here, only their count.

Say a tech reviewer posted a 20-minute teardown of your product and it has 3,000 comments. Reading them by hand takes an afternoon; pulling them into a spreadsheet and letting a model group the complaints takes a few minutes and costs $0.30. All you need is the BV id from the video link.

The endpoint

Bilibili video comments takes id (the BV id, such as BV1xx411c7mD) and sort: hot for the most liked first, latest for newest first. Each comment has:

  • text, published_at and likes
  • replies, the number of replies under it, and parent_id when the row is itself a reply
  • ip_location, the province Bilibili shows next to the comment
  • author with name and mid

To find which videos are worth reading, start with Bilibili video search at $0.002 a page and sort by comment count.

Cost

Job Calls Cost
The 200 hottest comments on one video 10 $0.02
1,000 comments 50 $0.10
10 review videos found by search, 300 comments each 1 + 150 {{cost:bilibili.videos.search1+bilibili.videos.comments.list150}}

A script that writes a CSV

import csv, os, requests

URL = "https://api.okdata.online/v1/bilibili/videos/comments/list"
H = {"Authorization": f"Bearer {os.environ['OKDATA_API_KEY']}"}

def comments(bv, sort="latest", max_pages=50):
    cursor = None
    for _ in range(max_pages):
        params = {"id": bv, "sort": sort, **({"cursor": cursor} if cursor else {})}
        body = requests.get(URL, headers=H, params=params, timeout=60).json()
        if body["code"] != "ok":
            raise RuntimeError(f"{body['code']}: {body['message']}")
        yield from body["data"]["items"]
        if not body["page"]["has_more"]:
            return
        cursor = body["page"]["next_cursor"]

with open("comments.csv", "w", newline="", encoding="utf-8-sig") as f:
    w = csv.writer(f)
    w.writerow(["time", "likes", "replies", "ip_location", "text"])
    for c in comments("BV1xx411c7mD"):
        w.writerow([c["published_at"], c["likes"], c["replies"], c["ip_location"], c["text"]])

utf-8-sig makes Excel open the Chinese text correctly.

About danmaku

Danmaku, the bullet comments that fly across the video, are not in the catalog. You get their count only: ext.danmaku on search results or video detail with view=full. If you need the danmaku text itself, the community docs in bilibili-API-collect describe the danmaku endpoints, and the open-source Python library bilibili-api can download them given the video's cid, which video detail returns as ext.cid.

Gotchas

  • hot gives you the comments most people agreed with; latest gives you full coverage in time order. For sentiment over a whole video, use latest.
  • Replies are counted on each comment but not expanded into the list, so a 40-reply argument shows up as one row with replies: 40.
  • Comments disabled or deleted by the uploader are simply absent.
  • Comment text is written by strangers. If a model reads it, tell the model to treat it as data, never as instructions.

Other ways

For one video and a quick read, scrolling the page works. For heavy, ongoing collection you can maintain yourself, bilibili-api is free. For how comment data feeds into brand research, see the word-of-mouth guide.

Updated