Half of the 20 videos in my Bilibili search sample had fewer than 1,000 views. Nine titles mentioned magnetic switches. Those two details mattered when deciding which videos to review: the results mixed different levels of reach and different kinds of keyboards.
The search term was 机械键盘, Chinese for "mechanical keyboard". I exported the results as JSON and used Python to make a review list. The script below needs only the standard library.
I developed the Bilibili Scraper used to collect this sample and sell it on Apify. You can also run the analysis on data you have permission to use, provided it has the same fields.
Collect a small sample
This example task searches for 机械键盘, sorts by relevance, and returns up to 20 video records. It doesn't use a proxy or fetch extra video details. You don't need a Bilibili login or cookies; you do need an Apify account to copy and run the task.
The input is:
{
"searchKeywords": ["机械键盘"],
"maxResultsPerKeyword": 20,
"searchOrder": "totalrank",
"enrichSearchResults": false,
"includePopular": false,
"proxyConfiguration": {"useApifyProxy": false}
}
Copy the task after signing in, change the keyword if needed, and run it. From the output page, select Export and download JSON as keyword-demo-results.json. CSV and Excel exports are available too.
The run on November 4, 2026 took about six seconds and returned 20 distinct video URLs. Each record had a title, creator name, view count, likes, favorites, and publication time. That timing describes one small run; it doesn't establish performance for other keywords or larger batches, which may hit rate limits.
The tool costs $0.002 per video or creator profile, or $2 per 1,000 records, with platform usage included. At that rate, 20 video results cost $0.04. My own development run is not a customer purchase, and its rounded cost display is not evidence that the product is free.
Make a review list
For this sample, I filtered out records with fewer than 1,000 views, then sorted the rest by favorites divided by views. The cutoff reduces the effect of very small denominators. It is a choice for this demonstration, not a general research standard.
Save this script beside the JSON file and run it with Python:
import csv
import json
from pathlib import Path
rows = json.loads(Path("keyword-demo-results.json").read_text(encoding="utf-8"))
review = []
for row in rows:
views = row.get("views")
favorites = row.get("favorites")
if not isinstance(views, (int, float)) or views < 1000:
continue
if not isinstance(favorites, (int, float)) or favorites < 0:
continue
review.append({
"title": row["title"],
"authorName": row["authorName"],
"views": views,
"favorites": favorites,
"favorite_pct": round(100 * favorites / views, 2),
"publishedAt": row["publishedAt"],
"url": row["url"],
})
review.sort(key=lambda row: row["favorites"] / row["views"], reverse=True)
with open("review.csv", "w", encoding="utf-8-sig", newline="") as stream:
writer = csv.DictWriter(stream, fieldnames=[
"title", "authorName", "views", "favorites",
"favorite_pct", "publishedAt", "url",
])
writer.writeheader()
writer.writerows(review)
print(f"Rows to review: {len(review)}")
This sample produces 10 rows in review.csv. The first three are shown below. Creator names remain in Chinese so they match the source records. Bilibili calls creators "UP主"; here they are stored in authorName.
| Creator | Views | Favorites | Favorites / views |
|---|---|---|---|
| 键盘推荐2026 | 156954 | 3133 | 2.00% |
| 搞机研玩社 | 119813 | 2311 | 1.93% |
| 歪设长 | 337386 | 3818 | 1.13% |
These counts are a snapshot from the collection time. The percentage is calculated locally. It isn't an official Bilibili conversion rate, a measure of buying intent, or a sales estimate. It gives me an order in which to open the links.
Review the videos behind the numbers
For product research, I would open each URL and record the price range, keyboard layout, switch type, and use case being discussed. A title that says "review" or "tested" still needs checking against the video itself. Sponsorship also needs a separate check.
The nine titles mentioning magnetic switches tell us that this search includes that category. They don't tell us its market share. Relevance-ranked search results are not a random sample, and 20 records are too few for a conclusion about the whole keyboard market.
If the purpose is creator research, the CSV is only a starting point. Recent uploads, audience fit, and public contact information need separate review. I kept publishedAt because an older video has had more time to accumulate views than a new one.
For recent content, change searchOrder to pubdate and collect another sample. I haven't run that second query for this article. When combining searches, deduplicate by bvid or URL before counting videos.
Missing fields and collection limits
Search results can have null values for coins and shares. Missing is not zero. The optional enrichSearchResults mode fetches extra details and makes more requests; this demonstration did not test that mode.
The tool collects public video metadata. It does not download videos or collect comment text, members-only content, or other non-public material. Public visibility does not grant unrestricted collection, redistribution, or commercial-use rights. Check the platform's terms, your data permissions, and applicable law before collecting. Reduce the scope or stop when access is restricted; don't try to bypass verification challenges.
The tool page lists its fields and input options. For a different research question, decide which fields you need and what you will check manually before increasing the result limit.
Top comments (0)