For AI

How-to guides

Weibo API in Python: search, profiles and hot search (2026)

Three endpoints: Weibo post search, Weibo account profile by UID and Weibo hot search, each a plain GET with an API key, no OAuth app and no login cookie. The worked example below is 9 calls and costs $0.018; a failed call is not charged.

Updated

Weibo does have an open API, but it is built around the user who authorizes your app. The interface list on open.weibo.com runs through OAuth 2.0: read the authorized user's profile, their own posts, their home timeline, the comments on a post, and a few write calls such as sharing a link. Interfaces marked as advanced need a separate application. Keyword search is not in the standard list. The closest thing, search/topics, is an advanced interface that only searches posts inside a #topic# (the keyword has to be a topic between two # signs) and returns only the newest 200 results. Wider access goes through Weibo's commercial data interfaces, which come with their own subscription terms.

So most Python scripts for Weibo data scrape the site with a logged-in cookie, as searching Weibo without a cookie describes. This guide skips both the OAuth app and the cookie: each call is an HTTPS GET with an API key and requests is the only library. You end with a CSV of posts, a CSV of the accounts that posted them, and a check against the hot search board.

Step by step

Set the key once: export OKDATA_API_KEY=okd_.... Every answer has code ("ok" on success); lists come in data.items with a page, single objects in data.item.

Step 1: search posts by keyword

Weibo post search takes query, typed as you would in Weibo's search box, and sort: hot (the default, most engagement) or latest (newest first). One call returns about 10 posts for $0.002. Each has id, url, text, published_at, images, hashtags, and metrics.likes, metrics.comments and metrics.reposts; video posts also carry a play count in metrics.views. The author comes with the UID in author.id, author.name, author.followers and author.verified.

curl -G "https://api.okdata.online/v1/weibo/posts/search" -H "Authorization: Bearer $OKDATA_API_KEY" \
  --data-urlencode 'query=预制菜' --data-urlencode 'sort=latest'

For page two and on, send page.next_cursor back as cursor, unchanged; stop when page.has_more is false. With view=full, ext.region gives the place Weibo shows as 发布于, ext.source the client it was posted from, and ext.is_long_text flags posts that search shows cut short.

Step 2: look up the authors

Weibo account profile takes the numeric UID as id, the same number as author.id in search or the digits in weibo.com/u/5730129846. For $0.002 it returns name, bio, followers, following, posts and verified; with view=full, ext adds verified_reason, ip_location, location and gender. Looking up the UID behind a custom profile address is covered in getting a profile from a Weibo UID.

curl -G "https://api.okdata.online/v1/weibo/users/get" -H "Authorization: Bearer $OKDATA_API_KEY" \
  --data-urlencode 'id=5730129846' --data-urlencode 'view=full'

Step 3: read the hot search board

Weibo hot search takes no parameters. One call returns the current board, about 50 rows, for $0.002: rank, name (the search term), heat and url (the search page for that topic). Paid placements are left out.

curl -G "https://api.okdata.online/v1/weibo/trends/list" -H "Authorization: Bearer $OKDATA_API_KEY"

Step 4: the full script

The helper checks body["code"], returns None for deleted or banned accounts, and retries rate limits and busy upstreams with the same Idempotency-Key, so a retry is never charged twice. MAX_PAGES caps the search.

import csv
import os
import time
import uuid

import requests

API = "https://api.okdata.online"
KEY = os.environ["OKDATA_API_KEY"]
QUERY = "预制菜"
MAX_PAGES = 3     # search pages; each page is one call
TOP_AUTHORS = 5   # profile lookups


def call(path, **params):
    headers = {"Authorization": f"Bearer {KEY}", "Idempotency-Key": str(uuid.uuid4())}
    for attempt in range(4):
        body = requests.get(API + path, headers=headers, params=params, timeout=60).json()
        if body["code"] == "ok":
            return body
        if body["code"] == "not_found":
            return None  # deleted, banned or private: not charged
        if body.get("retry") in ("yes", "same_key"):
            time.sleep(body.get("retry_after_seconds") or 2 ** attempt)
            continue
        raise RuntimeError(f"{body['code']}: {body['message']} (request {body['request_id']})")
    raise RuntimeError(f"{path}: still failing after 4 tries")


