diff --git a/README.md b/README.md index b30943a..1e70c10 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,60 @@ # schiene -schiene is a Python library for interacting with Bahn.de +schiene is a Python library for interacting with Bahn.de. Consider it a unofficial API client. + +## Install + +``` +pip install schiene +``` + +## Usage +```python +>>> import schiene +>>> s = schiene.Schiene() +>>> s.connections('Mannheim HbF', 'Stuttgart HbF') +[{'arrival': '13:08', + 'canceled': True, + 'delay' : { + 'delay_departure' : 15, + 'delay_arrival': 0 + } + 'departure': '12:30', + 'details': 'http://mobile.bahn.de/bin/mobil/query.exe/dox?ld=15085&n=1&i=or.0179785.1439546366&rt=1&use_realtime_filter=1&co=C0-1&vca&HWAI=CONNECTION$C0-1!details=opened!&', + 'price': 39.0, + 'products': ['ICE'], + 'time': '0:38', + 'transfers': 0}, + {'arrival': '13:54', + 'departure': '12:38', + 'details': 'http://mobile.bahn.de/bin/mobil/query.exe/dox?ld=15085&n=1&i=or.0179785.1439546366&rt=1&use_realtime_filter=1&co=C0-2&vca&HWAI=CONNECTION$C0-2!details=opened!&', + 'ontime': True, + 'price': 30.0, + 'products': ['S', 'EC'], + 'time': '1:16', + 'transfers': 1}, + ...] +>>> s.stations('Hamburg') +[{'extId': '008002549', + 'id': 'A=1@O=Hamburg ' + 'Hbf@X=10006908@Y=53552732@U=80@L=008002549@B=1@p=1439332022@', + 'prodClass': '15', + 'state': 'id', + 'type': '1', + 'typeStr': '[Bhf/Hst]', + 'value': 'Hamburg Hbf', + 'weight': '24258', + 'xcoord': '10006908', + 'ycoord': '53552732'}, + {'extId': '008002548', + 'id': 'A=1@O=Hamburg ' + 'Dammtor@X=9989568@Y=53560751@U=80@L=008002548@B=1@p=1439332022@', + 'prodClass': '31', + 'state': 'id', + 'type': '1', + 'typeStr': '[Bhf/Hst]', + 'value': 'Hamburg Dammtor', + 'weight': '27663', + 'xcoord': '9989568', + 'ycoord': '53560751'}, + ...] +``` diff --git a/schiene/__init__.py b/schiene/__init__.py new file mode 100644 index 0000000..a646815 --- /dev/null +++ b/schiene/__init__.py @@ -0,0 +1 @@ +from schiene.schiene import Schiene diff --git a/schiene/schiene.py b/schiene/schiene.py new file mode 100755 index 0000000..2be176a --- /dev/null +++ b/schiene/schiene.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python3 +import requests +import json +from datetime import datetime +from bs4 import BeautifulSoup + + +def parse_connections(html): + soup = BeautifulSoup(html, "lxml") + connections = list() + + for row in soup.find_all("td", class_="overview timelink")[1:]: + columns = row.parent.find_all("td") + data = { + 'details': columns[0].a.get('href'), + 'departure': columns[0].a.contents[0].string, + 'arrival': columns[0].a.contents[2].string, + 'transfers': int(columns[2].contents[0]), + 'time': columns[2].contents[2], + 'products': columns[3].contents[0].split(', '), + 'price': columns[3].contents[3].string.strip().replace(',', '.') + } + + if data['price'] == "": + data['price'] = None + else: + data['price'] = float(data['price']) + + if columns[1].find('img'): + data['canceled'] = True + elif columns[1].find('span', class_="okmsg"): + data['ontime'] = True + elif columns[1].find('span', class_="red"): + if hasattr(columns[1].contents[0], 'text'): + delay_departure = columns[1].contents[0].text.replace("ca. +", "") + else: + delay_departure = 0 + if hasattr(columns[1].contents[2], 'text'): + delay_arrival = columns[1].contents[2].text.replace("ca. +", "") + else: + delay_arrival = 0 + data['delay'] = { + 'delay_departure': int(delay_departure), + 'delay_arrival': int(delay_arrival) + } + connections.append(data) + return connections + +def parse_stations(html): + """ + Strips JS code, loads JSON + """ + html = html.replace('SLs.sls=', '').replace(';SLs.showSuggestion();', '') + html = json.loads(html) + return html['suggestions'] + + +class Schiene(): + + def stations(self, station, limit=10): + """ + Find stations for given queries + + Args: + station (str): search query + limit (int): limit number of results + """ + query = { + 'start': 1, + 'S': station + '?', + 'REQ0JourneyStopsB': limit + } + rsp = requests.get('http://reiseauskunft.bahn.de/bin/ajax-getstop.exe/dn', params=query) + return parse_stations(rsp.text) + + + def connections(self, origin, destination, dt=datetime.now()): + """ + Find connections between two stations + + Args: + origin (str): origin station + destination (str): destination station + dt (datetime): date and time for query + """ + query = { + 'S': origin, + 'Z': destination, + 'date': dt.strftime("%d.%m.%y"), + 'time': dt.strftime("%H:%M"), + 'start': 1 + } + rsp = requests.get('http://mobile.bahn.de/bin/mobil/query.exe/dox?', params=query) + return parse_connections(rsp.text) diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..b88034e --- /dev/null +++ b/setup.cfg @@ -0,0 +1,2 @@ +[metadata] +description-file = README.md diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..b2f5a48 --- /dev/null +++ b/setup.py @@ -0,0 +1,18 @@ +from distutils.core import setup +setup( + name = 'schiene', + packages = ['schiene'], + version = '0.12', + license = 'MIT', + description = 'schiene is a Python library for interacting with Bahn.de', + author = 'Kevin Kennell', + author_email = 'kevin@fileperms.org', + install_requires=[ + 'requests>=2.7.0', + 'beautifulsoup4>=4.4.0' + ], + url = 'https://github.com/kevvvvv/schiene', + download_url = 'https://github.com/kevvvvv/schiene/tarball/0.12', + keywords = ['bahn', 'api'], + classifiers = [], +)