From 8ba99292b7f09ffe8c72d6b76071e653bc5ccaa3 Mon Sep 17 00:00:00 2001 From: TianXuan Developer Date: Thu, 23 Jul 2026 23:59:27 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20MMDB=E4=B8=AD=E6=96=87=E8=B7=AF=E5=BE=84?= =?UTF-8?q?=E8=A7=A3=E5=86=B3=E6=96=B9=E6=A1=88=20+=20=E8=81=9A=E7=B1=BB?= =?UTF-8?q?=E4=BC=98=E5=85=88=E4=BD=BF=E7=94=A8=E6=9C=80=E6=96=B0GeoIP?= =?UTF-8?q?=E6=95=B0=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - geoip.py: maxminddb C库不支持Windows中文路径,复制MMDB到ASCII临时目录 - views.py: _cluster_network 优先用 geoip_lookup()(MMDB) 而非上传时缓存(text) - 效果: IP地理坐标从 ~55城市粗定位 → 全球百万级精确城市定位 Co-Authored-By: Claude --- analysis/geoip.py | 18 ++++++++++++++++-- simple_analysis/views.py | 5 +++-- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/analysis/geoip.py b/analysis/geoip.py index 076b42b..ca9e832 100644 --- a/analysis/geoip.py +++ b/analysis/geoip.py @@ -12,6 +12,7 @@ import bisect import gzip import logging import shutil +import tempfile from pathlib import Path from typing import Optional @@ -107,11 +108,24 @@ def _load_mmdb() -> None: try: import maxminddb - _mmdb_city = maxminddb.open_database(city_path) + + # maxminddb C extension cannot handle non-ASCII Windows paths. + # Workaround: copy MMDB files to a temp dir with ASCII-only path. + _tmp_dir = Path(tempfile.gettempdir()) / 'tianxuan_geoip' + _tmp_dir.mkdir(parents=True, exist_ok=True) + + _tmp_city = _tmp_dir / 'GeoLite2-City.mmdb' + if not _tmp_city.exists() or _tmp_city.stat().st_size != city_path.stat().st_size: + logger.info('[GEOIP] copying MMDB to ASCII-safe temp dir …') + shutil.copy2(city_path, _tmp_city) + _mmdb_city = maxminddb.open_database(str(_tmp_city)) logger.info('[GEOIP] loaded GeoLite2-City.mmdb (MMDB format)') if asn_path.exists(): - _mmdb_asn = maxminddb.open_database(asn_path) + _tmp_asn = _tmp_dir / 'GeoLite2-ASN.mmdb' + if not _tmp_asn.exists() or _tmp_asn.stat().st_size != asn_path.stat().st_size: + shutil.copy2(asn_path, _tmp_asn) + _mmdb_asn = maxminddb.open_database(str(_tmp_asn)) logger.info('[GEOIP] loaded GeoLite2-ASN.mmdb (ISP/ORG)') except Exception as e: logger.warning('[GEOIP] failed to open MMDB: %s', e) diff --git a/simple_analysis/views.py b/simple_analysis/views.py index ee1018d..72a4782 100644 --- a/simple_analysis/views.py +++ b/simple_analysis/views.py @@ -792,11 +792,12 @@ def _cluster_network(entry: dict, df: pl.DataFrame, meta: dict, logger.info('Network clustering: %d unique IPs from %d records', n_nodes, len(df)) # ── 2. GeoIP 解析所有 IP ─────────────────────────────────────────── + # MMDB优先(高精度),upload时的geo_cache兜底(低精度文本回退) node_geo = {} # ip → {lat, lon, city, country, isp, org} for ip in unique_ips: - info = geo_cache.get(ip) + info = geoip_lookup(ip) # 优先用当前加载的MMDB数据库 if not info: - info = geoip_lookup(ip) + info = geo_cache.get(ip) # 回退到上传时的缓存 if info: node_geo[ip] = info