⬆️ ⬇️

We buy train tickets in the New Year

Of course, this new year, all of you would like to spend at home. We will not argue about what a house is, everyone has their own idea about this, but personally my house is associated with family and parents. Probably the most affordable way to be at home in the new year in Russia (in addition to the metro or a few hours of traffic jams) is of course a train from the well-known company of Russian Railways .







But demand clearly exceeds supply. Especially on the reserved seat, which, frankly, the most profitable. So what to do? If interested, then you can go under the cat. But, of course, things may not be so dramatic, but you just have to go somewhere, at any time of the year, and prices for a suite from Russian Railways do not suit you. We all know about the reservation that is being withdrawn and the tickets that can be returned, we will catch them then :)

')





To begin with, we will just send requests, by crown, for example, every five minutes. Then read the answer, and if the conditions suit us, then send yourself an SMS that you can take. But if everything is so simple, then why the article on Habr, you ask? And then, that this is just a ready-made solution, which I can share, with those who cannot or do not want to waste their time + there is a rather curious protection mechanism against such left-wing requests on the Russian Railways website, which I bypassed, and now I will tell you what it is is and how to get around it.



Request for receiving places on a specific date:



curl 'http://pass.rzd.ru/timetable/public/en?STRUCTURE_ID=735&layer_id=5371&dir=0&tfl=3&checkSeats=1&st0= {from} & code0 = 2004000 & dt0 = {date} & st1 = {to} & code1 = 2060600 & dt1 = date} & rid = 729493435 & SESSION_ID = 2 '-H' Cookie: JSESSIONID = 00006mwFi5RKtF-z0R16OGSMJtS: 17obqce3m; '



In bold, I highlighted the parameters that interest us:







After a little study, it becomes clear that with each new request, rid changes outwardly erratically, and SESSION_ID simply increases by one. What to do, how to recognize them? If we look closely at the logs, we will see another request that always goes before this.



Here he is:



curl 'http://pass.rzd.ru/timetable/public/en?STRUCTURE_ID=735&layer_id=5371&dir=0&tfl=3&checkSeats=1&st0= {from} & code0 = 2004000 & dt0 = {date} & st1 = {to} & code1 = 2060600 & dt1 = date} '-H' Cookie: JSESSIONID = 00006mwFi5RKtF-z0R16OGSMJtS: 17obqce3m; '



And that's what he will return to us:



{"Result": "RID", " SESSION_ID ": 2, " rid ": 729493435, "discounts": {}}



We are interested in this clear that :)



You will clearly say everything, we make two requests in succession, we get the missing parameters from the first one, we substitute the second and bingo! But no. That's not all. To be honest, I went further into a stupor, why does it refuse to work? Compare other headers, look for hidden variables, look for a little magic. But no. It works from the console, it works from the site, from the script it is an error.



Even imbued with respect for the protection, which he underestimated at first glance. And of course it dawned on me, the delay! There must be a pause between requests. sleep (2); That's all the solution. It is difficult to say what it is connected with, whether the delay is really there for protection, or just the data gets where it is needed not so quickly, but somehow its necessity was not quite obvious to me.



That's all. There is data, how to send free SMS? You can of course by mail, but if efficiency is important, then SMS will be preferable. It's all up to your taste, but I just used sms.ru, sending to one phone number is free there, but I don’t need it anymore. For each of your particular city, I will need unique numeric codes, which, as we see, we transfer to the input of our method:



$ rzd -> request ( [

'Saint Petersburg' ,

'2004000' ,

'Kirov' ,

'2060600' ,

'28 .12.2013 ' ,

] ) ;




To find them out, thank you mafet , for example, you can make a request to http://pass.rzd.ru/suggester?lang=ru&stationNamePart=Sa , substituting the first two letters of the city and find the desired city and station there, and from there get the desired id.



If anyone needs it, then the script itself:



Script
<? php



