def navigate_route(self, route, retry=False, timeout=NAV_TIMEOUT): if isinstance(route, str): route = self.routes.get(route) log.info('Navigating ' + str(route)) route.waypoints_reached = 0 if self.current_url != route.route_start: log.info('Navigating to route start: {}'.format(route.route_start)) jitter(.4) self.driver.get(route.route_start) for waypoint in route.waypoints: try: valid_dest = [] for w in route.waypoints[route.waypoints.index(waypoint):]: valid_dest.extend(w.dest) if waypoint.check_current(self.current_url): log.warning("Already at dest: '{}'".format( waypoint.check_current(self.current_url))) else: self.navigate_waypoint(waypoint, timeout, valid_dest) except NavigationException: try: handle_redirect(self, valid_dest=valid_dest, timeout=timeout, route=route) except RouteRedirect: if retry: log.warning('Retrying route') self.navigate_route(route, timeout=timeout) return else: raise route.waypoints_reached += 1 log.info('Route complete')
def save_cart(self): jitter(.4) self.driver.get(self.site_config.BASE_URL + self.site_config.cart_endpoint) cart = [] for element in wait_for_elements(self.driver, self.Locators.CART_ITEMS): try: cart.append(CartItem(element).data) except Exception: log.warning('Failed to parse a cart item') if cart: dump_toml( {'cart_item': sorted(cart, key=lambda k: k['product_id'])}, self.site_config.service.replace(' ', '') + '_cart')
def main_loop(driver, args): slot_prefs = get_prefs_from_conf() site_config = config.SiteConfig(args.service) wait_for_auth(driver) if args.save_cart: try: save_cart(driver, site_config) except Exception: log.error('Failed to save cart items') slot_route = build_route(site_config, 'SLOT_SELECT', args) slot_route.navigate(driver) slots = get_slots(driver, slot_prefs, slot_route) if slots: annoy() alert('Delivery slots available. What do you need me for?', 'Sosumi') else: executor = ThreadPoolExecutor() while not slots: log.info('No slots found :( waiting...') jitter(config.INTERVAL) driver.refresh() slots = get_slots(driver, slot_prefs, slot_route) if slots: alert('Delivery slots found') message_body = generate_message(slots, args.service, args.checkout) executor.submit(send_sms, message_body) executor.submit(send_telegram, message_body) if not args.checkout: break checked_out = False log.info('Attempting to select slot and checkout') while not checked_out: try: log.info('Selecting slot: ' + slots[0].full_name) slots[0].select() build_route(site_config, 'CHECKOUT', args).navigate(driver) checked_out = True alert('Checkout complete', 'Hero') except RouteRedirect: log.warning('Checkout failed: Redirected to slot select') slots = get_slots(driver, slot_prefs, slot_route) if not slots: break try: executor.shutdown() except Exception as e: log.error(e)
def save_cart(driver, site_config): filepath = '{}_cart_{}.toml'.format(site_config.service.replace(' ', ''), timestamp()) driver.get(config.BASE_URL + site_config.cart_endpoint) jitter(.4) cart = [] for element in wait_for_elements(driver, config.Locators.CART_ITEMS): try: cart.append(CartItem(element).data) except Exception: log.warning('Failed to parse a cart item') if cart: cart = sorted(cart, key=lambda k: k['product_id']) log.info('Writing {} cart items to: {}'.format(len(cart), filepath)) with open(filepath, 'w', encoding='utf-8') as f: toml.dump({'cart_item': cart}, f) # :)
def navigate_waypoint(self, driver, waypoint, timeout, valid_dest): log.info('Navigating ' + str(waypoint)) elem = wait_for_element(driver, waypoint.locator, timeout=timeout) jitter(.4) click_when_enabled(driver, elem) try: WebDriverWait(driver, timeout).until(EC.staleness_of(elem)) except TimeoutException: pass current = remove_qs(driver.current_url) if current == BASE_URL + waypoint.dest: log.info("Navigated to '{}'".format(waypoint.dest)) elif valid_dest and any(d in current for d in valid_dest): log.info("Navigated to valid dest '{}'".format(current)) else: raise NavigationException("Navigation to '{}' failed".format( waypoint.dest))
def main_loop(self): wait_for_auth(self) if self.args.save_cart: try: self.save_cart() except Exception: log.error('Failed to save cart items') self.navigate_route('SLOT_SELECT', retry=True) slots = self.get_slots() if slots: annoy() alert('Delivery slots available. What do you need me for?', 'Sosumi') else: self.executor = ThreadPoolExecutor() while not slots: log.info('No slots found :( waiting...') jitter(INTERVAL) self.driver.refresh() slots = self.get_slots() if slots: alert('Delivery slots found') message_body = self.generate_message(slots) self.executor.submit(send_sms, message_body) self.executor.submit(send_telegram, message_body) if not self.args.checkout: break checked_out = False log.info('Attempting to select slot and checkout') while not checked_out: try: log.info('Selecting slot: ' + slots[0].full_name) slots[0].select() self.navigate_route('CHECKOUT') checked_out = True alert('Checkout complete', 'Hero') except RouteRedirect: log.warning( 'Checkout failed: Redirected to slot select') slots = self.get_slots() if not slots: break if self.executor: self.executor.shutdown()
def navigate_waypoint(self, waypoint, timeout, valid_dest): if callable(waypoint.callable): log.info('Executing {}() before navigation'.format( waypoint.callable.__name__)) waypoint.callable(browser=self) log.info('Navigating ' + str(waypoint)) elem = wait_for_element(self.driver, waypoint.locator, timeout=timeout) jitter(.4) click_when_enabled(self.driver, elem) try: WebDriverWait(self.driver, timeout).until(EC.staleness_of(elem)) except TimeoutException: pass if waypoint.check_current(self.current_url): log.info("Navigated to '{}'".format( waypoint.check_current(self.current_url))) elif valid_dest and any(d in self.current_url for d in valid_dest): log.info("Navigated to valid dest '{}'".format(self.current_url)) else: raise NavigationException("Navigation to '{}' failed".format( waypoint.dest))