![](https://habrastorage.org/webt/a0/8u/mi/a08umi6_8yn4eobkvs63zv_s9tq.jpeg)
Автор: Михаил Аксенов, .NET Developer, DataArt
- Сайт проекта Vrnbus (Автобусы Воронежа);
- Telegram-бот: @vrnbusbot;
- GitHub проекта: vrntrans/vrnbus.
С чего все началось
Осенью 2014 года появилась радостная новость о том, что в Воронеже заработал Яндекс.Транспорт, который показывает движение автобусов и троллейбусов. Было очень круто прямо на остановке открыть расписание и узнать, что ваш автобус подойдет через 5 минут.
Но уже через пару месяцев все пошло по вполне предсказуемому сценарию. Поскольку весь транспорт в Воронеже от троллейбуса до маршрутки работает «на наличке», каждый водитель заинтересован в том, чтобы перевезти как можно больше пассажиров. В результате они устраивают гонки между собой.
Новый сервис водители использовали, чтобы следить друг за другом по карте, обгоняя и подрезая конкурентов на дороге. У некоторых начала падать выручка, они стали жаловаться владельцам маршрутов, а те пошли к людям, продающим оборудование с ГЛОНАСС и GPS и отправляющим данные о перемещениях машин в Яндекс. По просьбам хозяев автопарков они информацию отправлять перестали, и автобусы сразу начали исчезать с карты. Сейчас их стало чуть побольше, но это все равно гораздо меньше, чем на самом деле.
![](https://habrastorage.org/webt/hy/2p/d9/hy2pd9kotq6w2jrb__n5gm8nzx0.jpeg)
Для тех, кому лень читать дальше, предлагаю видео доклада на эту тему:
Для остальных — опишу проект в виде текста.
Где взять данные?
При этом в в Воронеже есть место, где собираются все данные — Центр Организации Дорожного Движения (ЦОДД). У них на сайте есть большое и тяжелое веб-приложение с неотлаженным JavaScript и прочими артефактами, при этом все в нем идет POST-запросами и ничего не кешируется. С помощью самого этого сайта можно запросто положить сервис, который собирает данные о передвижении автобусов.
Там имелась опция, позволяющая ткнуть на карту и узнать, когда придет автобус и каким он будет. При условии, что вы приблизительно попадаете в остановку (± 50 метров). В меню можно было открыть список маршрутов и посмотреть, где именно ездят автобусы, но там была проблема — ездили они странно. Например, по Кольцовской, улице в центре, где особенно не разгонишься, автобус перемещался вперёд и назад со скоростью примерно 200 км/ч.
Почему Python?
Я выбрал Python потому что он классный, батарейки в комплекте, и т. д. А 3.6 потому, что здесь есть форматирование строковых литералов, typing, вот это всё. Давайте посмотрим на то, что я в принципе использовал:
- Многие жаловались, что вбить точное название остановки со всякими знаками препинания очень тяжело. Тогда я реализовал возможность нечеткого поиска и создал для него первый юнит-тест.
- Вся система хостится на Heroku. Бесплатно, поскольку у меня нет базы данных — я надеюсь обойтись базой ЦОДДа. О ее использовании я договорился с Центром, когда понял, что данных, которые я забираю через веб-интерфейс, недостаточно.
- Собственно, хостинг идет через веб-сервер Tornado. Думаю, он знаком каждому, кто сталкивался с веб-запросами в Python.
- Пакет Pytz понадобился мне, потому что сервер Heroku находится в другом часовом поясе, а данные ко мне поступают без указания временной зоны. Поэтому я сам позаботился о локализации.
- Для создания бота я использовал рекомендованную библиотеку Python-telegram-bot. Документация здесь вполне адекватная, и вообще библиотека соответствует требованиям minimum viable product. Изначально весь проект представлял собой Telegram-бота, который в ответ на отправку вашего местоположения присылал расписание автобусов.
- Firebird, бывший Interbase — Open source база данных, с которой, полагаю, многие из вас работали. Конечно, она не такая крутая, как тот же самый PostgreSQL, но для очень большого количества запросов ее достаточно. В нашем случае большего не нужно.
- Caсhetools — очень простой модуль, который позволяет кешировать вычисления. Речь тут, конечно, не о memecached или кешировании веб-страниц, а о тех случаях, когда вам нужна мемоизация на долгие запросы. Просто берете, добавляете соответствующий декоратор — и всё работает. Кеш имеет разные варианты, я использую TTL-версию, который сохраняет данные на указанное время, потому что я знаю, что данные не будут обновляться чаще, чем через определённые промежутки времени (в моём случае — 30 секунд).
Функционал бота
- /nextbus имя остановки — ожидаемое время прибытия;
- /last номера маршрутов через пробел — последние остановки;
- Отправка местоположения — ожидаемое время прибытия для ближайших трех остановок;
- Свободный ввод — номера маршрутов и расстояние до автобусов (при отправке местоположения).
Команды я постарался описать достаточно полно, чтобы люди не спрашивали, как ими пользоваться. Базовых команд по сути две: nextbus, когда вы пишете название остановки, и отправка местоположения.
Функционал сайта
Bеб-сайт я сделал настолько минималистичным, насколько это в принципе возможно. Из сторонних библиотек использовал всего две, для поддержки fetch и promise, потому что старые версии предустановленных браузеров в телефонах не умеют обходиться без них. Если не поддержать эти методы, получится достаточно тяжелая лапша из коллбеков для самих запросов. С fetch все выглядит изящнее.
![](https://habrastorage.org/webt/vn/sd/gu/vnsdgutglxminl8j6wi07w4nkp0.jpeg)
Собственно, функционал здесь состоит из 4 пунктов:
- Прибытие. Можно просто посмотреть остановку. Нажав на кнопку (ее, кстати, может быть, стоит сделать побольше — я подумаю!), вы отправляете свое местоположение, система ищет три ближайшие к вам остановки и показывает информацию по ним. Можно ввести название остановки и получить информацию по ней. Поскольку вам вряд ли нужны все 20–30 автобусов, которые могут приехать к остановке, вы можете отфильтровать их по маршрутам.
- Автобусы. На второй странице собрана информация по автобусам. Это связано еще с одной историей, подтолкнувшей меня к этому проекту. В один прекрасный день я забыл в автобусе шапку, позвонил в диспетчерскую, объяснил, где это случилось. Диспетчер предложил мне ловить свой автобус в центре, куда он вернется, развернувшись на конечной. Я вспомнил, что у меня есть логин и пароль от системы Центра организации дорожного движения, но оказалось, что отследить местоположение нужной мне машины я через веб-интерфейс все равно не могу. Шапку я вернул, но с большим трудом.
Я подумал, что поиск автобуса мог бы быть гораздо проще. Написал номер маршрута, а система показывает тебе машины на линии, их текущее местоположение и время, когда они проходили остановки по пути. И даже если вы знаете номер маршрута, но вы знаете номер автобуса (такое тоже бывает), вы все равно сможете его найти. - Карта. Карта на сайте без анимации. Здесь можно выбирать автобусы из списка или вводить номера вручную, можно их отфильтровать. На карте могут быть показаны до 600 автобусов, хотя уже после 20 найти что-то в центре становится сложно, просто потому, что маршруты все сконцентрированы здесь. Поэтому лучше ограничивать поиск параметрами более жестко.
- О проекте. Сейчас у проекта есть сайт, есть Telegram-бот, группы в соцсетях.
***
К счастью, Python — это язык с батарейками из коробки. Для несложных вещей, вам даже ничего скачивать не нужно, достаточно внимательно прочитать документацию.
Разумеется, такие сервисы можно делать и для других городов, более того, в некоторых они уже работают. Многое зависит от местного ЦОДД, кое-где, например, в Санкт-Петербурге есть даже API для разработчиков. Но самое главное — горожане, которые хотят менять свой город к лучшему.