def attempt(self, pilot: iTunesConnectPilot): yield ClickElementManeuver( instruction='select the last 30 days', seeker=lambda p: p.soup.find('div', {'class': 'chartdatepicker'})) yield ClickElementManeuver( instruction='select the last 30 days', seeker=lambda p: p.soup.find('div', text='Last 30 Days'))
def attempt(self, pilot: iTunesConnectPilot): yield ClickElementManeuver( instruction='click the profile menu dropdown', seeker=lambda p: p.soup.find( 'div', {'class': 'itc-user-profile-controls-menu'})) yield ClickElementManeuver(instruction='select client profile', seeker=lambda p: p.soup.find( 'li', title=pilot.client_profile_name))
def attempt(self, pilot: iTunesConnectPilot): yield ClickElementManeuver( instruction='click on the view-by dropdown', seeker=lambda p: p.soup.find('div', {'class': 'view-by-menu'})) yield ClickElementManeuver( instruction='click the impressions menu item', seeker=lambda p: p.soup.find('div', text=self.view_by_text)) sleep(self.wait_after)
def attempt(self, pilot: AppsFlyerPilot): yield ClickElementManeuver( instruction='click the date range picker', seeker=lambda p: p.soup.find('div', {'class': 'date-range-picker-button'}) ) selector = CalendarSelector(browser=pilot.browser) self.ordnance = selector.get_last_day_available() yield ClickElementManeuver( instruction='dismiss date range picker', seeker=lambda p: p.soup.find('button', {'class': 'date-range-picker-control-button'}, text=re.compile('Cancel')) )
def attempt(self, pilot: AppsFlyerPilot): yield ClickElementManeuver( instruction='click the date range picker', seeker=lambda p: p.soup.find('div', {'class': 'date-range-picker-button'}) ) selector = CalendarSelector(browser=pilot.browser) selector.select_start_date(self.start_date) selector.select_end_date(self.end_date) yield ClickElementManeuver( instruction='apply date range', seeker=lambda p: p.soup.find('button', {'class': 'date-range-picker-control-button'}, text=re.compile('Apply')) )
def attempt(self, pilot: RaspadorTemplatePilot, fly: Callable[[Maneuver], Maneuver]): click_manuever = ClickElementManeuver( instruction='click the Start button', seeker=lambda p: p.soup.find('a', text=self.item_text)) fly(click_manuever) sleep(self.wait_after)
def attempt(self, pilot: AppsFlyerPilot): email_element = yield ClickElementManeuver( instruction='click the email filed', seeker=lambda p: p.soup.find('input', {'id': 'user-email'}) ) email_element.ordnance.send_keys(pilot.email) sleep(1) password_element = yield ClickElementManeuver( instruction='click the password field', seeker=lambda p: p.soup.find('input', {'id': 'password-field'}) ) password_element.ordnance.send_keys(pilot.password) sleep(1) password_element.ordnance.send_keys(Keys.RETURN) sleep(pilot.sign_in_wait)
def attempt(self, pilot: PeriscopePilot): email_element = yield ClickElementManeuver( instruction='click the email filed', seeker=lambda p: p.soup.find('input', placeholder='Enter email address')) email_element.ordnance.send_keys(pilot.email) password_element = yield ClickElementManeuver( instruction='click the password field', seeker=lambda p: p.soup.find('input', placeholder='Enter password' )) password_element.ordnance.send_keys(pilot.password) yield ClickElementManeuver( instruction='click the login button', seeker=lambda p: p.soup.find('span', text='LOG IN')) sleep(pilot.sign_in_wait)
def attempt(self, pilot: AppsFlyerPilot): yield ClickElementManeuver( instruction='click the table toggle button', seeker=lambda p: p.soup.find('div', {'class': 'toggle-button-label'}, text=re.compile('Table')) ) yield ClickElementManeuver( instruction='click the on day toggle button', seeker=lambda p: p.soup.find('div', {'class': 'toggle-button-label'}, text=re.compile('On day')) ) yield ClickElementManeuver( instruction='select days dropdown', seeker=lambda p: p.soup.find('div', {'class': 'qa-days-selector'}) ) yield ClickElementManeuver( instruction='select 180 days', seeker=lambda p: p.soup.find('div', {'class': 'af-tooltip-content'}, text=re.compile('180 Days')) )
def attempt(self, pilot: GooglePlayPilot): yield ClickElementManeuver( instruction='click on the "Use classic Play Console" button', seeker=lambda p: p.soup.find('span', {'class': 'label'}, text=re.compile('Use classic Play Console')).parent ) sleep(5) pilot.browser.driver.close() assert len(pilot.browser.driver.window_handles) == 1 pilot.browser.driver.switch_to.window(pilot.browser.driver.window_handles[0])
def attempt(self, pilot: RaspadorTemplatePilot): iframe = pilot.browser.driver.find_elements_by_tag_name('iframe')[0] pilot.browser.driver.switch_to_frame(iframe) email_element = yield ClickElementManeuver( instruction='click the email field', seeker=lambda p: p.soup.find('input', {'name': 'email'})) email_element.ordnance.send_keys(pilot.email) sleep(1) email_element.ordnance.send_keys(Keys.RETURN) sleep(1) password_element = yield ClickElementManeuver( instruction='click the password field', seeker=lambda p: p.soup.find('input', {'name': 'password'})) password_element.ordnance.send_keys(pilot.password) sleep(1) password_element.ordnance.send_keys(Keys.RETURN) pilot.browser.driver.switch_to.default_content() sleep(pilot.sign_in_wait)
def attempt(self, pilot: iTunesConnectPilot): yield ClickElementManeuver( instruction='click the add filter button', seeker=lambda p: p.soup.find('div', {'class': 'addfilter_button'})) def find_source_type_element(parser): icons = parser.soup.find_all('div', {'class': 'more cicon-right'}) for sibling in [icon.find_previous_sibling() for icon in icons]: if sibling.text == 'Source Type': return sibling return None if self.filter_text: source_type_element = (yield ElementManeuver( instruction='click the add filter button', seeker=find_source_type_element, )).ordnance action = ActionChains(pilot.browser.driver) action.reset_actions() source_type_web_element = pilot.browser.driver.find_element_by_xpath( source_type_element.xpath) action.move_to_element(source_type_web_element).perform() sleep(1) popover_xpath = "div[contains(@class, 'children popover-wrap')]" yield ClickElementManeuver( instruction='click the filter taret button', xpath= f"//{popover_xpath}//child::div[contains(text(),'{self.filter_text}')]" ) action.reset_actions() sleep(5) yield ExportCSVManeuver() yield ClickElementManeuver( instruction='click the close filter button', seeker=lambda p: p.soup.find_all('div', {'class': 'killer'})[-1], )
def attempt(self, pilot: AppsFlyerPilot): yield ClickElementManeuver( instruction='click the edit cohort button', seeker=lambda p: p.soup.find('div', {'class': 'edit-button'}, text=re.compile('Edit cohort')) ) sleep(1) for _ in range(max(0, len(self.groupings) - 1)): yield ClickElementManeuver( instruction='add a report grouping', seeker=lambda p: p.soup.find('div', {'class': 'link-title'}, text=re.compile('Group by')) ) sleep(.5) parser = GroupByDropdownsParser.from_browser(browser=pilot.browser) group_by_children = parser.parse().deploy() assert len(group_by_children) == len(self.groupings) children = [Element(soup_element=c, browser=pilot.browser) for c in group_by_children] children = [c for c in children if c.soup_element.text not in self.groupings] filtered_groupings = [g for g in self.groupings if g not in [g.text for g in group_by_children]] for index, child in enumerate(children): child.click() input_element = Element( soup_element=child.soup_element.findChild('input'), browser=pilot.browser ) input_element.send_keys(filtered_groupings[index]) sleep(.5) input_element.send_keys(Keys.DOWN) input_element.send_keys(Keys.ENTER) sleep(.5) yield ClickElementManeuver( instruction='click the apply changes button', seeker=lambda p: p.soup.find('button', text=re.compile('Apply changes')) )
def attempt(self, pilot: GooglePlayPilot): sleep(2) yield ClickElementManeuver( instruction='click the bulk export download button', seeker=lambda p: p.soup.find('a', {'href': f'#BulkExportPlace:bep={pilot.app_id}&bet=USER_ACQUISITION'}) ) sleep(5) for date in self.download_dates: yield ClickElementManeuver( instruction='click the year accordion', seeker=lambda p: p.soup.find('div', {'class': 'gwt-Label'}, text=re.compile(f'{date.year}')) ) sleep(2) yield ClickElementManeuver( instruction='click the bulk export download button', seeker=lambda p: p.soup.find('button', {'aria-label': f'Download: Retained installers report, {calendar.month_name[date.month]} {date.year}'}) ) yield ClickElementManeuver( instruction='click the year accordion', seeker=lambda p: p.soup.find('div', {'class': 'gwt-Label'}, text=re.compile(f'{date.year}')) ) sleep(2) current_dir = Path('.') downloaded_file_paths = [p for p in current_dir.glob(f'retained_installers_{pilot.app_id}*.zip')] renamed_downloaded_file_paths = [] for file in downloaded_file_paths: target = f'{pilot.download_path.absolute()}/{file.name}' file.rename(target) renamed_downloaded_file_paths.append(Path(target)) self.ordnance = renamed_downloaded_file_paths
def attempt(self, pilot: iTunesConnectPilot): impressions_before_check = int( (yield ElementManeuver( instruction='find impressions element', seeker=lambda p: p.soup.find('div', {'class': 'itemtotal'})) ).ordnance.soup_element.text.replace(',', '')) yield ClickElementManeuver(instruction='click the checkbox container', seeker=lambda p: p.soup.find( 'div', {'itc-checkbox': 'isUniqueSel'})) sleep(3) impressions_after_check = int( (yield ElementManeuver( instruction='find impressions element', seeker=lambda p: p.soup.find('div', {'class': 'itemtotal'})) ).ordnance.soup_element.text.replace(',', '')) if impressions_after_check < impressions_before_check: yield ClickElementManeuver( instruction='click the checkbox container', seeker=lambda p: p.soup.find('div', {'itc-checkbox': 'isUniqueSel'})) sleep(3)
def attempt(self, pilot: PeriscopePilot, fly: Callable[[Maneuver], Maneuver]): fly( ClickElementManeuver(instruction='click the refresh icon', seeker=lambda p: p.soup.find( 'div', {'class': 'refresh-icon'})))
def attempt(self, pilot: PeriscopePilot, fly: Callable[[Maneuver], Maneuver]): fly( ClickElementManeuver( instruction='open the filter bar', seeker=lambda p: p.soup.find('div', {'class': 'filters-bar'})))
def attempt(self, pilot: GooglePlayPilot): yield NavigationManeuver(url='https://accounts.google.com/signin/v2/identifier?service=androiddeveloper&passive=true&continue=https%3A%2F%2Fplay.google.com%2Fconsole%2Fdeveloper%2F') yield SignInManeuver() # This interact halts the program so that 2-factor auth can be used to sign in # continue after successfully using the Gmail app to sign in, or after the following manual steps are completed yield InteractManeuver() # ----- comment this block out if these things should be done manually ---------- company_name = pilot.config['company_name'] yield ClickElementManeuver( instruction=f'click the company name after signing in: {company_name}', seeker=lambda p: p.soup.find('div', {'class': 'business-name'}, text=re.compile(company_name)) ) sleep(5) yield OpenClassicPlayConsoleManeuver() # ----- comment this block out if these things should be done manually ---------- # If the OpenClassicPlayConsole isn't working, or is not to be used, these things need to be done manually: # 1. click on the "Use classic Play Console" button # 2. copy the url in the new browser window # 3. close the new browser window and paste in the copied link in the original browser window # 4. re-select the client account # 5. enter "C" for "Continue" in the console yield ClickXPathSequenceManeuver(xpaths=[ # f"//a/descendant::span[text()='{pilot.company_name}']", f"//a/descendant::div[text()='{pilot.app_id}']", "//button/descendant::span[text()='User acquisition']", "//a/descendant::span[text()='Acquisition reports']", ]) sleep(5) date_keys = {'apcs', 'apce'} url_parts = [p.split('=') for p in pilot.browser.current_url.split('&')] now = datetime.datetime.utcnow() for p in url_parts: if p[0] in date_keys: p[1] = datetime.datetime.strftime(now, '%Y-%m-%d') url_parts.append(['ts', 'FIFTEEN_DAYS']) new_url = '&'.join(['='.join(p) for p in url_parts]) yield NavigationManeuver(url=new_url) sleep(10) url_parts = [p.split('=') for p in pilot.browser.current_url.split('&')] for p in url_parts: if p[0] in date_keys: url_date = p[1] last_date_available = datetime.datetime.strptime(url_date, '%Y-%m-%d') data_frame = pd.DataFrame() date_range = [last_date_available - datetime.timedelta(days=d) for d in range(pilot.days_back)] data_frame = (yield ScrapeDateRangeManeuver(date_range=date_range)).deploy() data_frame['app_id'] = pilot.app_id data_frame.reset_index(drop=True, inplace=True) data_frame.to_csv(str(pilot.download_path / 'GooglePlayScraper.csv')) pilot.ordnance = data_frame def month_delta(date, delta): m, y = (date.month+delta) % 12, date.year + ((date.month)+delta-1) // 12 if not m: m = 12 d = min(date.day, calendar.monthrange(y, m)[1]) return date.replace(day=d,month=m, year=y) yield DownloadBulkExportManeuver( download_dates=[ last_date_available, month_delta(last_date_available, -1), ] ) processor = (yield ProcessGooglePlayDataManeuver()).deploy() yield SendDataToSlackManeuver( data_path=processor.processed_data_path, min_date=processor.min_processed_date, max_date=processor.max_processed_date )
def attempt(self, pilot: iTunesConnectPilot): yield ClickElementManeuver( instruction='click the metrics nav bar item', seeker=lambda p: p.soup.find('a', text=self.item_text)) sleep(self.wait_after)
def attempt(self, pilot: iTunesConnectPilot): yield ClickElementManeuver( instruction='click the export button', seeker=lambda p: p.soup.find('div', {'class': 'cicon-download'}))