def _submit_form(self): log.info("Submitting dates.") with IFrameSwitch(self._driver, "childFrame"): with IFrameSwitch(self._driver, "frame3"): self._driver.wait().until( EC.element_to_be_clickable( (By.XPATH, self.done_button_xpath))) self._driver.click(self.done_button_xpath, xpath=True)
def get_install_date(self): """ Install date is the earliest date we can request - located in a hidden input element on the page. """ with IFrameSwitch(self._driver, "childFrame"): with IFrameSwitch(self._driver, "frame3"): log.info("Finding inverter install date.") return self._driver.find_or_raise( self.install_date_selector).get_attribute("value")
def click_ac_power_button(self): """ This switches data to kW format. """ with IFrameSwitch(self._driver, "childFrame"): with IFrameSwitch(self._driver, "frame3"): log.info("Waiting to see AC Power Button.") self._driver.wait().until( EC.element_to_be_clickable((By.ID, self.ac_power_id))) log.info("Clicking AC Power button.") self._driver.find_element_by_id(self.ac_power_id).click() self._driver.sleep(1)
def _click_range_button(self): """ This opens a form with two datepickers. """ with IFrameSwitch(self._driver, "childFrame"): with IFrameSwitch(self._driver, "frame3"): self._driver.wait().until( EC.element_to_be_clickable( (By.CSS_SELECTOR, self.range_button_selector))) log.info("Clicking on Range button.") self._driver.click(self.range_button_selector) self._driver.sleep(1)
def _enter_date(self, date_obj: datetime, date_input_selector): with IFrameSwitch(self._driver, "childFrame"): with IFrameSwitch(self._driver, "frame3"): self._driver.wait().until( EC.presence_of_element_located( (By.CSS_SELECTOR, date_input_selector))) self._driver.clear(date_input_selector) date_string = self.date_to_string(date_obj) log.info("Entering date {}".format(date_string)) self._driver.fill(date_input_selector, date_string) # Click outside of the date picker, helps make "Done" button selectable self._driver.click(self.title_dialog_selector) self._driver.sleep(2)
def get_bill_details(self, bill_row: BillSummaryRow): """Click on the 'details' link for a given bill summary, and scrape the resulting page""" with IFrameSwitch(self.driver, "mainFrame"): # We open the page in a new window by shift-clicking. actions = ActionChains(self.driver) actions.move_to_element(bill_row.detail_link) actions.key_down(Keys.SHIFT) actions.click(bill_row.detail_link) actions.key_up(Keys.SHIFT) actions.perform() self.driver.wait().until(window_count_equals(2)) other_window = self.driver.window_handles[1] detail_raw = {} with WindowSwitch(self.driver, other_window, close=True): WebDriverWait(self.driver, 20).until( EC.presence_of_element_located((By.XPATH, "//table"))) table = self.driver.find_element_by_tag_name("table") for row in table.find_elements_by_tag_name("tr"): cells = row.find_elements_by_tag_name("td") if len(cells) >= 2: row_label = cells[0].text.strip() detail_raw[row_label] = cells[1].text.strip() return BillDetail( account=str(detail_raw["Account"]), rate=str(detail_raw["Rate"]), bill_start=parse_date(detail_raw["Bill Start"]).date(), bill_stop=parse_date(detail_raw["Bill Stop"]).date(), total_kwh=self.parse_float(detail_raw["Total kWh"]), on_peak_kw=self.parse_float(detail_raw["On Peak KW"]), cost=self.parse_cost(detail_raw["Total Bill"]), )
def func_wrapper(self, *args, **kwargs): iframe_selector = self.get_iframe_selector() if iframe_selector: # Switches to iframe only if exists with IFrameSwitch(self._driver, self.get_iframe_selector()): return func(self, *args, **kwargs) else: return func(self, *args, **kwargs)
def select_inverter_from_both_dropdowns(self, inverter_id: str): """ SolrenView has two dropdowns to compare inverters. Since we're scraping one inverter at a time, we're selecting the same inverter from both dropdowns - this will also halve the amount of data we're requesting at a time. """ with IFrameSwitch(self._driver, "childFrame"): with IFrameSwitch(self._driver, "frame3"): log.info("Selecting inverter from LHS dropdown.") self._select_individual_inverter( self.dropdown_button_one_selector, self.lhs_li_xpath, inverter_id) log.info("Selecting same inverter from RHS dropdown.") self._select_individual_inverter( self.dropdown_button_two_selector, self.rhs_li_xpath, inverter_id)
def get_meters(self) -> List[MeterInfo]: """Scrape the meter data from this page into a list of MeterInfo objects""" results = [] with IFrameSwitch(self.driver, "mainFrame"): table = self.driver.find_element(*self.ProfileTableLocator) current_meter = None current_stop_date = None for row in table.find_elements_by_tag_name("tr"): # This table has two kinds of rows: "primary" rows, which describe a meter and its first channel; # and supplementary "channel" rows, which describe additional channels for a given meter. The # primary row will appear first, followed by a channel row for each channel beyond the first. # Therefore, we keep track of the "current" meter, so that when we come across a channel row we # known which meter to associate it with. cells = row.find_elements_by_tag_name("td") if len(cells) >= 9: # Each meter channel reports the dates for which data is available (start and end date). However, # in all observed cases the end date is specified once, on the primary row for the meter (opposed # to the start date, which appears for each channel). However, in case its possible for a channel # to report a different stop date, we still check for one, even if we are sitting on a channel row. if len(cells) == 10: current_stop_date = parse_date( cells[9].text.strip()).date() meter_name = cells[0].text.strip() if meter_name: # This indicates we have hit a new "primary" row, and thus need to emit a record for the # previous active meter, if there is one. if current_meter: results.append(current_meter) current_meter = MeterInfo( name=cells[0].text.strip(), account=cells[1].text.strip(), meter_id=cells[2].text.strip(), address=cells[3].text.strip(), meter_number=cells[4].text.strip(), iph=cells[5].text.strip(), channels=[], ) if current_meter: current_meter.channels.append( ChannelInfo( id=cells[6].text.strip(), units=cells[7].text.strip(), data_start=parse_date( cells[8].text.strip()).date(), data_end=current_stop_date, )) if current_meter: results.append(current_meter) return results
def set_date_range(self, start: date, end: date): date_format = "%m/%d/%Y" with IFrameSwitch(self.driver, "mainFrame"): start_elem = self.driver.find_element(*self.StartDateLocator) start_elem.clear() start_elem.send_keys(start.strftime(date_format)) end_elem = self.driver.find_element(*self.StopDateLocator) end_elem.clear() end_elem.send_keys(end.strftime(date_format))
def select_account(self, account_id): with IFrameSwitch(self.driver, "mainFrame"): selector = Select( self.driver.find_element(*self.MeterSelectLocator)) try: selector.select_by_value(account_id) except NoSuchElementException: raise saltriver_errors.MeterNotFoundError.for_account( account_id)
def _export_data(self) -> str: log.info("Exporting data.") with IFrameSwitch(self._driver, "childFrame"): with IFrameSwitch(self._driver, "frame3"): self._driver.wait().until( EC.element_to_be_clickable( (By.XPATH, self.export_data_xpath))) self._driver.sleep(2) export_button = self._driver.find_element_by_xpath( self.export_data_xpath) self._driver.execute_script("arguments[0].click();", export_button) # Wait for csv to download download_dir = self._driver.download_dir filename = self._driver.wait(60).until( file_exists_in_dir(download_dir, r".*\.csv$")) file_path = os.path.join(download_dir, filename) return file_path
def get_bill_summaries(self): results = [] with IFrameSwitch(self.driver, "mainFrame"): table = self.driver.find_element(*self.BillTableLocator) for row in table.find_elements_by_tag_name("tr"): cells = row.find_elements_by_tag_name("td") if len(cells) == 10 and cells[0].text.strip() != "Total": results.append( BillSummaryRow( detail_link=cells[0].find_element_by_tag_name("a"), stop_date=parse_date(cells[1].text.strip()).date(), rate=cells[2].text.strip(), max_kw=self.parse_float(cells[3].text.strip()), total_kwh=self.parse_float(cells[4].text.strip()), cost=self.parse_cost(cells[9].text.strip()), )) return results
def goto_bill_history(self): with IFrameSwitch(self.driver, "mainFrame"): self.driver.find_element(*self.BillsByAccountLink).click()
def download_interval_data(self): with IFrameSwitch(self.driver, "mainFrame"): log.info("clicking submit") self.driver.find_element(*self.SubmitSelector).click()
def select_meter_by_id(self, meter_id: str): log.info("select meter by id") with IFrameSwitch(self.driver, "mainFrame"): selector = Select( self.driver.find_element(*self.MeterSelectLocator)) selector.select_by_value(meter_id)
def basic_configuration(self): log.info("basic_configuration") with IFrameSwitch(self.driver, "mainFrame"): self.driver.find_element(*self.FifteenMinuteOptionLocator).click() self.driver.find_element(*self.DemandDatatypeLocator).click()
def generate_report(self): with IFrameSwitch(self.driver, "mainFrame"): self.driver.find_element(*self.NextButtonLocator).click()
def select_longest_report(self): with IFrameSwitch(self.driver, "mainFrame"): selectors = self.driver.find_elements(*self.TimeButtonSelector) longest = max(selectors, key=lambda s: int(s.get_attribute("value"))) longest.click()
def wait_until_ready(self): with IFrameSwitch(self._driver, "childFrame"): log.info("Waiting to see the site analytics tab.") self._driver.wait().until( EC.presence_of_element_located( (By.XPATH, self.site_analytics_xpath)))
def goto_meter_profiles(self): with IFrameSwitch(self.driver, "mainFrame"): self.driver.find_element(*self.MeterProfilesLink).click()
def navigate_to_site_analytics(self): with IFrameSwitch(self._driver, "childFrame"): log.info("Clicking on the site analytics tab.") self._driver.click(self.site_analytics_xpath, xpath=True)
def wait_until_ready(self): with IFrameSwitch(self._driver, "childFrame"): # Page blocked by a loading indicator - wait for this to disappear self._driver.wait().until( EC.invisibility_of_element_located( (By.XPATH, self.block_ui_xpath)))
def goto_interval_download(self): log.info("click interval download") with IFrameSwitch(self.driver, "mainFrame"): self.driver.find_element(*self.IntervalDownloadLink).click()
def goto_reports(self): with IFrameSwitch(self.driver, "banner"): self.driver.find_element(*self.ReportPageLink).click()