Initial commit. This is based on code from ed_tools and fvbot.

This commit is contained in:
Anna Rose 2016-01-21 11:11:53 -05:00
commit 010ff377e5
3 changed files with 166 additions and 0 deletions

21
Readme.md Normal file
View File

@ -0,0 +1,21 @@
# inara.py
This is a simple python library that is used to retrieve and store data to inara.py.
It subclasses requests_cache.core.CachedSession to provide a specialized HTTP session to talk to inara.
Usage is simple:
from inara.inara import InaraSession
session = InaraSession(inara_username, inara_password)
session.update_location('Chona')
session.update_credits(1000000000)
info = session.get_cmdr_info()
pprint(info)
If the logged-in user is a member of a Wing, you can get information about wing-mates like so:
info = session.get_cmdr_info(wing_id, cmdr_id)
where the 'id's are the numeric identifiers visible in inara's URLs.

0
__init__.py Normal file
View File

145
inara.py Normal file
View File

@ -0,0 +1,145 @@
"""
A wrapper around the requests library to retrieve and update various information
about a commander from inara.cz
"""
from bs4 import BeautifulSoup
import re
import requests_cache
from requests_cache.core import CachedSession
BASE_URL = "http://inara.cz/"
CMDR_URL = BASE_URL + 'cmdr/'
# Some fun exceptions to raise!
class ServerError(Exception):
pass
class CredentialsError(Exception):
pass
class LoggingInException(Exception):
pass
class CmdrNotFoundException(Exception):
pass
class InaraSession(CachedSession):
def __init__(self, username, password):
CachedSession.__init__(self,
cache_name='inara',
backend='memory',
expire_after=600.0,
old_data_on_error=True)
self.username = username
self.password = password
self.inara_login()
def inara_login(self):
if (not self.username or not self.password):
raise CredentialsError()
data = {
"loginid": self.username,
"loginpass": self.password,
"formact": "ENT_LOGIN",
"location": "intro"
}
r = self.post(BASE_URL, data=data)
r.raise_for_status()
def _inara_is_logged_in(self, soup):
logout_link = soup.find(href=re.compile('ENT_LOGOUT'))
return logout_link is not None
def update_credits(self, credits):
soup = session.get_soup(CMDR_URL)
if not self._inara_is_logged_in(soup):
return False
oass = int(soup.find(id='oassinput')['value'])
data = {
"location": "cmdr",
"formact": "USER_CREDITS_SET",
"playercredits": credits,
"playercreditsassets": credits + oass,
"oass": oass,
}
r = self.post(CMDR_URL, data=data)
r.raise_for_status()
return True
def update_location(self, location):
data = {
'formact': 'USER_LOCATION_SET',
'playercurloc': location
}
r = self.post(CMDR_URL, data=data)
r.raise_for_status()
def get_cmdr_info(wing_id=None, cmdr_id=None):
result = {}
if wing_id is not None and cmdr_id is not None:
wing_soup = session.get_soup("%s/wing/%s" % (BASE_URL, wing_id))
result['rank'] = _get_rank(wing_soup, cmdr_id)
result['location'] = _get_location(wing_soup, cmdr_id)
if cmdr_id is not None:
cmdr_soup = session.get_soup("%s/cmdr/%s" % (BASE_URL, cmdr_id))
else:
cmdr_soup = session.get_soup(CMDR_URL)
result['balance'] = _get_cmdr_balance(cmdr_soup)
result['assets'] = _get_cmdr_assets(cmdr_soup)
return result
def get_soup(self, url):
r = self.get(url)
r.raise_for_status()
soup = BeautifulSoup(r.text, 'html.parser')
if not self._inara_is_logged_in(soup):
self.inara_login()
# invalidate the cache entry, since we only want logged-in data
self.cache.delete_url(url)
raise LoggingInException()
return soup
def _get_cmdr_row(soup, cmdr_id):
link = soup.find(attrs={'class': 'subtable'}).find(
href=re.compile('/cmdr/' + cmdr_id))
for parent in link.parents:
if parent.name == 'tr':
return parent
raise CmdrNotFoundException()
def _get_rank(soup, cmdr_id):
row = _get_cmdr_row(soup, cmdr_id)
return row.td.img['title']
def _get_location(soup, cmdr_id):
row = _get_cmdr_row(soup, cmdr_id)
location_link = row.find(href=re.compile('market'))
if not location_link or len(location_link.contents) == 0:
return "Unknown"
else:
return location_link.contents[0]
def _get_cmdr_balance(soup):
title_text = soup.find(text="Credit Balance")
br = title_text.parent.next_sibling
return br.contents[0]
def _get_cmdr_assets(soup):
title_text = soup.find(text="Overall assets")
br = title_text.parent.next_sibling
return br.contents[0]