この記事では、ロシア鉄道のチケットを購入する際の問題と、ブラウザーでアクションを自動化して問題を解決する方法について説明します。
はじめに
数年前、 ロシア鉄道はticket.rzd.ruウェブサイトでチケットのオンライン販売を開始し、すぐにほとんどすべての列車に電子登録が登場しました(駅の窓でインターネットを介してチケットを購入する必要はありませんが、印刷したい場合はインターネットでチケットを購入できます)注文フォーム、およびそれを使用して、乗客のリストを持っている車掌に直接行きます)。
そのため、プロセスの所要時間は短くなり、その本質はサイトでチケットを購入することだけになりました。 しかし、人気のある目的地へのチケットは、事前に購入しないとすぐに解体され、多くの場合、必要な列車のチケットがないだけでなく、新年などの大きな祝日はもちろん、45日後にチケットが販売され、数日後にすでに在庫切れです。
多くの場合、誰かがチケットを引き渡し、時間内に購入できることを期待して、ページを座って更新しました。 チケットでページを集中的かつ継続的に更新することで、チケットを購入して出発する機会が常に得られたことに驚きましたが、そのような「ブルートフォース」に多くの時間と労力を費やさなければなりませんでした。
自動化
ある時点で、このプロセスを自動化するというアイデアが思い浮かびました。 購入と支払いの段階なしで、無料チケットの監視プロセスを自動化した予約をすぐに行います。 明らかにこれは危険な仕事です。
ハブでセレンとブラウザーでのアクションを自動化するためのそのアプリケーションに関する多くの記事を見て、それをこのタスクに適用することにしました。 Pythonのソリューション(このタスクに最適です)には、適切なパッケージをインストールする必要があります。
pip install selenium
コードレイアウトは、 Selenium IDE (Firefoxのプラグイン)を使用して、ユーザーアクションの事前記録を使用してページで標準アクションを実行するだけですばやく生成できます。 プラグインは公式Webサイトで入手できます。
次に、このコードを少し組み合わせて、表示された情報の解析、必要なチェック、アラームのトリガーを追加する必要がありました。
結果は、次のコードのようなものになります。
# 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'<div class="wotnumarrow">': train = strlist[i+1].replace('<span><b>','') if x == u'': # winsound.PlaySound('alarma.ogg', winsound.SND_NOWAIT) self.logger.info(u'-%s -%s %s' % ( train, strlist[i+3].replace('<b>','').replace('</b>',''), strlist[i+5].replace('<td><span>','').replace('</span></td>',''))) 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()
このコードは、5分ごとにチケットをチェックするなど、指定した間隔でサイクルで実行できます。
コードの記述とデバッグのプロセス全体に約30分かかりました。
必要な列車、日付、場所などについて、コードのチェックを固定できます。
このバージョンでは、検出時に、チケットが登場したことを知らせる音声信号が鳴ります。代わりに、メールまたはSMSを送信できますが、この場合、チケットを購入する時間がないだけです。
まとめ
サイトにはキャプチャはありませんが、同様のメカニズムを安全に使用できますが、突然表示された場合は、より複雑なものを考え出す必要があります。 誰が知っているか、将来的にはロシア鉄道はAPIを備えたサービスのようなものを持つでしょう。
驚いたことに、チケットは非常に頻繁に配られ、注文をすばやく完了すると、渡されたばかりのチケットを傍受する可能性が非常に高いことに注意してください。 チケットが登場することはよくありましたが、それを埋めた後に他の誰かがすでにそれを買っていたことが判明しました。
個人的な経験から、ほとんどのチケットは最終日に配られます。
素敵な旅行を!