一、切入------从一场"看不见的观众"说起
2026年3月,LCK在中国香港举办了首届海外杯赛。两日赛事线下吸引近2万名观众入场观赛,线上预约网站访问量达94万,公开售票两日内场次2分钟内售罄。与此同时,LCK事务总长李正勋透露了一个关键数字:60%的LCK观众来自韩国以外地区 。
这意味着,在每一场中韩对抗赛的直播间里,观众的IP地址正跨越国界涌入------但他们的地域分布特征如何?中国哪些城市的用户最爱看LCK?华东观众偏爱T1还是Gen.G?这些问题的答案,隐藏在每一行IP访问日志里。
本文从IP归属地的技术视角切入,探讨如何通过IP归属地查询平台 和离线IP数据库部署 方案,构建电竞观众的地域画像分析能力。
二、市场背景:中韩电竞观众的地域分布格局
中国电竞用户规模
据《2025年中国电子竞技产业报告》数据,2025年中国电竞产业收入达293.31亿元,同比增长6.40%;用户规模超4.95亿人,同比增长1.06%。线下赛事举办城市集中分布在华东、西南地区,上海、成都、重庆位列前三。其中上海占全国电竞赛事总量的19.2%,成都和重庆分别为10.6%和7.9%。
中韩对抗赛热度
中韩对抗赛的热度远超预期。以2026年亚洲对抗赛为例,在线观众峰值超过2800万,剔除中国观众数据后,海外观众峰值仅26万多。这意味着,中国观众占据了中韩对抗赛超过99%的在线收视份额 。
与此同时,LCK的平均每分钟观众数达63.4万,同比增长42%,国内观众首次突破20万,T1与Gen.G的季后赛最高同时观看人数约为203万,赛季累计观看时间约2.29亿小时。
这些数据指向一个清晰的结论:中韩电竞观众的精准地域画像,是中国电竞市场商业决策的关键变量 。
三、技术方案:从IP日志到观众画像的完整链路
3.1 IP归属地查询平台 vs 离线IP数据库部署
实现电竞观众地域分析,主要有两条技术路径:
|------|-----------|---------|
| 对比维度 | 在线API方案 | 离线数据库方案 |
| 响应速度 | 受网络延迟影响 | 毫秒级本地查询 |
| 并发能力 | 受API限流限制 | 无限制 |
| 数据隐私 | 日志外传风险 | 数据本地存储 |
| 内网环境 | 需开放外网访问 | 可直接部署 |
| 适用场景 | 小规模、低频次分析 | 大规模实时分析 |

