Комментарии 66
Если желающих появится много, введут капчу (
Я бы на их месте просто бы открыл api. Я люблю api. И не люблю капчи.
… поставят проводника с флажком.
Так и не понял, что конкретно упрощает скрипт из топика.
Могу ответить, почему ответ приходит на запрос не сразу. Я сам написал скрипт обработки данных с сайта РЖД полгода назад. Точней написал я его больше года назад, но пол года назад один существенно изменили движок. Раньше приходилось парсить html, а теперь json обмен, что очень удобно.
Так вот.
В первый запрос вы никогда не получите полный ответ по билетам, т.к. база у них работает не быстро и вообще вся логика построена на очереди на запрос со стороны клиента. В первом запросе вы получаете номер сессии [rid] (можно сравнить с талончиком на получение информации) и cookie, которое нужно формально. В следующий раз вы должны прийти с этим номером сессии и cookie и спрашивать — получена ли информация. Спрашивать до упора (нужно заложить свой таймаут, хотя можно покопаться в скриптах сайта и понять, какой у них зашит, но это не принципиально. у меня лично ответ должен прийти за 25 запросов. Каждый запрос не более 5 секунд) и не важно с каким интервалом. У меня лично опрос после первого запроса — раз в секунду и никаких проблем, там никакой защиты в этом плане нет.
Кстати рекомендую делать обработку типа билетов по полю «type», хоть оно и на русском языке, что не очень удобно парсить. Раньше парсил по itype (или ittype), но номера itype могут отличаться в зависимости от направления. Не знаю, зачем оно нужно.
И кстати насчёт session_id — я лично забил на увеличение на 1 каждый запрос. Тупо шлю то, что мне в первый раз ответили.
ps. Очень рекомендую веб-дебаггер Charles — любая стандартная веб-активность там просто на лицо. Из его дебага сразу становится понятно, как работать с сайтом РЖД
Так вот.
В первый запрос вы никогда не получите полный ответ по билетам, т.к. база у них работает не быстро и вообще вся логика построена на очереди на запрос со стороны клиента. В первом запросе вы получаете номер сессии [rid] (можно сравнить с талончиком на получение информации) и cookie, которое нужно формально. В следующий раз вы должны прийти с этим номером сессии и cookie и спрашивать — получена ли информация. Спрашивать до упора (нужно заложить свой таймаут, хотя можно покопаться в скриптах сайта и понять, какой у них зашит, но это не принципиально. у меня лично ответ должен прийти за 25 запросов. Каждый запрос не более 5 секунд) и не важно с каким интервалом. У меня лично опрос после первого запроса — раз в секунду и никаких проблем, там никакой защиты в этом плане нет.
Кстати рекомендую делать обработку типа билетов по полю «type», хоть оно и на русском языке, что не очень удобно парсить. Раньше парсил по itype (или ittype), но номера itype могут отличаться в зависимости от направления. Не знаю, зачем оно нужно.
И кстати насчёт session_id — я лично забил на увеличение на 1 каждый запрос. Тупо шлю то, что мне в первый раз ответили.
ps. Очень рекомендую веб-дебаггер Charles — любая стандартная веб-активность там просто на лицо. Из его дебага сразу становится понятно, как работать с сайтом РЖД
И кстати, я что-то не понял, почему у вас code0 и code1 фиксированные. Я конечно сейчас не очень уверен, но по моему они важны для сайта ржд. Я лично забираю полный список станций с ссылки pass.rzd.ru/suggester?lang=ru&stationNamePart= (например pass.rzd.ru/suggester?lang=ru&stationNamePart=МО ) по первым двум буквам [А-Я][А-Я]. Там так же указаны коды станций.
Такой у меня интерфейсик
К сожалению не готов в паблик выкладвать, т.к. очкую что забанят мой ип от количества запросов. Да и sql инъекций там можно много сделать.
К сожалению не готов в паблик выкладвать, т.к. очкую что забанят мой ип от количества запросов. Да и sql инъекций там можно много сделать.
Да, точно. Немного отредактировал исходный код своего скрипта, спасибо за замечание и столь развернутый комментарий :)
Сайт РЖД это просто ад какой-то… Неужели из миллиардов не нашлось пару тысяч на разработку нормального сайта, а не этого ужаса с зойчем в логотипе?..
Сайты железных дорог они часто такие.
Ну знаете ли. Если всё делать как надо, то на очередное шубохранилище может и не хватить.
Шутки шутками, но если уж сравнивать…
Сайт Trainitalia до сих пор шлет мне спам. Регистрация там была сущим адом, потому что в пароле — скрытая авто-капитализация и нет фильтрования пробелов (ну и угадайте, как это обнаружить). Но даже после прохождения этих квестов я все равно не смог купить билет — сайт просто отдавал 500.
Сайт Trainitalia до сих пор шлет мне спам. Регистрация там была сущим адом, потому что в пароле — скрытая авто-капитализация и нет фильтрования пробелов (ну и угадайте, как это обнаружить). Но даже после прохождения этих квестов я все равно не смог купить билет — сайт просто отдавал 500.
я этим летом написал аналогичный скрипт чтобы взять билеты в крым. только он еще отправлял мне смс когда нужный билет появляется. ) могу скинуть кому надо, но код непричесанный (php, bash).
А как смс слал? В смысле, использовал какой-то сторонний сервис или своё что-то?
А разве сайты типа tutu.ru не так делают? Или они платят, а им дают доступ к api?
Программисты компаний по продаже билетов уже реализуют ваш хак. Через пару дней свободных билетов не будет, а через неделю РЖД закроет дыру. Получение преимуществ за чужой счет/в обход очереди — неэффективный путь. Хотя и веселый.
В студенчестве наездился в старых плацкартах. Всё-таки 48 часов из Петербурга в Пятигорск — очень утомительно. Позже перешёл на купейные вагоны. А сейчас, купе почти сравнялся по цене с самолётом, так что проблема выбора почти отпала. Летаю:) Тем более, очень жалко двух суток в дороге.
public function request($data) { ... }
$rzd->request([...]);
Ну почему не так?
public function request($from, $codeFrom, $to, $codeTo, $date) { ... }
А если еще аргументы надо будет ввести? Масштабируемо же.
Преждевременная оптимизация однако
Да тут копеечная оптимизация, всего 2 скобки лишние, почему бы сразу не ее сделать.
Потому что без документации непонятно сколько элементов должно быть в переданном массиве и их тип. Это даже не оптимизация, так делать нельзя. Плюс непонятно как делать анализ такого кода.
Если методу надо 5 строк и одно число, он должен принимать 5 строк и одно число, а не массив. Если в будущем понадобится еще аргумент, добавьте его и сделайте необязательным, чтобы ничего не сломать.
Если методу надо 5 строк и одно число, он должен принимать 5 строк и одно число, а не массив. Если в будущем понадобится еще аргумент, добавьте его и сделайте необязательным, чтобы ничего не сломать.
Вы правы в том, что «непонятно сколько элементов должно быть в переданном массиве и их тип». Для этого в самой функции обязательно надо массив переданных параметров мержить с массивом параметров по умолчанию. Такая методика вполне себе отлично работает. Широко применяется к примеру в jQuery-плагинах.
Только потом будет у нас какой-то уродец, а не функция some_function($a, $b, $c, $d, $e = null, $f = 0, $g = 'all', $h = true). Извините, но это говнокод.
Если в будущем понадобится еще аргумент, добавьте его и сделайте необязательным, чтобы ничего не сломать.
Только потом будет у нас какой-то уродец, а не функция some_function($a, $b, $c, $d, $e = null, $f = 0, $g = 'all', $h = true). Извините, но это говнокод.
Почему это говнокод? Если some_function может работать с четырьмя параметрами и с семью, то три последних должны быть необязательными, это нормальное поведение функции.
Говнокод, потому что без той же самой документации не поймешь в каком порядке надо ставить параметры. А если дальше у вас не нужны будут первые 4 параметра $a, $b, $c, $d, зато надо будет определить пятый $e? Тогда функция плавно превращается в some_function($a = 0, $b = 1, $c = false, $d = null, $e = null, $f = 0, $g = 'all', $h = true) и будете писать some_function(0, 1, false, null, $foobar). Вообще, больше 4 параметров, на мой взгляд, это уже многовато — повод задуматься над декомпозицией.
1. Для того, чтобы знать какие параметры в каком порядке ставить достаточно именовать параметры не $a и $b, а $dateFrom и $dateTo, а также писать PHPDoc.
2. Если первые 4 параметра будут не нужны, ваш метод (с массивом) всё равно сломается и придется его переписывать. С нормальными аргументами это сделать будет проще и не надо будет изобретать ту чушь, которую вы привели как пример.
3. Если вам понадобится добавить еще аргументы, то либо они необязательные (значит все вызовы метода работают и без них и вам не надо будет их править), либо без них ничего не работает и вам в любом случае придется переписывать код.
2. Если первые 4 параметра будут не нужны, ваш метод (с массивом) всё равно сломается и придется его переписывать. С нормальными аргументами это сделать будет проще и не надо будет изобретать ту чушь, которую вы привели как пример.
3. Если вам понадобится добавить еще аргументы, то либо они необязательные (значит все вызовы метода работают и без них и вам не надо будет их править), либо без них ничего не работает и вам в любом случае придется переписывать код.
1. Это не отменяет необходимости запоминания порядка аргументов. А если человек в блокноте решил пару фиксов сделать?
2. Мой метод с массивом не поломается, так как достаточно будет внести в массив аргументов (который мы мержим с переданным в функции) значения по умолчанию для этих 4 параметров. И я не понял как вы собираетесь бороться с some_function(0, 1, false, null, $foobar) без переписывания всего кода, где встречается вызов этого метода.
3. Собственно пункт №2 показывает, что в моем случае все отлично работает и ничего переписывать не надо
Посмотрите на любой jQuery-плагин, как он работает. Добавление новых параметров происходит совершенно без болезненно, и ничего не ломается.
2. Мой метод с массивом не поломается, так как достаточно будет внести в массив аргументов (который мы мержим с переданным в функции) значения по умолчанию для этих 4 параметров. И я не понял как вы собираетесь бороться с some_function(0, 1, false, null, $foobar) без переписывания всего кода, где встречается вызов этого метода.
3. Собственно пункт №2 показывает, что в моем случае все отлично работает и ничего переписывать не надо
Посмотрите на любой jQuery-плагин, как он работает. Добавление новых параметров происходит совершенно без болезненно, и ничего не ломается.
1. Продолжайте писать в блокноте.
2. То есть вместо some_function(0, 1, false, null, $foobar) вы будете передавать some_function([0, 1, false, null, $foobar])? Даа, это очень круто )
И зачем вы сравниваете PHP и jQuery?
В общем, я не собираюсь вас переубеждать. Продолжайте говнокодить.
2. То есть вместо some_function(0, 1, false, null, $foobar) вы будете передавать some_function([0, 1, false, null, $foobar])? Даа, это очень круто )
И зачем вы сравниваете PHP и jQuery?
В общем, я не собираюсь вас переубеждать. Продолжайте говнокодить.
1. Это не имеет значения
2. Я буду передавать some_function(['foobar' => $foobar]). Что здесь непонятного?
Говнокодите из нас только вы. Ни в одной приличной библиотеке не видел функций вида some_function($a, $b, $c, $d, $e = null, $f = 0, $g = 'all', $h = true)
2. Я буду передавать some_function(['foobar' => $foobar]). Что здесь непонятного?
Говнокодите из нас только вы. Ни в одной приличной библиотеке не видел функций вида some_function($a, $b, $c, $d, $e = null, $f = 0, $g = 'all', $h = true)
Видимо разработчики php где-то ошиблись. Зачем вообще методу несколько аргументов, если можно принимать на входе один массив. Видимо это фатальный недостаток языка.
Безусловно это не везде надо, но отсутствие именованных аргументов — да — 1 из недостатков PHP.
Давайте не будем разводить срач теперь и про PHP vs Ruby/Python/C#/whatever, просто я хотел донести мысль, что
гораздо выразительнее, чем
some_function([
'param1' => $value1,
'param2' => $value2,
'param3' => $value3,
'param4' => $value4,
'param5' => $value5,
'param6' => $value6,
'param7' => $value7,
'param8' => $value8
])
гораздо выразительнее, чем
some_function($a = null, $b = 1, $c = 0, $d = false, $e = true. $f = 'all', $g = 100, $h = $foobar)
Довольно холиварная тема, на самом деле. Мне нравится способ «обязательные раздельно, необязательные потом массивом». В одном из выпусков JavaScript Jabber он был упомянут.
Если интересно, то, как вы можете догадаться, то что выше не первый вариант скрипта, он менялся и так было проще в процессе, особенно для использования str_replace, как минишаблонизатора. А еще я в конце статьи специально написал постскриптум :)
Вот этой штукой пользовался, довольно сносно работает: www.watchmyticket.com/
Да. РЖД вообще странная компания. Впервые за 33 года моей жизни сокращают количество поездов до 4 в неделю (раньше было 14, т.е. два раза в день, потом стало 7). При этом как не попробуешь билет брать, так мест нет. Или у туалета или верхние. На сайте минимум свободных мест. При этом сокращение поездов мотивировали низким спросом. Типа сколько из областного бюджета заплатите, столько и будет поездов хранить. И это с тем учётом, что билеты на автобус дешевле плацкарта. Разве что не все готовы в автобусе 6 часов в пути проводить, особенно если с детьми.
Как минимум уже один раз на хабре была подобная вещица, весной вроде бы.
Помнится весной хотел купить билет на поезд — их нет. Через час дёрнуло меня ещё раз посмотреть — опа, билет есть. Пока тыкал в кнопки — его купили/заблокировали. В 5 минут следующего часа смотрю — снова 1 билет — успел купить.
Также летом покупал билет. Выбрал вагон, в нём 50/50 свободных мест, дошёл до выбора места — решил вернуться обратно, пощёлкал другие поезда, возвращаюсь заново к своему поезду и вагону, а там уже 49/50 свободных мест. Тут я вспомнил ситуацию с весной и решил подождать до начала следующего часа, ради интереса. И действительно, в начале следующего часа снова стало 50/50 свободных мест.
К чему я это всё писал: на определённом этапе оформления билета он блокируется для продажи. А дальше пользователь может купить этот билет, а может отказаться. Сброс блокировки некупленных билетов происходит раз в час (по крайней мере так было весной и летом), поэтому обновлять по крону раз в 5 минут никакого смысла нет.
Также летом покупал билет. Выбрал вагон, в нём 50/50 свободных мест, дошёл до выбора места — решил вернуться обратно, пощёлкал другие поезда, возвращаюсь заново к своему поезду и вагону, а там уже 49/50 свободных мест. Тут я вспомнил ситуацию с весной и решил подождать до начала следующего часа, ради интереса. И действительно, в начале следующего часа снова стало 50/50 свободных мест.
К чему я это всё писал: на определённом этапе оформления билета он блокируется для продажи. А дальше пользователь может купить этот билет, а может отказаться. Сброс блокировки некупленных билетов происходит раз в час (по крайней мере так было весной и летом), поэтому обновлять по крону раз в 5 минут никакого смысла нет.
офтоп — но может кому-то поможет
хотел предупредить граждан других стран (не РФ)
у них там косяк сейчас с оформлением билетов (уже месяц как — наверное в связи с борьбой со шпионами)
при вводе серии паспорта латинскими буквами возникает ошибка — потому что система проверяет только буквы из кириллицы.
например, если серии типа PP (латинские)- то водите РР (русские)
хотел предупредить граждан других стран (не РФ)
у них там косяк сейчас с оформлением билетов (уже месяц как — наверное в связи с борьбой со шпионами)
при вводе серии паспорта латинскими буквами возникает ошибка — потому что система проверяет только буквы из кириллицы.
например, если серии типа PP (латинские)- то водите РР (русские)
Нормальный интерфейс сайта? Разработчики?
Этот человек Вам искренне улыбается
Этот человек Вам искренне улыбается
Вот тут и выясняется, что у каждого путешествующего программиста есть скрипт в загашнике )
Спасибо за скрипт! Вы молодец, что докопались. Я с наскока не смог обойти защиту, стал мониторить более простым способом: скриптом с GET-запросом на Яндекс.Расписания:
rasp.yandex.ru/buy/options/?number=154А&thread=154AB_tis&t_type=train&station_to=9602494&station_from=2006004&date=2014-01-01
Запрос возвращает либо «retrieving», либо ответ в формате JSON.
Выяснил также, что сервис Яндекса обновляет данные из базы РЖД с некоторым интервалом, из-за этого билет на Яндексе может появиться на несколько минут позже. Забыл уже, где-то около 2-х минут разница, но этих пару минут хватает, чтобы билет уже кто-то увел.
Плюс Яндекса в том, что можно мониторить билеты на любой транспорт.
Спасибо за скрипт! Вы молодец, что докопались. Я с наскока не смог обойти защиту, стал мониторить более простым способом: скриптом с GET-запросом на Яндекс.Расписания:
rasp.yandex.ru/buy/options/?number=154А&thread=154AB_tis&t_type=train&station_to=9602494&station_from=2006004&date=2014-01-01
Запрос возвращает либо «retrieving», либо ответ в формате JSON.
Выяснил также, что сервис Яндекса обновляет данные из базы РЖД с некоторым интервалом, из-за этого билет на Яндексе может появиться на несколько минут позже. Забыл уже, где-то около 2-х минут разница, но этих пару минут хватает, чтобы билет уже кто-то увел.
Плюс Яндекса в том, что можно мониторить билеты на любой транспорт.
Спасибо за статью, сам об этом доумал, но не было времения заняться.
Если в скором появится много скриптов и сервисов по отловле билетов — будет важно то, кто первее получит информацию и кто быстрее сможет ею воспользоваться.
Второй этап тоже можно автоматизировать по максимуму — например приложение в телефоне, которое хранит даынне карточки и может и имеет досту к смс (для чтения кода от банка).
— Жду следующую статью — высокоскоростная выкупка освободившихся билетов РЖД.
Если в скором появится много скриптов и сервисов по отловле билетов — будет важно то, кто первее получит информацию и кто быстрее сможет ею воспользоваться.
Второй этап тоже можно автоматизировать по максимуму — например приложение в телефоне, которое хранит даынне карточки и может и имеет досту к смс (для чтения кода от банка).
— Жду следующую статью — высокоскоростная выкупка освободившихся билетов РЖД.
Спасибо, отличный скрипт, все работает.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Покупаем билеты на поезд в Новый год