Пишем мониторинг наличия билетов на РЖД

от автора

Не раз слышал от своих знакомых, что было бы неплохо увидеть сайт который будет мониторить наличие свободных мест на ржд. Про себя я думал — «да неплохо бы» и благополучно забывал, но пост заставил меня вспомнить навыки копи паста, которыми я владею в совершенстве и обернуть это дело в питонячий код. Сразу оговорюсь что именно про мониторинг будет во второй части, а в этой будет про то: как ходить на РЖД из питона, что это за загадочный sleep про который писали в предыдущем посту и как живется на Google App Engine. Итак приступим:
image

Сначала я написал код, а потом задумался о хостинге, есстественно сайт не предполагал никакой наживы, а был лишь 4 fun, поэтому и хостинг должен быть бесплатным и тут я вспомнил про App Engine. Для начала работы стоит скачать SDK. Запускаем, указываем путь к будущему приложению: image

В указанной рабочей директории сознаем файл настроек app.yaml содержащий примерно следующее:

application: rzdzstan1 version: 1 runtime: python27 threadsafe: false api_version: 1  handlers: - url: /favicon.ico   static_files: favicon.ico   upload: favicon.ico  - url: /.*   script: web.py  libraries: - name: webapp2   version: "latest" 

Дальше в вышеобозначенной рабочей директории создаем, web.py и тут уже можно начинать писать код копипастить. Приложение будем строить на легковесном WebApp2. Итак пишем основные обработчики:

import webapp2  application = webapp2.WSGIApplication([     ('/', MainPage),     ('/trains', TrainListPage),     ('/suggester', SuggesterPage), ], debug=True)  def main():     application.run()  if __name__ == "__main__":     main() 

Далее, как и говорилось в базовой статье, нам понадобятся коды городов для создания запроса:

def getCityId(city, s):   req = 'http://pass.rzd.ru/suggester?lang=ru&stationNamePart=' + urllib.quote(city.encode('utf-8'))   respData = getResponse(req)   rJson = json.loads(respData)   for item in rJson:     if item['name'].lower() == city.lower():       s.response.out.write(u'Найден: '+item['name']+' -> '+str(item['id'])+'<br>')       return str(item['id'])   s.response.out.write(u'Не найден: '+city+'<br>')   s.response.out.write(u'Выбранный вами город не найден, попробуйте найти в списке и ввести еще раз:<a href="../">Вернуться</a><br>')   for item in rJson:     s.response.out.write(item['name']+'<br>')   return None 

Ну а дальше остается получить rid, SESSION_ID и сформировать окончательный запрос, не забывая что часто РЖД рвет соединения, отвечает 500 кодом и т.д. чтобы это замаскировать напишем пару костылей-обработчиков:

def getResponse(url):   good = False   while not good:     try:       resp = opener.open(url, timeout=5)       if resp.getcode() in [httplib.OK, httplib.CREATED, httplib.ACCEPTED]:         good = True     except (urllib2.HTTPError, HTTPException):       pass   return resp.read()  def getResponseStub(url):   r = json.loads(getResponse(url))   cnt = 0   while (r['result']!='OK' and cnt < 5):     sleep(1)     cnt+=1     r = json.loads(getResponse(url))   return r  def getFinalRequest():   req1 = 'http://pass.rzd.ru/timetable/public/ru?STRUCTURE_ID=735&layer_id=5371&dir=0&tfl=3&checkSeats=1&\ st0='+st0+'&code0='+id0+'&dt0='+date+'&st1='+st1+'&code1='+id1+'&dt1='+date    r = json.loads(getResponse(req1))   if (r['result']=='OK'):     s.response.out.write(r['tp'][0]['msgList'][0]['message']) #errType     s.response.out.write('<br>')     return   sid = str(r['SESSION_ID'])   rid = str(r['rid'])   req2 = 'http://pass.rzd.ru/timetable/public/ru?STRUCTURE_ID=735&layer_id=5371&dir=0&tfl=3&checkSeats=1&\ st0='+st0+'&code0='+id0+'&dt0='+date+'&st1='+st1+'&code1='+id1+'&dt1='+date+'&rid='+rid+'&SESSION_ID='+sid    r = getResponseStub(req2) 

И в получившемся ответе — лежит все необходимое для финального парсинга. Теперь о загадочном sleep, он переехал в функцию: getResponseStub, дело в том что когда мы запрашиваем req1 му таким образом просим поставить нас в очередь исполнения, и если сразу спросить req2 — результат может быть еще не получен. Радиоактивные исходники доступны тут качать осторожно. Попробовать в действии можно тут и тут ибо квоты там небольшие и под известным эффектом быстро закончатся, а пока эта статья проходит премодерацию попробую закинуть немного денег чтобы страница продержалась продолжительное время. В следующей части будем приделывать собственно саму нотификацию по емайлу.

ссылка на оригинал статьи http://habrahabr.ru/post/210420/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *