示例#1
0
 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'))
示例#2
0
 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))
示例#3
0
 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)
示例#4
0
  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'))
    )
示例#5
0
  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'))
    )
示例#6
0
 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)
示例#7
0
  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)
示例#8
0
    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)
示例#9
0
 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'))
   )
示例#10
0
  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])
示例#11
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)
示例#12
0
    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],
        )
示例#13
0
  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'))
    )
示例#14
0
  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
示例#15
0
    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)
示例#16
0
 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'})))
示例#17
0
 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'})))
示例#18
0
  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
    )
示例#19
0
 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)
示例#20
0
 def attempt(self, pilot: iTunesConnectPilot):
     yield ClickElementManeuver(
         instruction='click the export button',
         seeker=lambda p: p.soup.find('div', {'class': 'cicon-download'}))