If you scrape Weibo's hot-search board you get a snapshot: ~50 trending topics, ranked, right now. That's table stakes — and on its own it's almost useless as a signal. The value isn't what is trending; it's what's moving: which topic just jumped 30 places in 20 minutes, which is decaying, which is brand-new this hour. That's velocity, and velocity is where the signal lives — for brand-crisis teams, consumer-trend desks, and anyone modelling attention in China.
The catch: a single scrape can't tell you velocity. You have to diff the board against its own past, reliably, run after run. That's a stateful pipeline, and it has a few non-obvious gotchas. Here's the shape of the problem and how to handle it.
Why a snapshot isn't enough
Rank-right-now tells you nothing about trajectory. "#7" could be a topic on its way to #1 or one fading out of the top 50 — same row, opposite meaning. To act on a trend you need the derivative: direction, speed, and how long it's been climbing. None of that is in a single pull.
The trending-delta problem
Three things make "just diff the board" harder than it looks:
- Key by identity, not position. You can't track a topic by its rank — rank is the thing that changes. Key by the topic itself (its text/keyword) or your deltas are nonsense.
- State has to survive between runs. A scheduled scrape is stateless by default — each run starts cold. To compute "this rose 12 places since 30 minutes ago," you must persist the previous board and reload it next run, keyed so independent schedules don't overwrite each other.
-
The board churns. Topics appear, peak, and fall off. You want each tagged
new/rising/falling/steady/dropped, plus how long it's been on the board and its running peak — none of which exist in the raw snapshot.
How to handle it (the pattern)
current = pull_board() # [{topic, rank, heat}, ...]
previous = load_state(key) # durable store that persists across runs
for t in current:
prev = previous.get(t.topic) # match on identity, not rank
t.rank_delta = (prev.rank - t.rank) if prev else None
t.heat_delta = (t.heat - prev.heat) if prev else None
t.status = classify(prev, t) # new / rising / falling / steady
t.first_seen = prev.first_seen if prev else now()
t.peak_rank = min(prev.peak_rank, t.rank) if prev else t.rank
emit(current + dropped(previous, current)) # include topics that fell off
save_state(key, current) # for next run
Schedule that (hourly or daily) and every run becomes a velocity reading instead of a snapshot. The hard parts in practice are the durable, per-stream state and stable identity matching — get those wrong and the deltas lie.
How this turns into money
Velocity is a leading indicator, and leading indicators are what people pay for:
- Brand-crisis alerting — catch a topic about your brand spiking before it peaks: hours of lead time vs. a once-a-day report. That lead time is the product.
- Consumer-trend alt-data — rising-topic velocity is an early read on attention and demand shifts. Trend desks and funds buy exactly this kind of signal; a clean, timestamped delta feed is a sellable input.
- Marketing / launch timing — ride a topic while it's ascending, not after it's saturated and CPMs have spiked.
If you're building a product on top, this delta stream is your signal layer — everything downstream (alerts, scoring, dashboards) hangs off it.
The practical path (skip the plumbing)
You can build the stateful diff and session handling yourself, or point a maintained extractor at it. I maintain a Weibo Scraper on Apify with a hot_search_delta mode that does exactly this — pulls the board, persists state across scheduled runs, and returns the new / rising / falling / dropped deltas with rank velocity, time-on-board, and peaks. Pay-per-result, runs on a schedule.
from apify_client import ApifyClient
client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("zhorex/weibo-scraper").call(run_input={
"mode": "hot_search_delta",
"deltaStateKey": "hourly", # name independent streams (hourly / daily / ...)
})
for topic in client.dataset(run["defaultDatasetId"]).iterate_items():
if topic["status"] == "rising" and (topic["rankDelta"] or 0) >= 10:
print(f'{topic["title"]} +{topic["rankDelta"]} ranks (heat {topic["hotValue"]})')
Wire it to an Apify Schedule and you have a rolling Weibo trend-velocity feed without owning the pipeline.
What it is — and isn't
- Is: a stateful, scheduled velocity feed over China's largest real-time attention signal.
- Isn't: a one-off snapshot (that's the standard hot-search mode) — or a sentiment model. You get structured movement; the modelling on top is yours.
Need a field that isn't there yet, or a different cadence? Open an issue on the Actor page — I usually ship small additions within a couple of days. For high-volume or managed feeds, the README has the enterprise contact.
Top comments (0)