Давным-давно, примерно с год назад, когда Московское метро ломалось в рандомных местах и удивительно часто, у нас ( dcoder_mm & Irenica ) возникла мысль: сделать какой нибудь сервис, для оповещения о поломках.
Вам эта идея может показаться странной, dcoder_mm тоже так казалось, до тех пор, пока сам в одну из таких поломок не попал. Стоять на переполненной платформе 10 минут в ожидании поезда, как оказалось неприятно, да так, что впредь решил так не попадаться.
После этого происшествия решили полистать twitter: пишут ли что-нибудь о происшествиях в метро. Как выяснилось, пишут. Причем первые твиты об этом были минут за 10 до того как зашел в метро.
Тут потихоньку и начала зарождаться идея: собираем информацию из twitter, ищем упоминания поломок метро и оповещаем пользователя, если что-то нашлось.
Правда потом эта идея была заброшена на долгое время, но осенью 2014 мы снова о ней вспомнили — метро опять стало регулярно ломаться.
В качестве способа оповещения решено было использовать смс. Можно было, конечно, использовать что-то другое, хоть твиттер-бота для аггрегации сообщений о метро завести, но у смс есть одно преимущество — они доходят даже когда нет нормального подключения к интернету. А в метро его часто не бывает, но при этом GSM ловится нормально. (Когда мы начали делать сервис, Wifi во всем метро еще не было).
Дело оставалось за малым — собственно, сделать парсилку твитов и отправку смс.
Для проверки боем был написан простенький однострочный скрипт, получающий через поиск (curl search.twitter.com) последние твиты с хештегом #метро, выделяющий из них нужные по ключевым словам, и отправляющий нам смс.
curl -ssl "https://twitter.com/search?f=realtime&q=%23%D0%BC%D0%B5%D1%82%D1%80%D0%BE&src=typd" | grep -E -o "js-tweet-text tweet-text.*<\/p>" | sed -e 's;[><\"=-]; ;g;s;js tweet text tweet text lang ru data aria label part 0;;g;s;/a;;g;s;\/\(a\|p\); ;g;s;\(.span\|.strong\|class\|twitter\|timeline\|link\|js display url\|invisible|\tco ellipsis\|href\|nofollow\|dir\|ltr\|data\|expanded\|url\|invisible\|tco\|ellipsis\|google&\;utm_medium\|banner&\;utm_campaign\|business_news\|target\|_blank\|title\|atreply\|pretty\| \;\|rel\|s\|?utm_source\|draggable\|false\|alt\|aria\|label\|u\|hidden\|pre\|embedded|\true\|b\|a\|qery\|orce\|hahtag_click\|hahtag\|j\|nav\|emedded\|tre\|&qot\;\|emedded\|tre\|rc\|hh\|qery\|orce\|hhtg_click\|hhtg\|img\);;g;s; ; ;g;s;
\; ;;g;s;&qot\;;;g;s;emedded;;g;s;tre;;g;s; \/ ;;g;s;hhtg_click hhtg;;g;s;hh;;g;s;qery oe;;g;s;\/tg\/[a-zA-Z]*;;g;s;tweet;;g;s;text;;g;s;lng;;g;s;nd;;g;s;prt;;g;s;http://intgrm.com\s\/[a-zA-Z]*\/;;g;s;[A-Z%a-z]*;;g;s;[\/_\/:\/?\.@&;…]*;;g;s;^[0-9]*;;g;s;[0-9]\{3,\};;g;s;^\s*;;g;s; *; ;g;s;^[0-9] ;;g;s;# ;#;g;s;[0-9 #]*$;;g' | grep -E -i "жертв|авари|ЧП|неполадки|не будет работать|закр|перебои|застрял|интервал|катастрофа|перекрыт|остановлен|простоял|битком|затык|интервал|не ходят|ремонт|приостановлено|сбой|неисправ|сломался поезд|бомб|взрыв|теракт|затруднен|приостанов|траур|давк|дым|взорв|стрел|наводнен|вода|потоп|затопил|на рельсы|не ходят|не идут|напряжение" | grep -E -i "Марьин|Достоевск|Трубн|Сретенск|Чкаловск|Римск|Крестьянск|Дубровк|Кожуховск|Печатник|Волжск|Люблин|Братиславск|Марьин|Борисов|Шипиловск|ЗябликовВаршавск|Каховск|Лесопарков|Старокачаловск|Скобелевск|Ушаков|Горчаков|БунинскРокоссовс|Черкизовс|Преображенск|Сокольн|Красносельск|Красн|Чисты|Лубянк|Охотн|Библиотек|Кропоткинск|Фрунзенск|Спортивн|Воробьёв|Университет|Вернадск|ЮгоЗападн|Западн|Юго Западн|Тропарев|Алма|Красногвардейск|Домодедовск|Орехов|Царицын|Кантемировск|Каширск|Коломенск|Автозаводск|Новокузнецк|Театральн|Тверск|Маяковск|Динам|Аэропорт|Сокол|Войковск|Водн|Речн|Пятницк|Митин|Волоколамск|Мякинин|Строгин|Крылатск|Молодежн|Кунцевск|Славянск|Побед|Смоленск|Арбат|Революц|Бауманск|Электрозаводск|Семеновск|Партизанск|Измайловск|Первомайск|Щелковск|Александровск|Смоленск|Выставочн|Международн|Студенческ|Кутузовск|Фил|Багратионовск|Филевск|Пионерск|Белорусск|Новослободск|проспект Мир|Комсомольск|Курск|Таганск|Павелецк|Добрынинск|Октябрьск|культур|Киевск|КраснопресненскМедведков|Бабушкинск|Свиблов|Ботаническ|ВДНХ|Алексеевск|Рижск|Сухаревск|Тургеневск|Третьяковск|Шаболовск|Ленинск|Академическ|Профсоюзн|Черемушк|Калужск|Беляев|Коньков| Стан |Ясенев|Новоясеневск|Жулебин|Лермонтовск|Выхин|Рязанск|Кузьминк|Текстильщик|Волгоградск|Пролетарск|Китай-город|Кузнецк|Пушкинск|Баррикадн|1905|Бегов|Полежаевск|Октябрьск[а-я ]поле|Щ[ую]кинск|Спартак|Тушинск|Сходненск|Планерн|Новокосин|Новогиреев|Перов|Энтузиаст|Авиамоторн|Ильич|Марксистск|Третьяковск|Делов|Алтуфьев|Бибирев|Отрадн|Владыкин|Петровск|Разумовск|Тимирязевск|Дмитровск|Савеловск|Менделеевск|Цветн|Чеховск|Боровицк|Полянк|Серпуховск|Тульск|Нагатинск|Нагорн|Нахимовск|Севастопольск|Чертановск|Южна|Пражск|Янгел|Аннин|Донск|арбатско-покровск| апл | син[яиюе]|таганско-краснопресненск| ткл |фиолетов[аоу][йюя]|замоскворецк| зл |зел[её]н[аоу][йюя]|серпуховско-тимизязевск| стл | сер[уоа][яйю]|сокольническ| сл | красн[аоу][яйу]|фил[её]вск| фл |голуб[аоу][йюя]|кольц|калужско-рижск| крл | рыж[еау][йюя]|калининск| кл |ж[её]лт[аоу][йюя]|оранжев[оау][йюя]|люблинск|салатов| лк |каховск|бутовск" | grep -i -v -E "лет назад|год назад|года назад|вспомнил|одесс|украин|спб|питер|петербург|санкт-петербург|повер|резиден|память|годжи|ягод|такси|окна|займ|деньг|iphone|худе|акци|скидк|порн|porn|pron|прон|диет|follow|retweet|скачать|бесплатн|курит смес|спайс|минск|истор|жизнь прекрасна|крещатник|квартир|выжил|прокуратур|киев |киеве|уголовное|Лесн|Геро Днепр|Сырецк|Черниговск|Минск|Дорогожичи|Дарниц|Оболон|Лукьяновск|Левобережн|Петровк|Золот ворот|Гидропарк|Тарас Шевченк|Дворец Спорт|Днепр|Контрактов площад|Кловск|Арсенальн|Почтов площад|Печерск|Крещатик|Майдан Независимост|Дружб Народ|площад Льв Толстог|Выдубич|Олимпийск|Славутич|Вокзальн|Дворец Украин|Осокорк|Политехническ институт|Лыбедск|Позняк|Шулявск|Димеевск|Харьковск|Берестейск|Голосеевск|Вырлиц|Нивк|Васильковск|Бориспольск|Святошин|Красн хутор|Житомирск|Ипподром|Академгородок|Теремк|париж|больниц|бостон|голос|кровь" | sort | uniq
И как ни странно, оно вполне нормально заработало. Иногда, конечно, попадались ложные срабатывания, но главное — оповещения приходили при всех мало-мальски важных поломках. И приходили быстро — значительно раньше, чем эта информация появлялась в СМИ или где нибудь еще.
Теперь, настала очередь фильтровать ложные срабатывания. Самый наглый и очевидный спам, например, реклама с хештегом #метро, не проходил, потому что не содержал ключевых слов (вроде «авария» или «поломка»). Но это не спасало, к примеру, от сообщений о поломках метро в других городах (не всегда в твите о поломке метро в Питере напишут слово «питер»). Поэтому пришлось ввести список «стоп-слов» при наличии которых сообщение не отправлялось. В него были включены некоторые названия станций других городов, ключевые слова, которые часто встречались в рекламе и т.д.
Проблему с тем, что на одно событие может приходится пара десятков твитов, и столько-же смс, решили в лоб: просто блокируем все сообщения про эту ветку метро на определенное время.
Впрочем, были и другие причины ложных срабатываний: сообщения о поломках другого транспорта (но при этом с тегом «метро»), сообщения, о старых поломках метро (пара аккаунтов пишет твиты о трагедии в метро летом 2014, так как будто это случилось только что).
Когда оно наконец-то стало более-менее стабильно работать, мы сделали веб интерфейс с возможностью регистрации по номеру телефона. Потихоньку начали подтягиваться еще люди, и естественно, в полном соответствии с законом подлости, случилось еще несколько ложных срабатываний. Чтобы больше такого не повторялось, сделали премодерацию: То есть сначала сообщения приходят нам, и если мы за пару минут не запретим их отправку, рассылаются всем остальным пользователям.
А еще у нас есть статистика. Ну, если уж ты собираешь данные, то грех не завести по ним статистику. В нашем случае это пока просто отображение количества поломок по веткам за определенный период времени. И краткое описание каждой поломки. В будущем наверное добавим еще что-нибудь, для начала надо побольше данных собрать.
В общем, кому это интересно: msk-metro.ru Вот мы. Можно считать, что проект еще на стадии от бета тестирования, поэтому если вам случайно придет левая смс — не расстраивайтесь. Мы это исправим, и в следующий раз такая-же смс точно не придет.
А живет это все на Raspberry Pi на debian.
Комментарии (52)
click0
07.05.2015 00:56-1Код мало читаем.
Для обработки текста лучше подходит awk, а не grep.dcoder_mm
07.05.2015 01:01+3Ну, так это же регулярки, они всегда нечитаемы) Тем более, это только часть кода.
click0
07.05.2015 01:08-1Даже используя регулярные выражения, переносы строк, табуляции и символ "\" сделают код более читабельным.
Вы же не собрались экономить пару байт кода скрипта в ущерб читабельности и дальнейшего рефакторинга?Irenica Автор
07.05.2015 01:15+4Или знаешь регулярные выражения или не понимаешь
Yaruson
07.05.2015 10:09+7Флеймxxx> Я умею читать чужие мысли!
Цитата #431836 — Цитатник Рунета
yyy> А я умею читать чужие регулярные выражения
xxx> Ок, ты победилclick0
07.05.2015 13:12И какая взаимосвязь?
Я вот знаю regexp и все равно, вынужден буду форматировать код для лучшей читабельности.
mtp
07.05.2015 13:01+1На мой взгляд, вполне всё читаемо, может быть, за исключением куска с точками с запятой. Более того, просмотр кода сделал излишним чтение пару абзацев последующего текста )
Irenica Автор
07.05.2015 01:14+3grep полезен если нужно быстро и просто найти строки, по заданному шаблону. Еще он может возвращать некоторую иную информацию, такую как списки имен файлов, выводить n-совпадений и много чего еще интересного и нужного.
А awk это С-подобный язык, им удобно будет читать, к примеру CSV файлы. Но он не такой простой, чтобы использовать для простых задач. Он умеет всё, что и grep, но это не всегда надо.click0
07.05.2015 13:21-1grep полезен если нужно быстро и просто найти строки
При больших текстах и файлах это не очень быстро.
Еще он может возвращать некоторую иную информацию
Вы и так результат присваиваете переменной и дальше обрабатываете.
… к примеру CSV файлы. Но он не такой простой
Вы парсите сложный html текст, форматированный CSV текст значительно проще.Irenica Автор
07.05.2015 13:25Где вы увидели тут большие тексты? html-страничка весит ну максимум 20кб
click0
07.05.2015 13:44-1html-страничка весит ну максимум 20кб
Вы хотели сказать 20KB? :)
Плотно размещенный печатный текст формата А4 занимает примерно 2KB в электронном виде.
Я раз за прогресс в росте производительности микропроцессоров, не не привык зря расходовать процессорные такты.
glazik
07.05.2015 01:55+1Здорово!
А как смски отправляете?dcoder_mm
07.05.2015 02:03Спасибо :)
Отправляем через websms.ru. Просто потому что это первое (или одно из первых) что нашлось в гугле. У них есть разнообразное api для отправки, в том числе и простыми get-запросами.
Думаем о том, чтобы приспособить старенькую нокию для отправки смс (взяв какой-нибудь жирный SMS-пакет) — это должно быть дешевлеWendor
07.05.2015 10:07+1Можно 3g модемом это еще делать. Вполне удобно.
А если прикрутить какой-нить smsd с плагином mysql, то для отправки будет достаточно вставить запись в БД.
DarkByte
08.05.2015 11:01Есть ведь сервисы, которые позволяют отправлять самому себе различные уведомления совершенно бесплатно. Насколько я помню, sms.ru имеет такую возможность. В случае подписки пользователей на уведомления предлагаем им регнуться на сайте и сообщить свой api-key. В случае малонагруженного сервиса вполне себе рабочее бесплатное решение.
Irenica Автор
08.05.2015 12:52Слишком сложная рега получается
DarkByte
08.05.2015 12:57При желании можно упростить: предупреждаем пользователя что его данные передаются третьей стороне и выводим ему капчу с сайта, остальные поля при регистрации в том сервисе заполняем самостоятельно. Чтобы быть честными с пользователем, сообщаем ему реквизиты от сайта, где его зарегистрировали, а себе в базу записываем его api-key. Это конечно уже не однострочник получится, зато бесплатно.
Irenica Автор
09.05.2015 02:12Пока что прикрутили nokia по uart смски слать о поломках. 1 телефона мало конечно, вскоре еще добавим
RoboSloNE
07.05.2015 03:38-13ИМХО как-то слабовато. Вы читаете твиттер, выгрепываете нужное и рассылаете смс через сторонний сервис — кажется, что в такой формулировке задачу способен решить простенький скрипт, написанный первокурсником в качестве лабораторной работы. И ссылки на какой-нибудь гитхаб не хватает.
И кстати, как вы монетизируетесь?Newbilius
07.05.2015 12:23+2Хорошее и полезное приложение не обязано быть люто сложным внутри. Да и то, что идея и реализация простые не означает, что в решении не будет мелких, но важных нюансов…
А вот к вопросу о планах монетизации я присоединюсь, СМС-ки то не бесплатные. Посмотрел тарифы, я так понимаю на 500+ людей разослать СМС будет стоить в районе 200 рублей, и чем больше — тем дороже. Можно кстати отказаться от СМС (или сделать его запасным вариантом) и зафигачить собственное мобильное приложение, которое будет принимать push-уведомления :-)LeshiyUrban
07.05.2015 14:24pushbullet API было бы очень круто
dcoder_mm
09.05.2015 02:10+1Поковырялись и прикрутили pushbullet-канал www.pushbullet.com/channel?tag=msk-metro-ru
mrol
07.05.2015 10:21Очень элегантное решение получилось.
А есть/будет возможность подписаться на определенные ветки метро?Irenica Автор
07.05.2015 10:26Мы как-то обсуждали такую возможность и не посчитали её нужной. Допустим работа/учеба — дом одни и те же ветки, но периодически человек может ездить по всем остальным веткам — дела, культурные мероприятия, etc
Как опционально можно и сделатьmrol
07.05.2015 10:29+1Не планируете аналогичную штуку для трамваев и троллейбусов? Они встают намного чаще, чем метро :)
Irenica Автор
15.05.2015 01:36Добавили личный кабинет, в котором можно выбрать ветки и время оповещения.
symbix
07.05.2015 11:56+2Молодцы, клево. А сделайте еще rss? Я вот, скажем, далеко не каждый день пользуюсь метро, и смски — это излишне; а вот проверить фид было бы самое то.
В идеале, конечно, вот так — www.tfl.gov.uk/tube-dlr-overground/statusIrenica Автор
07.05.2015 11:57Сделаем ))
iandarken
07.05.2015 13:17+ к RSS или возможности каким-нибуть GET получить ткущую ситуацию. Зашел в метро — стоит толпа и поезд не идет — и думай, это временная бага на 5 минут или там на рельсы Михалков упал и праздник, метро ходить не будет еще час, иди на автобус. А так ткнул кнопочку, получил инфу и решил.
alterpub
07.05.2015 14:55+1Еще можно канал на pushbullet создать, вместо смсок(или в дополнение к ним)
bobrovnikov
07.05.2015 18:06Надеюсь, не сочтёте за откровенную рекламу.
Я совсем недавно тоже сделал сервис с СМС оповещениями, только по раскрытию информации публичных компаний.
Скажем, Газпром публикует квартальный отчёт, так вот его подписчикам в течение минуты придёт эта новость вместе с ссылкой на сообщение компании. Рассчитано на весьма узкую в России аудитории участников торгов на фондовой бирже.
chernish2
09.05.2015 14:54Отличная вещь! Я Москвич, но, уверен, жителям, как минимум, Питера, такой сервис был бы тоже полезен. А ещё наверное и Минска, и Киева.
Steve_R
25.05.2015 16:24Если сообщений много, то есть смысл разделить ленты.
Irenica Автор
25.05.2015 16:27Пока что мы не знаем сколько сообщений, всё же только вчера подключили. Дорожные ситуации с dtmos.ru и они пишут не только об пробках, но и о наземном общественном транспорте. Тут надо понаблюдать на сообщениями и за предложениями пользователей.
Lol4t0
Вы надеюсь перешли на официальное twitter API, или все еще колхозите?
Там, кстати, можно больше условий на хеш-таги накладывать.
А для избежания ложных срабатываний не пробовали сделать простой пороговый фильтр?
dcoder_mm
А что подразумевается в данном случае под пороговым фильтром? Подсчет «ключевых» слов?
Lol4t0
Вообще можно много чего предложить для улучшения детектирования и отсеивания ложных тревог.
Самое простейшее — не реагировать на первое сообщение, а накапливать сообщения в течение некоторого окна времени. как только сообщений в окне становится достаточно много, генерируется событие.
Следующее улучшение — определять для каждого сообщения некоторую степень достоверности, и учитывать ее при подсчете очков.
Решением таких задач занимаются CEP в широком смысле
Irenica Автор
Прежде чем обрабатывать поломку, накапливаем некоторое количество сообщений.
На данный момент было интересно запустить проект как можно быстрее, не заморачиваясь с чем-то сложным. Интересно нужно ли это народу и в зависимости от этого будет ясно куда дальше двигаться.