Monitoring electronic railways tickets with selenium

By fate, I often have to travel across Russia from city to city for short distances: I live and work in Moscow, and relatives and friends live in Kazan. Previously, tickets for trains had to be bought in advance, to go to the station at the ticket office, to stand in lines, and the process took a lot of time, was inflexible, and everything had to be planned in advance.

In this article I will talk about problems when buying tickets for Russian Railways and how I try to solve them by automating actions in the browser.

Introduction



A few years ago, Russian Railways started selling tickets online on their ticket.rzd.ru website , and soon electronic registration appeared on almost all trains (it’s not necessary to get a ticket purchased through the Internet in a window at the station, but you can buy a ticket on the Internet if you want to print it order form, and with it go directly to the conductor, who has a list of passengers).

Thus, the process began to take less time, and its whole essence was reduced only to buying a ticket on the site. But tickets to popular destinations are quickly taken apart if they are not bought in advance, and often there are simply no tickets for the train you need, not to mention such big holidays as the New Year, when tickets appear on sale in 45 days, and after a few days already out of stock.

Often in such cases, I just sat and updated the page in the hope that someone would hand over the ticket, and I would have time to buy it. It’s worth admitting with surprise that with intensive and continuous updating of the page with tickets I always got the opportunity to buy a ticket and leave, but I had to devote a lot of time and effort to such a “brute force”.

Automation



At some point, the idea came to my mind to automate this process. I’ll make a reservation right away that I automated the process of monitoring free tickets, without the purchase and payment stage, because obviously this is a dangerous undertaking.

I saw a lot of articles on the hub about selenium and its application for automating actions in the browser and decided to apply it for this task. To solve it in python (it is perfect for this task), you need to install the appropriate package:

pip install selenium

The code layout can be quickly generated using the Selenium IDE (this is a plug-in for Firefox), simply by performing standard actions on the page with a record of user actions pre-enabled. The plugin is available on the official website .

Then we had to comb this code a bit and add the parsing of the displayed information, the checks we need, and the triggering of an alarm.
The result is something like the code below:
# coding=utf-8
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import Select
from selenium.common.exceptions import NoSuchElementException
import time, re
import winsound
class Rzdtemp():
    def __init__(self, logger):
        self.logger = logger
    def setUp(self):
        self.driver = webdriver.Firefox()
        self.driver.implicitly_wait(30)
        self.base_url = "http://ticket.rzd.ru/"
        self.verificationErrors = []
    def test_rzdtemp(self):
        self.logger.info('Вход...')
        driver = self.driver
        driver.get(self.base_url + "/static/public/ticket?STRUCTURE_ID=2")
        driver.find_element_by_link_text("Вход").click()
        self.logger.info('Ввод логина и пароля...')
        driver.find_element_by_id("j_username").clear()
        driver.find_element_by_id("j_username").send_keys("username")
        driver.find_element_by_id("j_password").clear()
        driver.find_element_by_id("j_password").send_keys("password")
        driver.find_element_by_id("other").click()
        self.logger.info('Меню покупки билетов...')
        driver.find_element_by_link_text("Покупка билета").click()
        self.logger.info('Ввод данных...')
        driver.find_element_by_id("fromInput").clear()
        driver.find_element_by_id("fromInput").send_keys(u'КАЗАНЬ ПАСС')
        driver.find_element_by_id("whereInput").clear()
        driver.find_element_by_id("whereInput").send_keys(u'МОСКВА КАЗАНСКАЯ')
        driver.find_element_by_id("forwardDate").clear()
        driver.find_element_by_id("forwardDate").send_keys(u'02.09.2012')
        driver.find_element_by_id("ticket_button_submit").click()
        time.sleep(40)
        self.logger.info('Поиск нужных билетов...')
        rawhtml = driver.find_element_by_id('ajaxTrainTable').get_attribute("innerHTML")
        if u'Плацкартный' in rawhtml:
            self.logger.info('!!!ЕСТЬ ПЛАЦКАРТ!!!')
            strlist = [x.strip() for x in rawhtml.split('\n') if x.strip()!=u'']
            #print strlist
            train = ''
            for i,x in enumerate(strlist):
                if x == u'
': train = strlist[i+1].replace('','') if x == u'Плацкартный': #включаем сигнал тревоги winsound.PlaySound('alarma.ogg', winsound.SND_NOWAIT) self.logger.info(u'Поезд-%s Число-%s %s' % ( train, strlist[i+3].replace('','').replace('',''), strlist[i+5].replace('','').replace('',''))) elif u'Сидячий' in rawhtml: self.logger.info('Только сидячие...') elif u'Купе' in rawhtml: self.logger.info('Только купе...') self.logger.info('Выход...') driver.find_element_by_link_text("Выход").click() def tearDown(self): self.logger.info('Закрываем браузер...') self.driver.close() self.driver.quit()

This code can be run in a cycle at a specified interval, for example, check tickets every 5 minutes.
The whole process of writing and debugging the code took about half an hour.
You can tie any checks to the code, for the trains, dates, places and so on that we need.
In this version, upon detection, an audible signal sounds that the ticket has appeared, as an alternative, you can send email or SMS, but in this case, you can simply not have time to buy a ticket.

Summary


While there is no captcha on the site, you can safely use similar mechanisms, if you suddenly appear, you have to come up with something more complicated. Who knows, maybe in the future Russian Railways will have something like a service with an API.
It is worth noting that, to my surprise, tickets are handed out quite often, and the probability of intercepting a ticket just handed over is very high if you quickly complete the order. It often happened that a ticket appeared, but after filling it turned out that someone else had already bought it.
From personal experience, most tickets are handed out on the last day.
Have a nice trip!

Also popular now: