Skip to content

Commit

Permalink
Merge pull request #453 from mrw298/feature/west-suffolk-council
Browse files Browse the repository at this point in the history
feat: Add support for West Suffolk Council
  • Loading branch information
dp247 authored Nov 30, 2023
2 parents 3920bc0 + 13685cd commit 6e9076d
Show file tree
Hide file tree
Showing 3 changed files with 131 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ Feature: Test each council output matches expected results
| WealdenDistrictCouncil | None | None |
| WelhatCouncil | None | None |
| WestLothianCouncil | http://selenium:4444 | local |
| WestSuffolkCouncil | http://selenium:4444 | local |
| WiganBoroughCouncil | None | None |
| WiltshireCouncil | None | None |
| WindsorAndMaidenheadCouncil | None | None |
Expand Down
11 changes: 10 additions & 1 deletion uk_bin_collection/tests/input.json
Original file line number Diff line number Diff line change
Expand Up @@ -648,6 +648,15 @@
"wiki_name": "West Lothian Council",
"wiki_note": "Pass the house name/number in the house number parameter, wrapped in double quotes"
},
"WestSuffolkCouncil": {
"house_number": "1 The Drift",
"postcode": "IP28 6DR",
"skip_get_url": true,
"url": "https://westsuffolk-self.achieveservice.com/service/WSS_EX_Inf_Bin_Collection_Postcode_Lookup",
"web_driver": "http://selenium:4444",
"wiki_name": "West Suffolk Council",
"wiki_note": "Pass the house name/number in the house number parameter, wrapped in double quotes and the postcode in the postcode parameter"
},
"WiganBoroughCouncil": {
"postcode": "WN24UQ",
"skip_get_url": true,
Expand Down Expand Up @@ -683,4 +692,4 @@
"url": "https://waste-api.york.gov.uk/api/Collections/GetBinCollectionDataForUprn/",
"wiki_name": "York Council"
}
}
}
120 changes: 120 additions & 0 deletions uk_bin_collection/uk_bin_collection/councils/WestSuffolkCouncil.py
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

0 comments on commit 6e9076d

Please sign in to comment.