Все библиотеки Петербурга: от списка адресов до интерактивной карты
Исследования

Все библиотеки Петербурга: от списка адресов до интерактивной карты

Рассказываем, как мы превратили текстовый список адресов в рабочую интерактивную карту — без боли, но с интересными нюансами. Задача звучала просто: положить на карту все библиотеки Санкт-Петербурга, срок — "нужно было ещё вчера". Оцениваем: очистка данных — 15 минут, геокодирование — 30 минут, визуализация — "на лету". Итого — час. Погнали...

Источник данных выбрали очевидный — Википедия. Там есть список из библиотек с адресами. Казалось бы, бери и мапь. Но адреса — это текст, а карта нуждается в координатах.

Википедия даёт нам строки вида:

Санкт-Петербург, наб. реки Фонтанки, д. 44
Санкт-Петербург, В. О., линия 21-я, д. 2
Санкт-Петербург, пос. Комарово, ул. 3-я Дачная, д. 8

Петербургская специфика адресов создаёт дополнительные сложности:

  • «В. О.» — это Васильевский остров, и не всякий геокодер поймёт аббревиатуру
  • «линия 21-я» — петербургская особенность, в других городах такого нет
  • «пос. Комарово» — это уже Курортный район, но формально Санкт-Петербург
  • «д. 16/7» — дробные номера домов
  • «корп. 2», «корп. 1» — корпуса важны для точности

Выбор пал на Yandex Geocoder — как самый «петербургский» из всех. Он действительно понимает «В. О.» как Васильевский остров и знает про линии. Ии самое главное — Yandex Geocoder API позволяет отправлять запросы пакетно. Обернули в удобный веб-интерфейс и для каждого адреса получили:

  • lat, lon — координаты
  • precision — точность (exact, number, street, etc.)
  • kind — тип объекта (house, street, metro...)

Техническая реализация

import requests
import json
import time
API_KEY = ‘your_yandex_api_key’
def geocode_address(address):
   """Геокодирование одного адреса через Yandex Geocoder"""
   url = "https://geocode-maps.yandex.ru/1.x/"
   params = {
       'apikey': API_KEY,
       'geocode': address,
       'format': 'json',
       'results': 1
   }
   
   response = requests.get(url, params=params)
   data = response.json()
   
   try:
       feature = data['response']['GeoObjectCollection']['featureMember'][0]['GeoObject']
       coords = feature['Point']['pos'].split()
       precision = feature['metaDataProperty']['GeocoderMetaData']['precision']
       
       return {
           'address': address,
           'lat': float(coords[1]),
           'lon': float(coords[0]),
           'precision': precision,
           'name': feature['name']
       }
   except (IndexError, KeyError):
       return {'address': address, 'error': 'not_found'}

# Пакетная обработка с задержкой (лимиты API)
addresses = [...]  # список из 100+ адресов
results = []
for addr in addresses:
   result = geocode_address(addr)
   results.append(result)
   time.sleep(0.2)  # не превышаем лимиты

Итоговая карта покрывает 100+ библиотек — от Российской национальной библиотеки на Московском проспекте до библиотеки-филиала в посёлке Комарово.

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

Что дальше?

  • Добавить атрибутику — часы работы, контакты, фотографии
  • Построить изохроны — зоны доступности «15 минут пешком до библиотеки»
  • Сравнить с данными Росстата — проверить, все ли библиотеки из официальных реестров попали на карту

Задача, которая могла растянуться на несколько дней, заняла менее часа. Иногда «взять готовое и преобразовать» — лучшая стратегия, чем собирать данные с нуля. Особенно когда речь идёт о городской инфраструктуре. Код геокодера выложили здесь — может, кому-то пригодится для аналогичных задач. Код написан на Python/Flask, деплой на Heroku/VPS занимает 10 минут.