开源波罗的海影子舰队追踪器。追踪1200+艘船只,提供实时AIS数据与海底电缆接近警报。无需云端、无需订阅,本地运行。
通过实时AIS数据监控波罗的海影子舰队。跟踪1200+艘来自乌克兰GUR战争与制裁目录的船只,对接AISStream WebSocket数据流,在自动更新的地图上标绘位置,标记靠近海底电缆的船只,并检测俄罗斯↔西方的转运模式。
免费、开源、本地运行。无云服务,除了免费的AISStream API密钥外无需订阅。
属于Former Lab主权情报工具链的一部分。
影子舰队追踪器·轻量版由Former Lab团队构建和维护——主权计算,在旧硬件上构建开放、隐私优先的工具,无风险投资支持。
如果此工具对您有用,请考虑在Patreon上支持我们。提供免费层级,付费层级提供7天试用。始终支持乌克兰!
关于追踪器的博文、截图等: https://www.patreon.com/posts/153285871
git clone https://github.com/FormerLab/shadow-fleet-tracker-light.git
cd shadow-fleet-tracker-light
pip install -r requirements.txt
export AISSTREAM_API_KEY=your_key_here # 在aisstream.io免费获取
python shadow_tracker.py &
uvicorn webserver:app --host 0.0.0.0 --port 8000
打开http://localhost:8000——地图在/map。
Windows用户:请参阅设置部分了解PowerShell/cmd环境变量语法。
Linux/macOS用户可使用start.sh。Windows用户可使用start.bat或start.ps1——两者都会在独立窗口中打开追踪器和仪表板,并自动启动浏览器。
Vessels1.db)获取的1200+艘船只的MMSI监视列表过滤数据流filtered_cables.kml)10公里范围内时发出警报深色CartoDB底图,电缆路线以绿色叠加。船只标记每3分钟更新一次,并附带下次刷新的实时倒计时——页面自动重新加载。弹出信息显示MMSI、IMO、船旗国、速度、航向、目的地,以及指向MarineTraffic、VesselFinder和War&Sanctions的深层链接。如果配置了API密钥,还将显示OpenSanctions制裁状态。
Vessels1.db中已知的船名在首次出现时立即显示,无需等待AIS静态消息。
启动时,地图会从最近24小时的位置日志中预填充数据。当前会话中尚未出现的船只以灰色标记显示,并标注“上次见X小时前”——当新数据到达时,它们会过渡为活跃颜色。
shadow_tracker.py 主进程 — WebSocket消费者、地图渲染器、数据库写入
loitering_module.py 徘徊检测与地图标注
transshipment_module.py 港口停靠检测与俄罗斯↔西方转运标记
webserver.py FastAPI仪表板
gur_scrape.py 一次性爬取器 — 构建IMO→GUR-ID映射 + 完整船只目录
check.py 预检 — Python版本、依赖、API密钥、网络
start.sh Linux/macOS启动器
start.bat Windows启动器(命令提示符)
start.ps1 Windows启动器(PowerShell)
requirements.txt 依赖列表
Vessels1.db 监视列表 — 1200+艘船只(MMSI + IMO + 名称(如已知))
vessel_data_log.db 位置日志 — 运行时追加写入
vessel_static.db AIS静态数据缓存(名称、目的地、船旗国历史)
transshipment.db 港口停靠日志与转运事件
loitering_events.db 徘徊事件
filtered_cables.kml 波罗的海海底电缆几何数据
cables.kml 完整电缆数据集(预过滤源)
gur_mapping.json IMO→GUR-ID映射(由gur_scrape.py生成,可选)
gur_vessels_full.json 完整GUR目录 — GUR-ID→{imo, mmsi, name, flag}(由gur_scrape.py生成)
Vessels1.db是被追踪船只的权威列表。包含1200+条记录,来自乌克兰GUR战争与制裁目录,涵盖被认定为俄罗斯影子舰队或涉及波罗的海混合活动的油轮和货船。
列表包括最近被波罗的海当局扣押或拦截的船只:
MMSI已根据当前AIS数据进行校正——影子舰队船只频繁更改船旗。update_vessels_2026_03.sql文件记录了所有变更及其来源。
监视列表有意保持开放。可在追踪器运行时直接向Vessels1.db添加船只——它们将在5分钟内被识别,无需重启。
Linux / macOS:
sqlite3 Vessels1.db "INSERT OR IGNORE INTO vessels (mmsi, imo, name) VALUES ('123456789', '9999999', 'VESSEL NAME');"
Windows(无需sqlite3 CLI):
import sqlite3
conn = sqlite3.connect("Vessels1.db")
conn.execute("INSERT OR IGNORE INTO vessels (mmsi, imo, name) VALUES ('123456789', '9999999', 'VESSEL NAME')")
conn.commit()
conn.close()
Vessels1.db — 监视列表
vessels(mmsi TEXT PK, imo TEXT, name TEXT, destination TEXT)
vessel_data_log.db — 位置日志
vessel_data_log(timestamp, mmsi, name, imo, destination, speed, heading, latitude, longitude, cable_alert)
追加写入。每次地图渲染周期写入。
vessel_static.db — AIS静态数据缓存
vessel_static(mmsi TEXT PK, name TEXT, imo TEXT, destination TEXT, flag TEXT)
flag_history(id, mmsi, flag, timestamp)
从实时ShipStaticData AIS消息填充。一旦收到,优先级高于Vessels1.db中的名称。flag_history记录每次船旗变更及时间戳——船旗变更事件被记录并显示在每艘船只的页面上。
loitering_events.db — 徘徊日志 (运行时创建)
loitering_events(id, mmsi, timestamp, latitude, longitude, near_cable)
transshipment.db — 港口停靠与转运日志 (运行时创建)
port_calls(id, mmsi, name, port, port_type, entry_ts, exit_ts, min_speed)
transshipment_events(id, mmsi, name, direction, from_port, from_exit_ts,
to_port, to_entry_ts, days_between, detected_ts)
requirements.txt中的依赖运行追踪器的最简单方式。每个脚本都会安装依赖、执行预检,并启动两个进程。
Linux / macOS:
chmod +x start.sh
export AISSTREAM_API_KEY=your_key_here
./start.sh
Windows (PowerShell):
$env:AISSTREAM_API_KEY = "your_key_here"
.\start.ps1
Windows (命令提示符):
set AISSTREAM_API_KEY=your_key_here
start.bat
所有三个脚本都会首先运行check.py——一个预检程序,验证Python版本、依赖、数据文件、API密钥和网络可达性,并在缺少任何项时给出清晰的错误信息。
您也可以随时单独运行预检:
python check.py
1. 克隆并安装依赖
git clone https://github.com/FormerLab/shadow-fleet-tracker-light.git
cd shadow-fleet-tracker-light
pip install -r requirements.txt
在Ubuntu 22.04+和Debian 12+上,您可能会遇到pip的“外部管理环境”错误。启动脚本会通过创建虚拟环境自动处理——只需运行start.sh即可。如果手动安装,请先创建venv:
python3 -m venv .venv
source .venv/bin/activate # Linux/macOS
.venv\Scripts\activate # Windows
pip install -r requirements.txt
2. 设置您的AISStream API密钥
Linux / macOS:
export AISSTREAM_API_KEY=your_key_here
export OPENSANCTIONS_API_KEY=your_key_here # 可选
Windows (命令提示符):
set AISSTREAM_API_KEY=your_key_here
set OPENSANCTIONS_API_KEY=your_key_here
Windows (PowerShell):
$env:AISSTREAM_API_KEY = "your_key_here"
$env:OPENSANCTIONS_API_KEY = "your_key_here"
3. 在两个终端分别运行追踪器和仪表板
终端1 — AIS数据流消费者:
python shadow_tracker.py
终端2 — Web仪表板:
uvicorn webserver:app --host 0.0.0.0 --port 8000
4. 打开仪表板
http://localhost:8000
实时地图位于http://localhost:8000/map,每3分钟更新一次。首次运行时,地图会立即从数据库中已有位置历史渲染——无需空白等待。
| 服务 | 必需 | 免费层级 | 链接 |
|---|---|---|---|
| AISStream | 是 | 是 — 非商业用途无限制 | aisstream.io |
| OpenSanctions |
如果没有OPENSANCTIONS_API_KEY,追踪器正常运行——地图弹出信息中仅不显示制裁徽章。
所有可调参数位于shadow_tracker.py文件顶部:
环境变量:
| 变量 | 必需 | 描述 |
|---|---|---|
AISSTREAM_API_KEY | 是 | AISStream WebSocket API密钥 |
OPENSANCTIONS_API_KEY | 否 | 在地图弹出信息中启用制裁查询 |
OpenSanctions对非商业用途免费——在opensanctions.org/api注册。无密钥时追踪器正常运行;弹出信息中省略制裁字段。
war-sanctions.gur.gov.ua是乌克兰GUR的影子舰队和受制裁船舶公开目录。每艘船都有一个编号页面,包含港口停靠历史、地图和制裁详情。
gur_scrape.py通过一次性爬取目录构建本地IMO→GUR-ID映射:
python gur_scrape.py
这将生成gur_mapping.json。追踪器在启动时加载该文件,并在地图弹出信息中使用直接的深层链接(/en/transport/ships/{id}),如果不可用则回退到Google站点搜索。
爬取覆盖约1600条记录,每个请求1.5秒(约40分钟)。随着目录增长,可定期重新运行——使用--start从特定ID恢复:
python gur_scrape.py --start 1580
调试单个页面:
python gur_scrape.py --probe 1517
gur_mapping.json会与监视列表一起每5分钟自动重新加载——重新爬取后无需重启追踪器。
loitering_module.py中的徘徊阈值:
| 常量 | 默认值 | 描述 |
|---|---|---|
SPEED_THRESHOLD_KN | 0.5节 | 低于此速度视为停止 |
TIME_THRESHOLD_S |
transshipment_module.py中的转运设置:
| 常量 | 默认值 | 描述 |
|---|---|---|
SPEED_THRESHOLD_KN | 1.5节 | 在港口区域内低于此速度视为一次停靠 |
MIN_PINGS_IN_ZONE |
覆盖的港口区域:
| 港口 | 类型 |
|---|---|
| 乌斯季卢加、普里莫尔斯克、圣彼得堡、维堡 | 俄罗斯出口终端 |
| 斯卡恩/斯卡根、哥德堡、基尔、哥本哈根、奥胡斯 | 西方转运枢纽 |
每艘船只的页面(/vessel/<mmsi>)显示:
根据位置数据推断两种模式:
港口停靠从位置ping推断——无需外部API。船只必须在港口区域内以<1.5节速度至少ping两次才能记录为一次停靠。这显示的是模式,而非最终结论。
filtered_cables.kml源自开源数据集,为近似数据——不适用于精确的近接计算。10公里的警报阈值已考虑到这一误差。欢迎提供改进的电缆几何数据。
追踪器在WebSocket流上运行一个异步循环。状态保存在内存中(vessel_info、static_cache),并在每个渲染周期刷新到SQLite。地图通过os.replace原子写入,以避免提供不完整的文件。
启动时,warm_restart()从vessel_data_log.db读取最近WARM_RESTART_HOURS小时的数据,并在WebSocket连接前预填充vessel_info。初始地图立即渲染。过时位置在视觉上被区分(灰色标记、暗淡轨迹),并在新ping到达时过渡到活跃颜色。
监视列表和gur_mapping.json每5分钟从磁盘重新加载——可在追踪器运行时添加船只和重新爬取GUR映射,无需重启。
Web服务器是无状态的,直接从SQLite文件读取——与追踪器进程不共享内存。
| 船只 | IMO | 事件 |
|---|
| EAGLE S | 9329760 | 芬兰2024年12月扣押 — Estlink-2电缆破坏,发现间谍设备 |
| EVENTIN | 9308065 | 德国2025年1–3月扣押 — 在吕根岛附近漂流,10万吨俄罗斯原油被没收 |
| KIWALA | 9332810 | 爱沙尼亚2025年4月扣留 — 无船旗,受欧盟/英国制裁 |
| JAGUAR | 9293002 | 爱沙尼亚2025年5月拦截 — 俄罗斯出动Su-35护航 |
| KIRA K | 9346720 | 确认2025年12月船上有瓦格纳/GRU船员 |
| QENDIL | 9310525 | 2025年9月瓦格纳/GRU船员 — 2025年12月遭乌克兰无人机袭击 |
| FITBURG | 9250397 | 芬兰2025年12月31日扣押 — 赫尔辛基-塔林电缆破坏 |
| CAFFA | 9143611 | 瑞典2026年3月6日扣押 — 盗窃乌克兰谷物,挂假旗 |
| SEA OWL I | 9321172 | 瑞典2026年3月12日扣押 — 受欧盟制裁,假科摩罗船旗 |
| 否 |
| 是 — 非商业用途 |
| opensanctions.org/api |
| 常量 | 默认值 | 描述 |
|---|
BALTIC_BBOX | 52.65–66°N, 9–30°E | AISStream订阅边界框 |
CABLE_ALERT_KM | 10 | 电缆接近阈值(公里) |
MAP_RENDER_INTERVAL | 180秒 | 地图刷新周期 |
MMSI_RELOAD_INTERVAL | 300秒 | 从数据库重新加载监视列表 |
WARM_RESTART_HOURS | 24 | 启动时加载的位置历史小时数 |
RECONNECT_DELAY | 10秒 | WebSocket重连退避时间 |
| 1200秒 |
| 标记为徘徊前的持续时间 |
RADIUS_THRESHOLD_KM | 0.5公里 | 视为同一位置的最大漂移距离 |
| 2 |
| 记录一次港口停靠前的最少ping次数 |
WINDOW_DAYS | 21 | 标记为转运的最长港口停靠间隔天数 |
| 路由 | 描述 |
|---|
/ | 实时日志查看器,每60秒自动刷新 |
/map | 最新渲染的地图(支持iframe嵌入) |
/analyze | 可过滤的船只记录表,支持CSV导出 |
/timeline | 活动概览——每艘被追踪船只一张卡片,按最近出现时间排序 |
/vessel/<mmsi> | 每艘船的历史:AIS信号中断、电缆接近、船旗变更、GPX导出 |
/vessel/<mmsi>/gpx | GPX轨迹导出——可在QGIS、OpenStreetMap、GPSBabel中打开 |
/loitering | 徘徊事件,包含近电缆标记、按船只汇总、CSV导出 |
/transshipment | 俄罗斯↔西方港口停靠模式——RU→WEST和WEST→RU事件,CSV导出 |
/log/download | 原始日志文件下载 |
| 组件 | 状态 |
|---|
| AIS流消费者 | 工作中 |
| 监视列表 | 1200+艘船只(完整GUR目录) |
| 电缆接近警报 | 工作中 |
| 徘徊检测 | 工作中 |
| 转运检测 | 工作中 — 从位置推断港口停靠,21天窗口 |
| 地图渲染 | 工作中 — 3分钟周期、实时倒计时、自动重新加载 |
| 热启动 | 工作中 — 从最近24小时日志预填充地图 |
| 船只弹出信息 | MarineTraffic + VesselFinder + War&Sanctions直接链接(已映射1337艘船) |
| 船只弹出信息 | OpenSanctions制裁状态(可选,需API密钥) |
| 船旗变更检测 | 工作中 — 记录变更,存储在flag_history中 |
| 仪表板 — 日志、船只、CSV导出 | 工作中 |
| 仪表板 — 时间线视图 | 工作中 |
| 仪表板 — 每艘船只历史+GPX | 工作中 |
| 仪表板 — 航线回放 | 工作中 — 播放/暂停/重置、速度控制、电缆警报高亮 |
| 仪表板 — 徘徊面板 | 工作中 |
| 仪表板 — 转运面板 | 工作中 |