Автоматизируем покупку Ж/Д билетов Укрзалізниці

    Привет! Наверное, каждый из нас когда-то сталкивался с ситуацией, когда нужно срочно куда-то уехать, но все Ж/Д билеты уже раскуплены. В этой статье я расскажу о том, как я писал Telegram бота для отслеживания и покупки освободившихся билетов Укрзалізниці.


    Как это работает


    Для покупки железнодорожных билетов в Украине компания Укрзалізниця запустила ресурс http://booking.uz.gov.ua/. Ресурс удобен тем, что не нужно посещать кассы, чтобы забрать сам билет. Достаточно показать проводнику QR код с посадочного талона на экране смартфона либо распечатав на принтере.


    Проблема состоит в том, что на популярные рейсы места очень быстро заканчиваются и иногда купить билет довольно проблематично. Однако, многие люди не покупают билет, а бронируют его. Бронь действует лишь 24 часа и после этого, если она не выкуплена в кассе, билет возвращается в пул свободных. Таким образом, необходимо успеть словить этот момент, когда билет доступен для покупки до того, как его снова забронируют или купят.


    Было принято решение решить эту задачу с помощью скрипта, который раз в минуту проверяет свободные билеты на интересующий поезд и, в случае наличия, резервирует его на 15 минут. После чего пользователю необходимо завершить процедуру оплаты через веб браузер.


    В качестве интерфейса был выбран Telegram так как это новая платформа для меня и я хотел с ней немного разобраться. В качестве бонуса сразу получаем уведомления на мобильный, не задумываясь о push нотификациях или email'ах.
    В качестве языка программирования был выбран Python.


    Интерфейс


    И всё же, как это работает с точки зрения пользователя?
    Бот распознает следующие команды:


    • /help — вернёт список поддерживаемых команд
    • /trains 2016-06-12 Kyiv Lviv — вернёт список поездов из Киева во Львов, отправляющихся 12 июня 2016 года
    • /scan Ivanov Ivan 2016-06-12 Kyiv Lviv 743K — запустит мониторинг билетов на поезд 743К Киев-Львов. Возвращает ID данного сканирования
    • /status_1234 — вернет состояние сканирования с ID 1234
    • /abort_1234 — остановит сканирование с ID 1234

    В случае успешного резервирования билета пользователь получит сообщение, содержащее Session ID. Этот ID затем необходимо вручную прописать в cookie браузера и завершить покупку билета.


    UZ API


    Для начала давайте разберёмся с форматом API, используемым порталом. Это не составляет большого труда, достаточно просто открыть консоль разработчика в браузере и посмотреть какие запросы выполняет скрипт на странице поиска билетов.


    В API используются только POST запросы. Для защиты от использования API сторонними разработчиками почти во всех вызовах в тело включается токен. Без токена можно производить только поиск станций.


    Стоит также отметить, некоторые нюансы работы с датами. Во-первых, формат даты меняется в зависимости от текущей локали API. Например, для локали en формат будет mm.dd.yyyy. Тогда как для ua и ru это будет привычный нам dd.mm.yyyy. Во-вторых, для некоторых запросов дата представляется в виде timestamp, однако он зависит от состояния летнего/зимнего времени. Потому я решил не заморачиваться с сериализацией/десериализацией данных штампов, а использовать их в том виде, в котором API возвращает их.


    Получение токена


    Покопавшись в подключаемых сайтом скриптах, можно с легкостью обнаружить такой кусок:


    var ajax = $v.ajax(url).header({
        'GV-Ajax': 1,
        'GV-Referer': encodeURI(GV.site.htcur_url + GV.site.requestUri),
        'GV-Screen': screen.width + 'x' + screen.height,
        'GV-Token': localStorage.getItem('gv-token') || ''
    });

    Здесь мы видим, что при вызовах в API токен считывается из localStorage браузера. Осталось найти где он туда записывается.


    Эта часть была самой интересной, потому как простым поиском по html и js этого найти не удалось. Потратив несколько часов в гугле, я наткнулся на статью, в которой автор решает такой же вопрос с мониторингом билетов на сайте УЗ. Итак, в статье подробно описано, что токен генерируется обфусцированным с помощью JJEncode кодом. За несколько минут находим реализацию деобфускатора на питоне, который и будет использоваться в дальнейшем.


    Краткий API reference


    Для вызова методов API, необходимо включать следующие заголовки:


    GV-Ajax: 1
    GV-Referer: http://booking.uz.gov.ua/en/
    GV-Token: <token>

    Поиск станций


    Например, для формирования подсказок автодополнения станций выполняется запрос с пустым телом по адресу http://booking.uz.gov.ua/en/purchase/station/ky/, где ky — это то, что пользователь вводит в текстовое поле выбора станции.


    В ответ сервер отправляет примерно такой JSON:


    {
      "value": [
        {
          "title": "Kyiv",
          "station_id": "2200001"
        },
        {
          "title": "Kyivska Rusanivka",
          "station_id": "2201180"
        },
        {
          "title": "Kyj",
          "station_id": "2031278"
        },
        {
          "title": "Kykshor",
          "station_id": "2011189"
        }
      ],
      "error": null,
      "data": {
        "req_text": [
          "ky",
          "лн"
        ]
      },
      "captcha": null
    }

    Поиск поездов


    Для поиска поездов необходимо выполнить запрос на http://booking.uz.gov.ua/en/purchase/search/ с таким телом:


    station_id_from=2200001  # ID станции отправления
    station_id_till=2218000  # ID станции назначения
    date_dep=06.12.2016      # дата отправления в формате mm.dd.yyyy
    time_dep=00:00 
    time_dep_till= 
    another_ec=0 
    search=

    В ответ мы получим список поездов, следующих по указанному маршруту. Так же, в ответ будет включена информация о количестве свободных мест в вагонах каждого типа (Люкс, Купе, Плацкарт, и т. д.):


    {
      "value": [
        {
          "num": "743Л",
          "model": 1,
          "category": 1,
          "travel_time": "5:01",
          "from": {
            "station_id": 2200001,
            "station": "Darnytsya",
            "date": 1465741200,
            "src_date": "2016-06-12 17:20:00"
          },
          "till": {
            "station_id": 2218000,
            "station": "Lviv",
            "date": 1465759260,
            "src_date": "2016-06-12 22:21:00"
          },
          "types": [
            {
              "title": "Seating first class",
              "letter": "С1",
              "places": 117
            },
            {
              "title": "Seating second class",
              "letter": "С2",
              "places": 176
            }
          ],
          "reserve_error": "reserve_24h"
        },
        {
          "num": "091К",
          "model": 0,
          "category": 0,
          "travel_time": "7:25",
          "from": {
            "station_id": 2200001,
            "station": "Kyiv-Pasazhyrsky",
            "date": 1465760460,
            "src_date": "2016-06-12 22:41:00"
          },
          "till": {
            "station_id": 2218000,
            "station": "Lviv",
            "date": 1465787160,
            "src_date": "2016-06-13 06:06:00"
          },
          "types": [
            {
              "title": "Suite / first-class sleeper",
              "letter": "Л",
              "places": 11
            },
            {
              "title": "Coupe / coach with compartments",
              "letter": "К",
              "places": 50
            }
          ],
          "reserve_error": "reserve_24h"
        }
      ],
      "error": null,
      "data": null,
      "captcha": null
    }

    Просмотр вагонов


    Просмотреть список вагонов и количество свободных мест можно выполнив запрос на http://booking.uz.gov.ua/en/purchase/coaches/ с таким телом:


    station_id_from=2200001
    station_id_till=2218000
    date_dep=1462976400
    train=743К               # номер поезда
    model=3                  # модель поезда
    coach_type=С2            # тип вагона (люкс, купе, и т. д.)
    round_trip=0
    another_ec=0

    В ответ мы получим список вагонов данного типа с количеством свободных мест и ценой:


    {
      "coach_type_id": 10,
      "coaches": [
        {
          "num": 1,
          "type": "С",
          "allow_bonus": false,
          "places_cnt": 21,
          "has_bedding": false,
          "reserve_price": 1700,
          "services": [],
          "prices": {
            "А": 35831
          },
          "coach_type_id": 10,
          "coach_class": "2"
        },
        {
          "num": 3,
          "type": "С",
          "allow_bonus": false,
          "places_cnt": 21,
          "has_bedding": false,
          "reserve_price": 1700,
          "services": [],
          "prices": {
            "А": 35831
          },
          "coach_type_id": 9,
          "coach_class": "2"
        }
      ],
      "places_allowed": 8,
      "places_max": 8
    }

    Просмотр свободных мест


    Для просмотра свободных мест в выбранном вагоне необходимо выполнить запрос на http://booking.uz.gov.ua/en/purchase/coach/ с телом:


    station_id_from=2200001
    station_id_till=2218000
    train=743К
    coach_num=1
    coach_class=2
    coach_type_id=19
    date_dep=1462976400
    change_scheme=1

    В ответ получаем список свободных мест:


    {
      "value": {
        "places": {
          "А": [
            "8",
            "12",
            "16",
            "18",
            "22",
            "27",
            "28",
            "32",
            "33",
            "34",
            "36",
            "37",
            "38",
            "39",
            "42",
            "43",
            "47",
            "48",
            "49",
            "55",
            "56"
          ]
        }
      },
      "error": null,
      "data": null,
      "captcha": null
    }

    Работа с корзиной


    Для того, чтобы положить билет в корзину, тем самым зарезервировав его на 15 минут для оплаты, необходимо выполнить запрос на http://booking.uz.gov.ua/en/cart/add/ с телом:


    code_station_from:2200007
    code_station_to:2218000
    train:743К
    date:1463580000
    round_trip:0
    places[0][ord]:0
    places[0][coach_num]:5
    places[0][coach_class]:2
    places[0][coach_type_id]:22
    places[0][place_num]:37
    places[0][firstname]:Name
    places[0][lastname]:Surname
    places[0][bedding]:0
    places[0][child]:
    places[0][stud]:
    places[0][transp]:0
    places[0][reserve]:0

    Мониторинг


    Итак, вот мы и добрались до самой интересной части, до мониторинга свободных билетов. Для решения этой задачи был реализован класс UZScanner, который имеет несколько методов:


    • добавить поезд для мониторинга
    • удалить поезд из мониторинга
    • запуск мониторинга
    • остановка мониторинга

    Класс мониторинга реализован таким образом, чтобы к нему с легкостью можно было подключать любые пользовательские интерфейсы, например, любой другой, отличный от Telegram, бот или веб сайт.


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


    class UZScanner(object):
    
        def __init__(self, success_cb, delay=60):
            self.success_cb = success_cb
    
            self.loop = asyncio.get_event_loop()
            self.delay = delay
            self.session = aiohttp.ClientSession()
            self.client = UZClient(self.session)
            self.__state = dict()
            self.__running = False

    Для того, чтобы вызывающий код различал для какого именно пользователя произошел callback, помимо данных о самом поезде также передаётся callback ID:


    def add_item(self, success_cb_id, firstname, lastname, date,
                 source, destination, train_num, ct_letter=None):
        scan_id = uuid4().hex
        self.__state[scan_id] = dict(
            success_cb_id=success_cb_id,
            firstname=firstname,
            lastname=lastname,
            date=date,
            source=source,
            destination=destination,
            train_num=train_num,
            ct_letter=ct_letter,
            lock=asyncio.Lock(),
            attempts=0,
            error=None)
        return scan_id

    Основная функция мониторинга является циклом, в котором для каждого поезда запускается функция проверки наличия мест.


    async def run(self):
        self.__running = True
        while self.__running:
            for scan_id, data in self.__state.items():
                asyncio.ensure_future(self.scan(scan_id, data))
            await reliable_async_sleep(self.delay)

    Сама же функция мониторинга работает по такому алгоритму:


    • Получить список поездов на заданную дату по заданному маршруту
    • Проверить, есть ли нужный поезд
    • Для всех вагонов (либо только для указанного типа) проверить наличие мест
    • Попробовать зарезервировать первое найденное свободное место
    • В случае успеха, выполнить callback, удалить поезд из мониторинга

    async def scan(self, scan_id, data):
        if data['lock'].locked():
            return
    
        async with data['lock']:
            data['attempts'] += 1
    
            train = await self.client.fetch_train(
                data['date'], data['source'], data['destination'], data['train_num'])
            if train is None:
                return self.handle_error(
                    scan_id, data, 'Train {} not found'.format(data['train_num']))
    
            if data['ct_letter']:
                coach_type = self.find_coach_type(train, data['ct_letter'])
                if coach_type is None:
                    return self.handle_error(
                        scan_id, data, 'Coach type {} not found'.format(data['ct_letter']))
                coach_types = [coach_type]
            else:
                coach_types = train.coach_types
    
            session_id = await self.book(train, coach_types, data['firstname'], data['lastname'])
            if session_id is None:
                return self.handle_error(scan_id, data, 'No available seats')
    
            await self.success_cb(data['success_cb_id'], session_id)
            self.abort(scan_id)
    
    @staticmethod
    async def book(train, coach_types, firstname, lastname):
        with UZClient() as client:
            for coach_type in coach_types:
                for coach in await client.list_coaches(train, coach_type):
                    try:
                        seats = await client.list_seats(train, coach)
                    except ResponseError:
                        continue
                    for seat in seats:
                        try:
                            await client.book_seat(train, coach, seat, firstname, lastname)
                        except ResponseError:
                            continue
                        return client.get_session_id()

    Заключение


    Мы разобрались с API, используемым порталом http://booking.uz.gov.ua и реализовали скрипт резервирования билета. Код доступен на GitHub. Docker image доступен на DockerHub. Также доступен Telegram бот @uz_ticket_bot


    UPD УЗ заблокировала IP бота. Бот временно отключён.

    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 52

      +2
      имхо, так можно сервис и заДДОСить, тем более что он до сих пор в тестовой експлуатации
        +1
        Заддосить можно все, что угодно. Но это же не повод не реализовывать программы, выполняющие полезную функцию, правда?
        А шильдик «тестовая эксплуатация» там висит с момента запуска сервиса. Лет 5 уже как.
          +3
          одно дело писать прораммы использующие публичное АПИ, но на сколько я знаю разработчики не открывали его. Да, они не особо то и скрывали, но обфускация важного кода какбы намекает, что АПИ не публичное. Сервис банально может быть не расчитан на нагрузки созданные всеми желающими и в итоге ни Вы не купити билетик, ни сотни других покупателей
            0

            Кроме того, запуском бота с множеством пользователей возникнет проблема с обычным нормальным пользованием сервисом, так как бот будет постоянно резервировать места и совсем не факт что с последующей покупкой.

        +3
        Автор, отличная работа. Вы материализовали мысль многих, кто пользуется этим сервисом
          0
          Спасибо. Рад, что кому-то кроме меня это может быть пригодиться.
          +2
          Отличная идея! Спасибо, прочитал доку по боту, там есть следующее: /scan Firstname Lastname 2016-01-01 Kyiv Lviv 743K C2
          Что такое C2 — Как я понял, с помощью этого можно указать тип места (плацкарт/купе и т.д.) Какие типы кроме C2 могут быть тогда, можно более развернуто?
            0

            Все верно, С2 — это тип вагона. /trains возвращает список поездов в таком виде:


            Train: 013Ш
            Departure time: 2016-07-01 01:08:00
            Travel time: 8:52
            ~~~~~~~~~~
            Л: 2 (Suite / first-class sleeper)
            К: 10 (Coupe / coach with compartments)
            П: 16 (Berth / third-class sleeper)
            ==========
            
            Train: 744Л
            Departure time: 2016-07-01 06:20:00
            Travel time: 4:59
            ~~~~~~~~~~
            С1: 164 (Seating first class)
            С2: 403 (Seating second class)
            ==========

            Здесь видно, что типы вагонов бывают С1, С2, Л, К, П

              0
              Спасибо за пояснения!
            +9
            У Укрзализныци наверняка есть такой же неочевидный лайфхак, как и у РЖД, суть его в следующем: если очень-очень нужно уехать на конкретном поезде, а билетов на него в продаже нет, то можно поискать билеты с «фиктивными» пересадками. Для тех, кто знаком с понятием split ticketing все уже понятно, для остальных поясню на актуальных на момент написания комментария данных.

            Допустим, есть поезд 062А, который едет из Москвы в Питер, проезжая при этом несколько промежуточных станций. Билетов на этот поезд на сегодня уже в продаже нет, но если очень хочется уехать, то можно купить два билета на одно и то же место, на два последовательных сегмента маршрута. Например, можно купить на 37 место 5 вагона из Москвы до Бологое, и на это же место от Бологое до Питера. Полного билета, из Москвы в Питер, на это место в продаже нет. Я не уверен, почему это так, скорее всего это как-то связано с квотами станций.

            А еще этот милый лайфхак иногда позволяет сэкономить приличную сумму денег. Например, прямо сейчас билет на сегодня из Москвы в Питер, в купе поезда 082А стоит 4326 рублей. Но вместо одного билета можно купить два, от Москвы до Окуловки за 1451 рублей и от Окуловки до Питера, за 947. В сумме это обойдется Вам в 2398 рублей, экономия равна 1928 рублям или 45%, при этом качественно разницы никакой нет совершенно.
              +1

              Вероятно, такая штука есть. Однако, в Украине помимо обычных поездов запустили быстрые электропоезда "интерсити". Зачастую они следуют без остановок по всему маршруту. Лично я чаще всего пользуюсь именно такими поездами, потому ваш вариант здесь вряд ли сработает.

                –2
                Все поезда интерсити на украине идут с промежуточными остановками. В этом можно легко убедиться здесь: intercity.kiev.ua/raspisanie
                +1
                Да, фиктивные «пересадки» не раз выручали. Однозначно стоит добавить в реализацию бота.
                Правда у нас в украинских поездах цена билетов наоборот получается дороже процентов на 30%, вероятно из-за двойной оплаты страховки и дополнительных сборов.
                Еще есть прикол, когда за неделю уже билетов на поезд нет, а в день отправления «магическим» образом появляется куча свободных мест в разных вагонах. Но это уже другая история, о куче посредников, их бизнесе и времени бронирования.
                  +3
                  УкрЗалізниця бронирует в каждом поезде определенный процент мест для своих сотрудников (они имеют право раз или два в год взять бесплатные билеты туда и обратно на любой поезд), для сотрудников разнообразных органов (внезапные командировки и так далее). Естественно эта бронь не выкупается в полном объеме никогда и в последний день снимается.
                    0
                    бронь снимается дважды.
                    первый раз ровно за 12 часов до отправления поезда.
                    второй раз по разному — для некоторых маршрутов за 3 часа для некоторых за полтора. Так и не понял в каких случаях выбирается какое время. (возможно проходящий или прямой)
                    Этот алгоритм работает даже в сезон на курортных маршрутах. Ни раз так брал билеты.
                    0
                    Да не на 30% а вдвое. Пример? Интерсити Днепр-Харьков, промежуточная Лозовая.
                    Днепр-Харьков =133 грн, Днепр-Лозовая=113грн, Лозовая-Харьков 112 грн, итого 225 против 133,
                    грабеж чистой воды.
                    0
                    В УЗ на каждую станцию выделяется определенный пул билетов, и часто такое бывает, что на больших станцииях билеты расходятся быстрее чем на мелких. Например если из Запорожья в Киев нет билетов ни на один поезд, то почти всегда из соседнего Мелитополя чуть ли не десяток в каждом вагоне. Выходит чуть дороже, но зато точно доедешь куда нужно и без нервотрепок по поводу наличия или отсутсвия снятой брони в последний день перед отправкой. Ну или если в обратную сторону — взять билет с посадкой из соседнего городка и добраться туда автобусом или машиной.
                      0
                      У Укрзализныци с этим как раз наоборот. Они при ажиотаже предпочитают продавать билеты от конечной до конечной, видимо зарабатывая при этом больше денег (билет стоит дороже, а на оставшуюся часть пути найти пассажира сложнее). Потому иногда система не позволяет купить билет с промежуточной станции, при этом позволяя купить с начальной до конечной. Но тут есть другая проблема — если пассажир не сел в поезд, то на одной из следующих станций они могут как-то подать эту информацию и билет снова поступает в продажу. Я не знаю как оно технически работает, это мне рассказывали в справочной. Потому чтобы не попасть в неприятную ситуацию, если вы садитесь на промежуточной станции, нужно посылать телеграмму начальнику поезда о том, что посадка будет производиться на такой-то станции.
                      0
                      Как-то одноразово понадобилось отловить билет на УЗ, в итоге «на коленке» родился такой tcl скрипт с проверкой билетов на направление/дату (через альтернативный api) и отправкой sms (через сервис twilio) — http://paste.tclers.tk/3842 Билет был успешно пойман и скрипт отправился в архив.
                        –2
                        А что за баннер у вас при входе на сайт открывается?
                          +1

                          О каком сайте/баннере речь?

                          0
                          Телеграм бот не работает. (
                          Он не отвечает на команды, даже на /help никакой реакции.
                            +3

                            UPD УЗ заблокировала IP бота. Бот временно отключён.

                            0
                            Когда-то тоже писал бот на Python. Поработал пару недель, и они добавили этот токен. Побороть его тогда не смог (.
                            Вещь отличная, особенно когда пользуется ей сравнительно немного людей.
                              0
                              На каком-то из сайтов — посредников (а билетами УЗ торгует не только booking, но и многие другие, сайты дирекций например, Приват-банк тот же) уже реализованы функции ожидания нужных билетов. В системе резервирования УЗ есть еще такая особенность, что в продажу выставляется не весь поезд одновременно, а сначала несколько вагонов, потом по их заполнению до определенного процента — добавляется еще вагон и т.д. Поэтому имеем ситуацию, что вчера например в поезде нет рядом 4х мест для семейной поездки, а сегодня они уже есть… И да, квоты между железными дорогами… Это просто пир духа… С моей станции ЮЖД например нет билета на нужный поезд, но с соседней станции ПриднЖД — есть… Приходится брать, благо разница в цене копеечная, но его надо обязательно предварительно за день регистрировать у дежурного по вокзалу, чтобы изменить место посадки, иначе билет аннулируется…
                                0
                                Десятки раз брал билет от соседнего города и никогда не регистрировал свой билет у дежурного по вокзалу — без проблем садился на своей станции(правда всегда брал в пределах одной ЖД)
                                0
                                Интересно, а внутренняя система, которой пользуются кассиры, смотрит на ту же БД\сервер? Я к тому, что вы только что открыли ящик Пандоры — оказывается легкое шаманство и можно тупо «положить» сервер, а если он еще и один с тем что кассиры используют…
                                  +1
                                  Есть, давненько уже, запущенный и работающий бот
                                  https://telegram.me/railwaybot
                                  На днях там запустилась еще и продажа билетов, к сожалению не на прямую через букинг, но тоже интересный вариант.
                                    0

                                    Благодарю за данный экземпляр!

                                    0
                                    Вопрос по авторской реализации. Для чего реализовано добавление в корзину, ведь корзина не привязывается к аккаунту и не получится просто зайти и купить, ожидающий билет. Это сделано просто для резервирования?
                                      0

                                      Корзина привязана к session id. Подменив этот id в браузере, можно произвести оплату билета. Это не идеальное решение, но первое, что пришло в голову.

                                      0
                                      Конечно, такие вещи давно многими реализованы «для себя». Просто не афишируются, ибо приведет к появлению captcha, как и у РЖД. Но использование telegramm безусловно интересный вариант, спасибо!
                                        0
                                        Запустил с Docker. Телеграм бот работает, отвечает на команду /help, но при вводе /trains или /scan возвращает 403 страницу с УЗ.
                                          0

                                          Очевидно, немного забомбили запросами и УЗ оперативно добавили еще одну проверку.

                                            0

                                            Попробуйте еще раз. Добавлена поддержка браузерных юзер агентов.

                                              0
                                              Спасибо, работает. А можно добавить бронь 2-3х мест рядом с исключением туалетов?
                                                0

                                                Не думаю, что у меня будет возможность сделать это в ближайшее время. Но я с удовольствием просмотрю ваш PR.

                                            0
                                            В целом не плохо, тоже в голову приходили мысли, а как же это автоматизировать. Но смущает только один момент: «вручную прописать в cookie браузера и завершить покупку билета.» — как-то не юзер френдли получается, я понимаю, что тут ограничения среды вступают в силу,, но все же.
                                              0

                                              Это решается простеньким js кодом упакованным в URL и запускаемым на странице УЗ. Достаточно туда впихнуть промпт который будет спрашивать sessionID и записывать его в LS.

                                                0

                                                PR приветствуется!

                                                  0

                                                  Done. Немного коряво вышло из-за ограничения гитхаба на публикацию букмарклетов в .md, так что нужно смерджить в бранч gh-pages где будет открываться html с линкой букмарклета.

                                                    0

                                                    Конечно, это только полуавтоматическое решение, и не для всех подходит, но самое простое. К сожалению, сделать это ссылкой из бота не выйдет, как могло показаться из моего первого комментария, речь шла именно о букмарклете.

                                                      0

                                                      Увы, но данный способ не подходит, так как куки будет записана для домена github.io и не будет работать для booking.uz.gov.ua.

                                                        0

                                                        Так запускать-то его надо именно на странице booking.uz.gov.ua. Я в ридми описал. Нужно не просто линку нажать на странице, а добавить её как закладку. Оттого оно и зовётся букмарклетом.

                                                          +1

                                                          Для наглядности скринкаст как пользоваться: http://screencast.com/t/xsqsLiE2

                                                            0

                                                            Спасибо за разъяснение.

                                                0
                                                Бот сейчас лежит судя по-всему. Не отзывается ни на единую команду…
                                                  0

                                                  Все верно. Там по этому поводу есть UPD в конце статьи.

                                                  0
                                                  Интересный подход, сыроват пока что, но тем немение для УЗ будет новым витком развития
                                                    0
                                                    SCAN_DELAY_SEC лучше ставить минимум 60 секунд.
                                                    Информация на сервере все равно обновляется только каждые 20 минут.
                                                    Поэтому лишний раз DDoS-ить сервер не надо.

                                                    Only users with full accounts can post comments. Log in, please.