Введение: зачем разработчику карта всех маяков мира?

Когда в пятницу вечером коллега-бэкендер задумчиво отправляет в чат ссылку на карту береговой охраны, у нормальных людей возникает желание спланировать отпуск у моря. У веб-разработчика же загораются глаза от другой мысли: «Интересно, а сколько запросов упадет база, если отрендерить их все одновременно?». (А главное — почему это падает на стейдже, но отлично работает на вашей машине). Представьте, что вы решили запустить свой Open Source проект «A map of every lighthouse» — интерактивный атлас всех навигационных огней планеты. Прямо сейчас это идеальный полигон, чтобы прокачать навыки сбора неструктурированных данных, очистки датасетов, работы с пространственными индексами и оптимизации рендеринга тысяч маркеров на веб-карте.

Исторически сложилось так, что навигационные огни находятся в ведении суверенных государств: Береговой охраны США (USCG), Британского адмиралтейства, международных ассоциаций маячных служб и сотен локальных портовых управлений. Единой, чистой и централизованной базы данных «всех маяков мира» в формате JSON или GeoJSON не существует. Разработчику предстоит собрать эту мозаику самостоятельно.

В этой статье мы подробно разберем архитектуру такого проекта: от поиска и парсинга разрозненных источников до оптимизации базы данных PostGIS и фронтенд-визуализации с использованием современных веб-технологий. Мы рассмотрим реальные примеры кода на Python и JavaScript, а также обсудим подводные камни работы с координатами и морскими навигационными стандартами.

Но прежде чем писать код, давайте разберем главное препятствие: где взять исходные данные и как не утонуть в их разнородности?

1. Источники данных и стратегия парсинга: собираем разрозненные пазлы

Первый и самый трудоемкий этап создания глобальной карты маяков — это агрегация информации. Поскольку единого API не существует, приходится комбинировать открытые государственные реестры, краудсорсинговые базы и специализированные морские порталы.

Основные источники, которые использует дата-инженер:

  • OpenStreetMap (OSM): Крупнейшая краудсорсинговая база геоданных. Тег seamark:type=lighthouse содержит тысячи точек по всему миру с базовыми атрибутами.
  • NGA (National Geospatial-Intelligence Agency): Издает официальный «List of Lights» (публикации 110–116), содержащий технические характеристики огней, высоту фокальной плоскости и дальность видимости.
  • Национальные ведомства: Данные береговой охраны США, Канады, Австралии и европейских стран, часто доступные в виде CSV-файлов или через государственные ArcGIS REST API.

Для автоматизации сбора данных из правительственных реестров в формате PDF или таблиц Excel пишется скрипт на Python с использованием библиотек requests, BeautifulSoup и geopandas. Ниже приведен пример надежного парсера, который извлекает координаты маяков из открытого API и приводит их к единому стандарту.

import requests
import json

def fetch_lighthouses_from_api(endpoint_url):
    headers = {'User-Agent': 'LighthouseMapBot/1.0 (admin@coffee-web.ru)'}
    try:
        response = requests.get(endpoint_url, headers=headers, timeout=10)
        response.raise_for_status()
        data = response.json()
        
        lighthouses = []
        for item in data.get('features', []):
            props = item.get('properties', {})
            coords = item.get('geometry', {}).get('coordinates', [])
            
            if len(coords) == 2:
                lighthouses.append({
                    "name": props.get('NAME', 'Unknown Lighthouse'),
                    "lat": coords[1],
                    "lon": coords[0],
                    "range_nm": props.get('RANGE_NM', None)
                })
        return lighthouses
    except requests.exceptions.RequestException as e:
        print(f"Ошибка при запросе к API: {e}")
        return []

# Пример использова (дописывать код на Stack Overflow мы, конечно же, не будем — напишем свой)