def search(query, max_pages):
    cursor = None
    for _ in range(max_pages):
        body = call("/v1/weibo/posts/search", query=query, sort="latest", view="full",
                    **({"cursor": cursor} if cursor else {}))
        yield from body["data"]["items"]
        if not body["page"]["has_more"]:
            return
        cursor = body["page"]["next_cursor"]


posts = list(search(QUERY, MAX_PAGES))
with open("weibo_posts.csv", "w", newline="", encoding="utf-8-sig") as f:
    out = csv.writer(f)
    out.writerow(["post_id", "published_at", "uid", "author", "text", "likes", "comments", "reposts", "region", "url"])
    for p in posts:
        m = p["metrics"]
        out.writerow([p["id"], p["published_at"], p["author"]["id"], p["author"]["name"], p["text"],
                      m["likes"], m["comments"], m["reposts"], p["ext"].get("region"), p["url"]])

authors = {p["author"]["id"]: p["author"] for p in posts}
biggest = sorted(authors.values(), key=lambda a: a["followers"] or 0, reverse=True)[:TOP_AUTHORS]
with open("weibo_authors.csv", "w", newline="", encoding="utf-8-sig") as f:
    out = csv.writer(f)
    out.writerow(["uid", "name", "followers", "following", "posts", "verified", "verified_reason", "ip_location"])
    for a in biggest:
        body = call("/v1/weibo/users/get", id=a["id"], view="full")
        if body:
            u = body["data"]["item"]
            out.writerow([u["id"], u["name"], u["followers"], u["following"], u["posts"], u["verified"],
                          u["ext"].get("verified_reason"), u["ext"].get("ip_location")])

board = call("/v1/weibo/trends/list")["data"]["items"]
on_board = [t for t in board if QUERY in t["name"]]
print(f"{len(posts)} posts, {len(biggest)} profiles;", "on the board:" if on_board else "not on the board",
      ", ".join(f"#{t['rank']} {t['name']}" for t in on_board))

That run is the worked example: 3 search pages, 5 profiles and one board read, 9 calls. A daily version for a month (the same 9 calls each day) is $0.54.

Good to know

  • What search shows. Results are what Weibo's own search returns; posts Weibo hides from search do not appear, and search stops paging at the depth Weibo's search does.
  • Long posts. Search can cut long posts short. Check ext.is_long_text (with view=full); the full text is on the post's page at url.
  • Nulls. Shares and favorites are not shown on Weibo posts, so those metrics are null; total likes received is null on profiles. meta.unavailable names each null field.
  • Not in the catalog. Comment threads and an account's own timeline are not covered; search, profiles and the board are.
  • UIDs. Profiles take the numeric UID only, not a nickname or link.
  • Free cases. Deleted or banned accounts answer not_found, which is free, like rate limits and every other error. The same request with the same Idempotency-Key within 24 hours returns the stored answer with meta.replayed: true.

To watch the board itself, open the Weibo hot search tool. For tracking what people say about a brand over time, see word of mouth.

What the example costs

3 pages of the newest posts about 预制菜 (prepared meals), the profiles of the 5 authors with the most followers, and one read of the hot search board

EndpointCallsPriceSubtotal
Weibo post search3$0.002$0.006
Weibo account profile5$0.002$0.01
Weibo hot search1$0.002$0.002
Total9$0.018

Prices in force when this page was built. A failed call costs nothing.

In your AI (MCP)

Connect the MCP server once, then say what you want. The agent finds these endpoints, reads their prices and calls them on your balance.

SaySearch Weibo for the newest posts about 预制菜, three pages. Find the 5 authors with the most followers and give me their profiles, then tell me whether the topic is on the hot search board right now.

What the agent sends to the call tool first
{
  "endpoint": "weibo.posts.search",
  "params": {
    "query": "新品发布"
  },
  "idempotency_key": "<a new UUID>"
}

Set up the MCP server →

Sources

  1. Weibo Open Platform: 微博API (interface list)open.weibo.com · read
  2. Weibo Open Platform: 2/search/topicsopen.weibo.com · read

Connect once, then just ask.

Every new key comes with $0.10 to try it. One sentence connects your agent.

Start free
Connect your AI

Paste this into your agent

Read https://okdata.online/agents.md and set up okdata for me; my key is in the OKDATA_API_KEY environment variable.

Claude Code, Cursor, Codex and other agents that can open a link set themselves up from it.

MCP serverhttps://api.okdata.online/mcp