""" 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 = self.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 = self.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 = self.get_soup("%s/cmdr/%s" % (BASE_URL, cmdr_id)) else: cmdr_soup = self.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]