在线API与离线IP数据库部署方案对比架构图
对于处理直播间数万乃至数十万并发观众IP的高频场景,离线IP数据库部署 是更为稳健的选择。
3.2 技术实现:基于ip2region的地域分析工具
以下代码使用 IP数据云 离线数据库(.mmdb格式),实现一个完整的电竞观众地域分析器。该工具支持从日志中提取IP、批量查询归属地,并输出多维度统计报告。
import re
import json
from collections import defaultdict
from ipdatacloud.ip import Ip
class EsportsAudienceAnalyzer:
"""电竞观众IP属地分析器(基于IP数据云离线数据库)"""
def __init__(self, db_path="ip2region.xdb"):
"""初始化:加载离线IP数据库"""
try:
self.db = Ip(filePath=db_path, method="content")
except Exception as e:
raise RuntimeError(f"加载数据库失败: {e}")
def extract_ips_from_log(self, log_file_path):
"""从直播访问日志中提取IP地址(去重+基础校验)"""
ip_pattern = re.compile(r'\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}\b')
ips = set()
try:
with open(log_file_path, 'r', encoding='utf-8') as f:
for line in f:
found = ip_pattern.findall(line)
for ip in found:
parts = ip.split('.')
try:
if all(0 <= int(p) <= 255 for p in parts):
ips.add(ip)
except ValueError:
continue
except (FileNotFoundError, PermissionError) as e:
print(f"读取日志文件失败: {e}")
return list(ips)
def _parse_region_string(self, region_str):
"""解析 ipdatacloud 返回的管道符分隔字符串"""
# 返回格式:洲|国家|省份|城市|区县|运营商|区域代码|...
parts = region_str.split('|')
return {
"continent": parts[0] if len(parts) > 0 else "",
"country": parts[1] if len(parts) > 1 else "",
"province": parts[2] if len(parts) > 2 else "",
"city": parts[3] if len(parts) > 3 else "",
"district": parts[4] if len(parts) > 4 else "",
"isp": parts[5] if len(parts) > 5 else ""
}
def batch_query_region(self, ips):
"""批量查询IP归属地,返回结构化数据"""
results = []
for ip in ips:
try:
region_str = self.db.get(ip)
parsed = self._parse_region_string(region_str)
results.append({"ip": ip, **parsed})
except Exception as e:
results.append({"ip": ip, "error": str(e)})
return results
def analyze_audience_distribution(self, results):
"""分析观众地域分布(国家/省份/城市/运营商)"""
stats = {
"by_country": defaultdict(int),
"by_province": defaultdict(int),
"by_city": defaultdict(int),
"by_isp": defaultdict(int)
}
for r in results:
if "error" not in r:
if r.get("country") and r.get("country") not in ["", "0"]:
stats["by_country"][r["country"]] += 1
if r.get("province") and r.get("province") not in ["", "0"]:
stats["by_province"][r["province"]] += 1
if r.get("city") and r.get("city") not in ["", "0"]:
stats["by_city"][r["city"]] += 1
if r.get("isp") and r.get("isp") not in ["", "0"]:
stats["by_isp"][r["isp"]] += 1
return stats
def export_report(self, stats, output_file="audience_report.json"):
"""导出分析报告为JSON文件"""
report = {
"total_unique_ips": sum(stats["by_country"].values()),
"distribution": {
"country": dict(stats["by_country"]),
"province": dict(stats["by_province"]),
"city": dict(stats["by_city"]),
"isp": dict(stats["by_isp"])
}
}
with open(output_file, 'w', encoding='utf-8') as f:
json.dump(report, f, ensure_ascii=False, indent=2)
print(f"报告已导出至 {output_file}")
return report
# 使用示例
if __name__ == "__main__":
analyzer = EsportsAudienceAnalyzer("ip2region.xdb")
sample_log = """
2026-04-10 20:00:15 用户 223.104.12.34 访问 T1 vs Gen.G 直播间
2026-04-10 20:01:22 用户 36.112.28.156 发送弹幕 "T1冲"
"""
with open("access.log", "w") as f:
f.write(sample_log)
ips = analyzer.extract_ips_from_log("access.log")
print(f"提取到 {len(ips)} 个唯一IP地址: {ips}")
results = analyzer.batch_query_region(ips)
stats = analyzer.analyze_audience_distribution(results)
report = analyzer.export_report(stats)
print("\n地域分布统计:")
print(json.dumps(report, ensure_ascii=False, indent=2))
运行前提 :
- 安装依赖:pip install ipdatacloud
- 从 IP数据云 官网或官方PyPI获取离线数据库文件,放置于脚本同目录。
3.3 代码说明
上述分析工具实现了完整的数据处理链路:
- IP提取模块 :使用正则表达式从各类日志文件中提取IP地址,支持访问日志、弹幕日志、登录日志等多种格式;
- 批量查询模块 :调用离线IP数据库逐条查询,单次查询耗时在毫秒级,支持百万级IP批量处理;
- 统计模块 :从省份、城市、运营商等多个维度聚合观众分布数据;
- 导出模块 :将分析结果输出为JSON格式,便于下游BI系统对接或生成可视化报表。

四、落地实践:从地域分析到商业决策
4.1 观众画像的三大应用场景
场景一:精准营销投放。 通过分析观众IP归属地,运营团队可以识别出高活跃度城市的用户特征,在这些城市针对性地投放线下观赛活动广告,或邀请当地KOL参与赛事推广。
场景二:赛事内容本地化。 不同城市观众对战队、选手的偏好存在差异。IP归属地运营商信息和ASN数据可以帮助运营方识别各地区观众的设备与网络环境差异,为不同地区的用户提供差异化的直播画质与解说内容。
场景三:反作弊与风险识别。 在互动环节(如投票、抽奖)中,通过IP归属地与用户注册地的交叉验证,可以有效识别异常流量和机器人刷量行为。
4.2 效果数据参考
某游戏平台采用IP归属地城市级离线库后,通过来访玩家登录的IP地址解析地理位置信息,统计用户来源地和活跃玩家分布,为市场决策提供了精准数据支撑。
五、技术选型建议
在构建电竞观众地域分析系统时,开发者需要在IP归属地API 和离线IP数据库部署 之间做出合理选择:
- 若分析任务为低频次(如每月一次的用户画像统计),可直接调用IP归属地查询平台 的在线API;
- 若需要在直播间实时展示观众地域分布热力图,或需要高频批量处理IP日志,离线IP数据库部署 更为合适------数据本地存储、无调用限制、不受网络延迟影响。
在实际选型中,开发者可参考IP数据云等离线数据库服务商的更新频率与覆盖范围,结合业务场景选择合适方案。
六、行业前瞻
随着中韩电竞交流的持续深化,观众地域分析将从"宏观统计"走向"精细化运营"。LCK事务总长李正勋指出,LCK不再局限于韩国本土,而是作为全球化内容被消费,下一阶段的关键不在于观看人数多少,而在于能否与粉丝建立深度连接。
对数据分析从业者而言,IP归属地信息正从单纯的"位置标签"演变为精细化用户运营的数据基石 。通过离线数据库与在线API的合理组合,辅以多维度交叉分析,电竞观众的地域画像将不再是一张静态的分布图,而是一张可实时更新的商业决策地图。
本文引用的行业数据截至2026年4月,来源于公开研究报告与行业分析,供技术交流参考。