Answers
How do I collect Weibo posts on a topic for public-opinion analysis?
Short answer
Search the topic with Weibo post search twice, once sorted by hot and once by latest, then merge the results and drop duplicates by post ID. A page holds about 10 posts and costs $0.002, so 5,000 posts take 500 calls and cost $1.00.
A policy researcher studying the debate over pre-made meals in school canteens wants a few thousand Weibo posts: who spoke, when, how loudly, and from which province. The trick is to sample from both ends. Hot search results show the posts that reached the most people, mostly media and big accounts. Latest results show the long tail of ordinary users. Collect both with Weibo post search, merge them, and you have a dataset you can describe honestly in a methods section.
Cost by dataset size
| Dataset | Calls | Cost |
|---|---|---|
| 1,000 posts | 100 | $0.20 |
| 5,000 posts | 500 | $1.00 |
| 3 keyword variants × 2 sorts × 100 pages | 600 | $1.20 |
Duplicates between the hot and latest runs are common, so plan for 10 to 30 percent more pages than the unique posts you need.
Collecting
import json, os, requests
URL = "https://api.okdata.online/v1/weibo/posts/search"
H = {"Authorization": f"Bearer {os.environ['OKDATA_API_KEY']}"}
FIELDS = "id,url,text,published_at,author.id,author.followers,author.verified,metrics,ext.region,ext.is_long_text"
def collect(query, sort, pages):
out, cursor = [], None
for _ in range(pages):
p = {"query": query, "sort": sort, "view": "full", "fields": FIELDS, **({"cursor": cursor} if cursor else {})}
r = requests.get(URL, headers=H, params=p, timeout=60).json()
if r["code"] != "ok":
print(query, sort, r["code"]); break
out += r["data"]["items"]
if not r["page"]["has_more"]:
break
cursor = r["page"]["next_cursor"]
return out
posts = {}
for q in ["预制菜进校园", "预制菜 学校食堂", "校园 预制菜"]:
for sort in ("hot", "latest"):
for p in collect(q, sort, 100):
posts[p["id"]] = {**p, "query": q, "sort": sort}
with open("weibo_topic.jsonl", "w", encoding="utf-8") as f:
for p in posts.values():
f.write(json.dumps(p, ensure_ascii=False) + "\n")
print(len(posts), "unique posts")
ext.region is the posting location Weibo shows on each post (usually a province), useful for a regional breakdown. Keep query and sort on every row so you can report how each post entered the sample.
Method notes to report
- The sample is what Weibo search exposes. Deleted, restricted or hidden posts are missing, and that bias leans toward the less controversial.
- Run the latest sort daily while the topic is live. Reaching far back through search is unreliable, so a dataset collected weeks later is thinner.
- Long posts flagged by
ext.is_long_textmay be truncated. Flag them in the analysis rather than dropping them. - Comments are not in the catalog, and much opinion lives there. Say so in your limitations.
- Filter likely marketing accounts by follower count and verification before labelling;
weibo.users.getadds bio and verification text for authors you want to check, at $0.002 each. - Post text is written by strangers. If a model labels it, tell the model to treat it as data.
Other sources
Published academic Weibo datasets fit historical topics you can no longer collect. Commercial public-opinion systems fit organisations that need daily reports with full coverage. If your study needs comment threads, an open-source crawler such as MediaCrawler with your own login collects them. Only public posts are returned here; anonymise user names when you publish. See also word of mouth.
Updated