def count_large_cargos(b): """Gather number of large cargos in each planet.""" def find_planets(): return sln.finds(sln.find(b, By.ID, 'planetList'), By.CLASS_NAME, 'planetlink') num_planets = len(find_planets()) logging.info('Found {} planets'.format(num_planets)) fleet = {} for i in range(num_planets): logging.info('Navigating to planet #{}'.format(i)) # Need to find the planets again since previous references are stale. planets = find_planets() planets[i].click() # Navigate to fleet view (only needed for the first planet). if i == 0: logging.info('Navigating to fleet view') sln.finds(sln.find(b, By.ID, 'links'), By.CLASS_NAME, 'menubutton')[7].click() try: large_cargos = sln.find(sln.find(b, By.ID, 'button203', timeout=5), By.CLASS_NAME, 'level').text except TimeoutException: # Most likely indicates there is no fleet on this planet. logging.warn('No fleet on this planet') large_cargos = 0 logging.info('Planet {} has {} large cargos'.format(i, large_cargos)) fleet[i] = int(large_cargos) return fleet
def go_to_galaxy_view(b, planet_num): """Navigate to galaxy view and return home galaxy and system.""" planets = sln.finds(sln.find(b, By.ID, 'planetList'), By.CLASS_NAME, 'planetlink') logging.info('Found {} planets'.format(len(planets))) logging.info('Navigating to planet #{}'.format(planet_num)) planets[planet_num].click() logging.info('Navigating to galaxy view') sln.finds(sln.find(b, By.ID, 'links'), By.CLASS_NAME, 'menubutton')[8].click() galaxy = int(sln.find(b, By.ID, 'galaxy_input').get_attribute('value')) system = int(sln.find(b, By.ID, 'system_input').get_attribute('value')) logging.info('Home system is {}:{}'.format(galaxy, system)) return galaxy, system
def alert_if_attacked(b, args): """Check if we're being attacked and send an email.""" alert_div = sln.find(b, By.ID, 'attack_alert') # The classes contain "noAttack" if there's no attack and "soon" if there is. classes = alert_div.get_attribute('class').split() if 'noAttack' in classes: logging.info('No attack, exiting') return # Send an alert email. logging.info('Attack! Sending email to {}'.format(args.email_to)) subject = 'Attack alert' body = '{} is being attacked!'.format(sln.find(b, By.ID, 'playerName').text) email_lib.send_email(args.smtp_host, args.smtp_port, args.smtp_user, args.smtp_password, args.email_to, subject, body)
def go_to_system(b, galaxy, system): """Navigate to system and return num ongoing missions.""" logging.info('Navigating to {}:{}'.format(galaxy, system)) sln.find(b, By.ID, 'galaxy_input').send_keys(str(galaxy)) sln.find(b, By.ID, 'system_input').send_keys(str(system)) sln.find(b, By.CSS_SELECTOR, '#galaxyHeader .btn_blue').click() # Wait for loader to appear, then wait for it to disappear. sln.wait_until(b, By.ID, 'galaxyLoading', timeout=1, timeout_ok=True) sln.wait_until_not(b, By.ID, 'galaxyLoading', timeout=3, timeout_ok=True) return int(sln.find(b, By.ID, 'slotUsed').text)
def inspect(b, num_already_processed, num_allowed, galaxy, system, args): """Inspect a system. Args: b: Browser. num_already_processed: Num already processed in this system. num_allowed: Num probes allowed at this point. galaxy: Galaxy (for debug). system: System (for debug). args: Command-line args. Returns: num_processed: (int) Number of targets newly processed in this system. done: (bool) Whether the scan was complete. """ logging.info('Inspecting [{}:{}]...'.format(galaxy, system)) # Get list of planets in this system. players = [ p for p in sln.finds( b, By.CSS_SELECTOR, '.playername', timeout=2, timeout_ok=True) if len(p.get_attribute('class').split()) > 1 and 'js_no_action' not in p.get_attribute('class') ] logging.info('Found {} players'.format(len(players))) # Get list of potential targets based on their class (inactive, strong, etc). potential_targets = [] for player in players: classes = player.get_attribute('class').split() if len(classes) == 2: # normal players have 2 classes if args.include_normal: logging.info('Adding normal player') potential_targets.append(player) elif any(x in classes for x in [ 'noob', 'vacation', 'vacationlonginactive', 'vacationinactive', 'banned' ]): pass else: for classname, arg, label in [ ('inactive', args.include_inactive, 'inactive'), ('longinactive', args.include_inactive, 'inactive'), ('honorableTarget', args.include_honorable, 'honorable'), ('stronghonorableTarget', args.include_strong, 'strong'), ]: if classname in classes: if arg: logging.info('Adding {} player'.format(label)) potential_targets.append(player) break else: # no known classname found logging.warn( 'Skipping unsupported player (classes = {})'.format( classes)) logging.info('Found {} potential targets'.format(len(potential_targets))) # Iterate over potential targets and scan those with rank within bounds. num_processed = 0 for potential_target in potential_targets: if num_allowed == 0: # Reached max number of concurrent missions. return num_processed, False # Find player name. sln.hover(b, potential_target) player_name = potential_target.text # Find player ID (sometimes we need to try multiple times). player_id, tries = None, 0 while not player_id and tries < 10: tries += 1 player_id = sln.find(potential_target, By.TAG_NAME, 'a').get_attribute('rel') if not player_id: logging.warn('Skipping (could not find player ID)') continue # Find player rank. Sometimes it can't be done e.g. if player name is empty. player_rank, tries = None, 0 while not player_rank and tries < 10: tries += 1 for tooltip in sln.finds(b, By.ID, player_id): rank = sln.find(tooltip, By.TAG_NAME, 'a').text if rank: player_rank = int(rank) break if not player_rank: logging.warn('Skipping (could not find player rank') continue # Find planet name. planet_name = sln.find(sln.find(potential_target, By.XPATH, '..'), By.CLASS_NAME, 'planetname').text # Find planet position. planet_position = int( sln.find(sln.find(potential_target, By.XPATH, '..'), By.CLASS_NAME, 'position').text) logging.info('Potential target: {}:{}:{} [{}] - {} (rank {})'.format( galaxy, system, planet_position, planet_name, player_name, player_rank)) if not args.rank_min <= player_rank <= args.rank_max: logging.info('Skipping (outside allowed rank bounds)') continue if num_already_processed: logging.info('Skipping (already processed)') num_already_processed -= 1 continue logging.info('--> Sending probe to {}:{}:{}'.format( galaxy, system, planet_position)) sln.click( b, sln.find(sln.find(potential_target, By.XPATH, '..'), By.CLASS_NAME, 'espionage')) num_processed += 1 num_allowed -= 1 return num_processed, True
def attack_target(b, coords, planet_num, num_cargos): """Attack a planet at given `coords` from `planet_num` with `num_cargos`.""" # Navigate to planet. planets = sln.finds(sln.find(b, By.ID, 'planetList'), By.CLASS_NAME, 'planetlink') planet = planets[planet_num] logging.info('Navigating to planet {}'.format(planet_num)) planet.click() # Navigate to fleet view. logging.info('Navigating to fleet view') sln.finds(sln.find(b, By.ID, 'links'), By.CLASS_NAME, 'menubutton')[7].click() # Set num cargos. large_cargos = sln.find(sln.find(b, By.ID, 'button203'), By.CLASS_NAME, 'fleetValues') large_cargos.send_keys(str(num_cargos)) sln.find(b, By.ID, 'continue').click() # Set target coords. galaxy = sln.find(b, By.ID, 'galaxy') system = sln.find(b, By.ID, 'system') position = sln.find(b, By.ID, 'position') galaxy.clear() galaxy.send_keys(str(coords.galaxy)) system.clear() system.send_keys(str(coords.system)) position.clear() position.send_keys(str(coords.position)) position.send_keys(Keys.RETURN) # Launch attack. sln.find(b, By.ID, 'missionButton1').click() sln.find(b, By.ID, 'start').click() # Wait for fleet view to be visible again. sln.wait_until(b, By.ID, 'movements') logging.info( 'Launched attack on [{}:{}:{}] with {} cargos from planet {}'.format( coords.galaxy, coords.system, coords.position, num_cargos, planet_num))
def gather_reports(b, args): """Gather probe reports.""" logging.info('Gathering reports...') sln.find(b, By.CLASS_NAME, 'messages').click() reports = {} num_reports = 0 last_data_msg_id = None # to know when next page is ready while num_reports < args.max_reports: # Wait for page to be ready. page_ready = False while not page_ready: logging.info('Waiting for page to be ready') time.sleep(0.5) try: top_msg_id = sln.finds( b, By.CLASS_NAME, 'msg', timeout=5)[0].get_attribute('data-msg-id') except StaleElementReferenceException: continue except TimeoutException: # Most likely indicates there are no probe reports. logging.warn('Cannot find messages, returning empty list') return [] page_ready = last_data_msg_id is None or last_data_msg_id != top_msg_id last_data_msg_id = top_msg_id # Iterate over messages. for msg in sln.finds(b, By.CLASS_NAME, 'msg'): # Parse resources. resspans = sln.finds(msg, By.CLASS_NAME, 'resspan', timeout=1, timeout_ok=True) if len(resspans) != 3: logging.warn('Skipping message: could not parse resources') continue metal = parse_number(resspans[0].text.split(' ')[1]) crystal = parse_number(resspans[1].text.split(' ')[1]) deuterium = parse_number(resspans[2].text.split(' ')[1]) # Parse fleet info. fleet_info = sln.finds(msg, By.CLASS_NAME, 'compacting')[-1] counts = sln.finds(fleet_info, By.CLASS_NAME, 'ctn') if len(counts) != 2: logging.warn('Skipping message: could not parse fleet info') continue fleet_pts = parse_number(counts[0].text.split(' ')[1]) defense_pts = parse_number(counts[1].text.split(' ')[1]) # Parse target coords from the message title. title = sln.find(msg, By.CLASS_NAME, 'msg_title') links = sln.finds(title, By.TAG_NAME, 'a') if len(links) != 1: logging.warn('Skipping message: could not parse message title') continue # Text is of the form "<planet name> [galaxy:system:position]" coords = list( map(int, links[0].text.split(' ')[-1][1:-1].split(':'))) if len(coords) != 3: logging.warn('Skipping message: could not parse coords') continue # Add report to the dict. key = Coords(coords[0], coords[1], coords[2]) value = PlanetInfo(metal, crystal, deuterium, fleet_pts, defense_pts) reports[key] = value num_reports += 1 logging.info('Report #{}: {}: {}'.format(num_reports, key, value)) if num_reports >= args.max_reports: break if num_reports < args.max_reports: # Not done, go to next page. lis = sln.finds(sln.find(b, By.CLASS_NAME, 'pagination'), By.TAG_NAME, 'li') if len(lis) != 5: logging.warn('Could not find five elements, returning') break cur_page, total_pages = lis[2].text.split('/') if cur_page == total_pages: logging.info('Reached last page') break lis[3].click() def score(x): if args.sort_by == 'total': return x.metal + x.crystal + x.deuterium if args.sort_by == 'metal': return x.metal if args.sort_by == 'crystal': return x.crystal if args.sort_by == 'deuterium': return x.deuterium return sorted(reports.items(), key=lambda x: score(x[1]), reverse=True)
def find_planets(): return sln.finds(sln.find(b, By.ID, 'planetList'), By.CLASS_NAME, 'planetlink')
def open_browser_and_connect(args): """Open a Chrome browser and connect to OGame account.""" b = _open_browser(args) url = 'http://www.ogame.' + args.tld logging.info('Navigating to ' + url) b.get(url) # Close ad. try: sln.find( sln.find(b, By.CLASS_NAME, 'openX_int_closeButton', timeout=3), By.TAG_NAME, 'a').click() except TimeoutException: pass logging.info('Filling login form...') sln.find(b, By.ID, 'ui-id-1').click() # Login tab sln.find(b, By.ID, 'usernameLogin').send_keys(args.email) sln.find(b, By.ID, 'passwordLogin').send_keys(args.password) sln.find(b, By.ID, 'loginSubmit').click() # login # Get list of accounts. logging.info('Getting list of accounts...') accounts = sln.finds( sln.find(sln.find(b, By.ID, 'accountlist'), By.CLASS_NAME, 'rt-tbody'), By.CLASS_NAME, 'rt-tr') logging.info('Found {} accounts'.format(len(accounts))) # Use --univ_name if it was provided if args.univ_name: account_names = [] for account in accounts: account_name = sln.find(account, By.CLASS_NAME, 'server-name-cell').text account_names.append(account_name) if account_name == args.univ_name: logging.info('Navigating to account {}'.format(account_name)) sln.find(accounts[args.univ_num], By.TAG_NAME, 'button').click() break else: # could not find --univ_name raise ValueError('Could not find account with --univ_name = {}; ' 'accounts found are [{}]'.format( args.univ_name, ', '.join(account_names))) # Else use --univ_num else: if not 0 <= args.univ_num < len(accounts): raise ValueError( '--univ_num should be between 0 and {}; found {}'.format( len(accounts) - 1, args.univ_num)) account_name = sln.find(accounts[args.univ_num], By.CLASS_NAME, 'server-name-cell').text logging.info('Navigating to account {}'.format(account_name)) sln.find(accounts[args.univ_num], By.TAG_NAME, 'button').click() b.switch_to.window(b.window_handles[-1]) logging.info('Switched to tab ' + b.current_url) return b