class rzd {



private $ urlData = 'http://pass.rzd.ru/timetable/public/ru?STRUCTURE_ID=735&layer_id=5371&dir=0&tfl=3&checkSeats=1&st0={from } & dt0 }} & st1 = {{to}} & code1 = {{code_to}} & dt1 = {{date}} ' ;

private $ data ;

private $ replace = [

'{{from}}' ,

'{{code_from}}' ,

'{{to}}' ,

'{{code_to}}' ,

'{{date}}' ,

] ;

private $ secure = '& rid = {{rid}} & SESSION_ID = {{session_id}}' ;

private $ replaceSecure = [

'{{rid}}' ,

'{{session_id}}' ,

] ;

private $ cookie = 'cookie' ;



public function request ( $ data ) {

$ this -> data = $ data ;

$ this -> urlData = str_replace ( $ this -> replace , $ this -> data , $ this -> urlData ) ;

$ ch = curl_init ( $ this -> urlData ) ;

curl_setopt ( $ ch , CURLOPT_RETURNTRANSFER , 1 ) ;

curl_setopt ( $ ch , CURLOPT_COOKIEJAR , $ this -> cookie ) ;

curl_setopt ( $ ch , CURLOPT_COOKIEFILE , $ this -> cookie ) ;

$ result = json_decode ( curl_exec ( $ ch ) , true ) ;

$ this -> urlData . = str_replace ( $ this -> replaceSecure , [ $ result [ 'rid' ] , $ result [ 'SESSION_ID' ] ] , $ this -> secure ) ;

sleep ( 2 ) ;

$ ch = curl_init ( $ this -> urlData ) ;

curl_setopt ( $ ch , CURLOPT_RETURNTRANSFER , 1 ) ;

curl_setopt ( $ ch , CURLOPT_COOKIEJAR , $ this -> cookie ) ;

curl_setopt ( $ ch , CURLOPT_COOKIEFILE , $ this -> cookie ) ;

$ result = json_decode ( curl_exec ( $ ch ) , true ) ;

$ result = reset ( $ result [ 'tp' ] ) ;

$ result = $ result [ 'list' ] ;

foreach ( $ result as $ train ) {

if ( isset ( $ train [ 'cars' ] ) && is_array ( $ train [ 'cars' ] ) )

foreach ( $ train [ 'cars' ] as $ ticket ) {

# here you can write a condition, for example, if the price is less than 4000r, then we do everything that is lower and send SMS

$ resultExec = 'On' . $ data [ 4 ] . '-' . $ train [ 'number' ] . "-" . $ ticket [ 'type' ] . 'for' . $ ticket [ 'tariff' ] . '-' . $ ticket [ 'freeSeats' ] . 'm' ;

$ ch = curl_init ( " sms.ru/sms/send" ) ;

curl_setopt ( $ ch , CURLOPT_RETURNTRANSFER , 1 ) ;

curl_setopt ( $ ch , CURLOPT_TIMEOUT , 30 ) ;

curl_setopt ( $ ch , CURLOPT_POSTFIELDS , array (

"api_id" => 'id sms.ru' ,

"to" => "your phone" ,

"text" => $ resultExec ,

) ) ;

sleep ( 2 ) ;

$ body = curl_exec ( $ ch ) ;

curl_close ( $ ch ) ;

}

}

}

}







$ rzd = new rzd ( ) ;

$ rzd -> request ( [

'Saint Petersburg' ,

'2004000' ,

'Kirov' ,

'2060600' ,

'27 .12.2013 ' ,

] ) ;





$ rzd = new rzd ( ) ;

$ rzd -> request ( [

'Saint Petersburg' ,

'2004000' ,

'Kirov' ,

'2060600' ,

'28 .12.2013 ' ,

] ) ;






Do not forget to put all this in the crontab and wait for the catch. Successful trips.



PS php 5.5, but what to change for 5.4 and less, I think everyone understands, and Dada, there is no OOP, no patterns and no thoughtful design of the code, it’s just a script that works for now (until the algorithm changes the algorithm)

Source: https://habr.com/ru/post/206146/



All Articles