-
Notifications
You must be signed in to change notification settings - Fork 105
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #453 from mrw298/feature/west-suffolk-council
feat: Add support for West Suffolk Council
- Loading branch information
Showing
3 changed files
with
131 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
120 changes: 120 additions & 0 deletions
120
uk_bin_collection/uk_bin_collection/councils/WestSuffolkCouncil.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
from selenium.webdriver.common.by import By | ||
from selenium.webdriver.common.keys import Keys | ||
from selenium.common.exceptions import TimeoutException | ||
from selenium.webdriver.support.ui import Select, WebDriverWait | ||
from selenium.webdriver.support import expected_conditions as EC | ||
from dateutil.parser import parse | ||
|
||
from uk_bin_collection.uk_bin_collection.common import create_webdriver, date_format | ||
from uk_bin_collection.uk_bin_collection.get_bin_data import AbstractGetBinDataClass | ||
|
||
|
||
class CouncilClass(AbstractGetBinDataClass): | ||
def wait_for_element(self, driver, element_type, element: str, timeout: int = 5): | ||
element_present = EC.presence_of_element_located((element_type, element)) | ||
self.wait_for_element_conditions(driver, element_present, timeout=timeout) | ||
|
||
def wait_for_element_conditions(self, driver, conditions, timeout: int = 5): | ||
try: | ||
WebDriverWait(driver, timeout).until(conditions) | ||
except TimeoutException: | ||
print("Timed out waiting for page to load") | ||
raise | ||
|
||
def parse_data(self, page: str, **kwargs) -> dict: | ||
web_driver = kwargs.get("web_driver") | ||
page = "https://westsuffolk-self.achieveservice.com/service/WSS_EX_Inf_Bin_Collection_Postcode_Lookup" | ||
|
||
# Assign user info | ||
user_postcode = kwargs.get("postcode") | ||
user_paon = kwargs.get("paon") | ||
|
||
# Create Selenium webdriver | ||
driver = create_webdriver(web_driver) | ||
driver.get(page) | ||
|
||
# Click the cookie button | ||
css_selector = "#close-cookie-message" | ||
self.wait_for_element(driver, By.CSS_SELECTOR, css_selector) | ||
cookie_button = driver.find_element(By.CSS_SELECTOR, css_selector) | ||
cookie_button.click() | ||
|
||
# switch to the form iframe | ||
iframe = driver.find_element(By.CSS_SELECTOR, "#fillform-frame-1") | ||
driver.switch_to.frame(iframe) | ||
|
||
# Wait for form to load | ||
xpath_selector = '//*[@id="postcode_search"]' | ||
self.wait_for_element(driver, By.XPATH, xpath_selector, timeout=6) | ||
|
||
# Send postcode | ||
postcode_input_box = driver.find_element(By.XPATH, xpath_selector) | ||
postcode_input_box.send_keys(user_postcode) | ||
postcode_input_box.send_keys(Keys.ENTER) | ||
|
||
search_for_address_button = driver.find_element( | ||
By.CSS_SELECTOR, "#addresssearch" | ||
) | ||
search_for_address_button.click() | ||
|
||
# Find address | ||
self.wait_for_element( | ||
driver, By.CSS_SELECTOR, "#selectaddr > option:nth-child(2)" | ||
) | ||
select_address_dropdown = Select( | ||
driver.find_element(By.CSS_SELECTOR, "#selectaddr") | ||
) | ||
if user_paon is not None: | ||
for option in select_address_dropdown.options: | ||
if user_paon in option.text: | ||
select_address_dropdown.select_by_visible_text(option.text) | ||
break | ||
else: | ||
# If we've not been supplied an address, pick the second entry | ||
select_address_dropdown.select_by_index(1) | ||
|
||
# Click the get schedule button (Once it's available) | ||
self.wait_for_element_conditions( | ||
driver, | ||
EC.element_to_be_clickable((By.CSS_SELECTOR, "#searchforcollections")), | ||
) | ||
check_schedules_button = driver.find_element( | ||
By.CSS_SELECTOR, "#searchforcollections" | ||
) | ||
check_schedules_button.click() | ||
|
||
# Grab the bin output data | ||
# Span is of the format: | ||
# Your Next bin collections are: | ||
# Black bin - Wednesday 29th November | ||
# Blue bin - Wednesday 6th December | ||
# Brown bin - Wednesday 6th December | ||
output_span_css_selector = "//span[@data-name='statictext6']" | ||
output_span_ec = EC.all_of( | ||
EC.presence_of_element_located((By.XPATH, output_span_css_selector)), | ||
EC.text_to_be_present_in_element( | ||
(By.XPATH, output_span_css_selector), "bin collections" | ||
), | ||
) | ||
self.wait_for_element_conditions(driver, output_span_ec) | ||
data_span = driver.find_element(By.XPATH, output_span_css_selector) | ||
|
||
data = {"bins": []} | ||
for item in data_span.text.splitlines(): | ||
if "bin" in item and " - " in item: | ||
bin_data = item.split(" - ") | ||
bin_name = bin_data[0] | ||
bin_date = bin_data[1] | ||
parsed_bin_date = parse(bin_date, fuzzy_with_tokens=True)[0] | ||
|
||
dict_data = { | ||
"type": bin_name, | ||
"collectionDate": parsed_bin_date.strftime(date_format), | ||
} | ||
|
||
data["bins"].append(dict_data) | ||
|
||
# Quit Selenium webdriver to release session | ||
driver.quit() | ||
|
||
return data |