Appearance
舆情监测怎么做地域分布?Python 按 IP 归属地统计热点来源地
某消费品牌出了负面舆情,公关总监十分钟后就要知道「这波声量主要从哪来」——是广东的维权群在发酵,还是北方某个城市的记者带了节奏。市面上的舆情 SaaS 一签就是几万一年,还要对接数据源。对于已经有内容库的中型公司,这事用 Python 和一张 IP 归属地表就能搭起来,花不了半天。
这里说的舆情地域分布,跟网站访问日志统计是两回事:日志统计回答「谁访问了我的站」,舆情分析回答「讨论声量集中在哪」。数据源是平台自己的舆情库——帖子、评论、转发的记录,每条带着发布者 IP 和互动数据。把 IP 换成省份,再按互动量加权聚合,就是一张地域声量榜。
一、为什么 IP 归属地能撑起舆情地域分析
一条舆情条目的地域属性,来自发布者当时的公网出口 IP。三个层次:
- 单条归属:评论「这牌子翻车了」的人在北京,这条就计给北京;
- 聚合声量:一个省的所有条目按互动数(点赞/评论/转发)加权求和,得到「地域热度」;
- 趋势对比:同一事件不同阶段跑一遍,看声量重心有没有从 A 省迁移到 B 省——这对判断「是区域性事件还是全国性事件」极有用。
加权是有讲究的:一条被转了两万次的原帖,分量应该重过一百条没人理的评论。权重按内容类型设就行,原帖 1.0、评论 0.3、转发 0.5 这类初始值,跑两轮数据再调。
二、方案设计
- 舆情库导出条目 JSON:IP、内容类型、互动数;
- 逐条查归属地,命中缓存直接取,未命中才调接口(免费版 60 次/分钟,批量必须循环 + 限速 + 缓存);
- 按省份累加「互动数 × 类型权重」;
- 排序输出 Top 榜,可选导出 CSV 给可视化。
三、Python 实现
python
import json
import time
import requests
from collections import defaultdict
# IP9 免费版 60 次/分钟/IP,缓存 + 限速是批量查询的标配
CACHE = {}
LAST_CALL = 0.0
def query_geo(ip):
global LAST_CALL
if ip in CACHE:
return CACHE[ip]
try:
now = time.time()
if now - LAST_CALL < 1.1:
time.sleep(1.1 - (now - LAST_CALL))
r = requests.get(f"https://ip9.com.cn/get?ip={ip}", timeout=5)
d = r.json()
LAST_CALL = time.time()
if d.get("ret") != 200:
return None # 非法 IP / 限速,跳过该条
CACHE[ip] = d["data"]
return d["data"]
except Exception:
return None
# 内容类型权重:原帖最重,评论/转发递减。按实际传播形态调。
WEIGHT = {"post": 1.0, "comment": 0.3, "repost": 0.5}
def region_heat(items):
prov_hot = defaultdict(float)
skipped = 0
for it in items:
geo = query_geo(it["ip"])
if not geo:
skipped += 1
continue
prov = geo.get("prov") or "未知"
hot = it.get("hot", 1) * WEIGHT.get(it.get("kind", "post"), 1.0)
prov_hot[prov] += hot
return prov_hot, skipped
def main():
with open("yq_items.json", encoding="utf-8") as f:
items = json.load(f) # [{"ip":"1.2.3.4","kind":"post","hot":120}, ...]
hot, skipped = region_heat(items)
print(f"共 {len(items)} 条,归属地查询失败跳过 {skipped} 条\n")
print("地域声量 Top 榜:")
for i, (prov, h) in enumerate(
sorted(hot.items(), key=lambda x: -x[1])[:15], 1):
print(f"{i:2d}. {prov:<6s} {h:8.1f}")
# 导出 CSV,喂给图表工具做舆情地图
with open("region_heat.csv", "w", encoding="utf-8-sig") as f:
f.write("省份,热度\n")
for prov, h in sorted(hot.items(), key=lambda x: -x[1]):
f.write(f"{prov},{h:.1f}\n")
if __name__ == "__main__":
main()这段原型的关键在 query_geo:缓存命中直接返回,没命中才发请求,间隔 1.1 秒压住免费额度;单条查询失败只跳过该条,不会让整个批次崩掉。region_heat 是核心逻辑——按省份累加加权热度,数据量几百几千条时秒级出榜。跑完把 region_heat.csv 丢进图表工具或叠到地图上,就是一张舆情地图。
四、落地注意事项
- 转发链会稀释地域属性:一条原帖被转发,转发的 IP 归属地是转发者所在省,不是发帖者。想分析「源头地域」就只统计原帖的 IP;想看「扩散地域」才纳入转发——口径不同,榜单结论完全不同,做之前先定好。
- IP 是城市级,不是精确位置:归属地给到省市足够支撑舆情地域分析,想精确到区县需要 VIP 版
area字段;别拿它定位具体个人。 - 代理 IP 要识别:舆情库里大量条目如果来自机房/代理(
ip_type为 IDC),可能是刷量号在干扰声量,统计时单列一组对比,别混进真实网民声量。 - 阈值从数据里来:权重和 Top 榜截断数(15 名)都是初始值,跑两期舆情后按「跟业务判断是否一致」校准;不加权的省份排名和加权的往往差很多,这也是加权存在的意义。
- 合规:处理的是已入库的舆情数据,IP 属性和内容关联分析要限定在本平台数据范围内,明确处理目的(地域声量分析),不对外输出单条 IP 明细。
总结
舆情地域分布不是舆情 SaaS 的专利,用 https://ip9.com.cn/get?ip=xxx 免费接口 + 一个 Python 脚本就能跑通:条目 IP → 归属地省份 → 互动加权聚合 → Top 榜和 CSV。接口免费版 60 次/分钟够中小舆情库用,权重、口径(源头 vs 扩散)、代理过滤这三件事想清楚,结果就能直接上汇报。觉得免费额度紧,或要区县粒度、ip_type 识别代理,再看官网 https://www.ip9.com.cn 的 VIP 说明。先拿最近一期舆情导出跑一遍,对照业务判断调好权重,这套轻量方案能顶掉一半的 SaaS 咨询费。