diff --git a/uk_bin_collection/tests/input.json b/uk_bin_collection/tests/input.json index af672b4173..9709823ea8 100644 --- a/uk_bin_collection/tests/input.json +++ b/uk_bin_collection/tests/input.json @@ -321,6 +321,15 @@ "wiki_name": "Cornwall Council", "wiki_note": "Use https://uprn.uk/ to find your UPRN." }, + "CotswoldDistrictCouncil": { + "house_number": "19", + "postcode": "GL56 0GB", + "skip_get_url": true, + "url": "https://community.cotswold.gov.uk/s/waste-collection-enquiry", + "web_driver": "http://selenium:4444", + "wiki_name": "Cotswold District Council", + "wiki_note": "Pass the full address in the house number and postcode in" + }, "CoventryCityCouncil": { "url": "https://www.coventry.gov.uk/directory-record/56384/abberton-way-", "wiki_command_url_override": "https://www.coventry.gov.uk/directory_record/XXXXXX/XXXXXX", diff --git a/uk_bin_collection/uk_bin_collection/councils/CotswoldDistrictCouncil.py b/uk_bin_collection/uk_bin_collection/councils/CotswoldDistrictCouncil.py new file mode 100644 index 0000000000..d34f52950c --- /dev/null +++ b/uk_bin_collection/uk_bin_collection/councils/CotswoldDistrictCouncil.py @@ -0,0 +1,120 @@ +import time +from datetime import datetime + +from bs4 import BeautifulSoup +from selenium.webdriver.common.by import By +from selenium.webdriver.common.keys import Keys +from selenium.webdriver.support import expected_conditions as EC +from selenium.webdriver.support.ui import Select +from selenium.webdriver.support.wait import WebDriverWait + +from uk_bin_collection.uk_bin_collection.common import * +from uk_bin_collection.uk_bin_collection.get_bin_data import AbstractGetBinDataClass + +# import the wonderful Beautiful Soup and the URL grabber + + +class CouncilClass(AbstractGetBinDataClass): + """ + Concrete classes have to implement all abstract operations of the + base class. They can also override some operations with a default + implementation. + """ + + def parse_data(self, page: str, **kwargs) -> dict: + driver = None + try: + page = "https://community.cotswold.gov.uk/s/waste-collection-enquiry" + + data = {"bins": []} + + house_number = kwargs.get("paon") + postcode = kwargs.get("postcode") + full_address = f"{house_number}, {postcode}" + web_driver = kwargs.get("web_driver") + headless = kwargs.get("headless") + + # Create Selenium webdriver + driver = create_webdriver(web_driver, headless, None, __name__) + driver.get(page) + + # If you bang in the house number (or property name) and postcode in the box it should find your property + wait = WebDriverWait(driver, 60) + address_entry_field = wait.until( + EC.presence_of_element_located( + (By.XPATH, '//*[@id="combobox-input-19"]') + ) + ) + + address_entry_field.send_keys(str(full_address)) + + address_entry_field = wait.until( + EC.element_to_be_clickable((By.XPATH, '//*[@id="combobox-input-19"]')) + ) + address_entry_field.click() + address_entry_field.send_keys(Keys.BACKSPACE) + address_entry_field.send_keys(str(full_address[len(full_address) - 1])) + + first_found_address = wait.until( + EC.element_to_be_clickable( + (By.XPATH, '//*[@id="dropdown-element-19"]/ul') + ) + ) + + first_found_address.click() + # Wait for the 'Select your property' dropdown to appear and select the first result + next_btn = wait.until( + EC.element_to_be_clickable((By.XPATH, "//lightning-button/button")) + ) + next_btn.click() + bin_data = wait.until( + EC.presence_of_element_located( + (By.XPATH, "//span[contains(text(), 'Container')]") + ) + ) + + soup = BeautifulSoup(driver.page_source, features="html.parser") + + rows = soup.find_all("tr", class_="slds-hint-parent") + current_year = datetime.now().year + + for row in rows: + columns = row.find_all("td") + if columns: + container_type = row.find("th").text.strip() + if columns[0].get_text() == "Today": + collection_day = datetime.now().strftime("%a, %d %B") + elif columns[0].get_text() == "Tomorrow": + collection_day = (datetime.now() + timedelta(days=1)).strftime( + "%a, %d %B" + ) + else: + collection_day = re.sub( + r"[^a-zA-Z0-9,\s]", "", columns[0].get_text() + ).strip() + + # Parse the date from the string + parsed_date = datetime.strptime(collection_day, "%a, %d %B") + if parsed_date < datetime( + parsed_date.year, parsed_date.month, parsed_date.day + ): + parsed_date = parsed_date.replace(year=current_year + 1) + else: + parsed_date = parsed_date.replace(year=current_year) + # Format the date as %d/%m/%Y + formatted_date = parsed_date.strftime("%d/%m/%Y") + + # Add the bin type and collection date to the 'data' dictionary + data["bins"].append( + {"type": container_type, "collectionDate": formatted_date} + ) + except Exception as e: + # Here you can log the exception if needed + print(f"An error occurred: {e}") + # Optionally, re-raise the exception if you want it to propagate + raise + finally: + # This block ensures that the driver is closed regardless of an exception + if driver: + driver.quit() + return data diff --git a/wiki/Councils.md b/wiki/Councils.md index 28351eb1ea..9592edba90 100644 --- a/wiki/Councils.md +++ b/wiki/Councils.md @@ -53,6 +53,7 @@ This document is still a work in progress, don't worry if your council isn't lis - [Colchester City Council](#colchester-city-council) - [Conwy County Borough Council](#conwy-county-borough-council) - [Cornwall Council](#cornwall-council) +- [Cotswold District Council](#cotswold-district-council) - [Coventry City Council](#coventry-city-council) - [Crawley Borough Council](#crawley-borough-council) - [Croydon Council](#croydon-council) @@ -743,6 +744,20 @@ Note: Use https://uprn.uk/ to find your UPRN. --- +### Cotswold District Council +```commandline +python collect_data.py CotswoldDistrictCouncil https://community.cotswold.gov.uk/s/waste-collection-enquiry -s -p "XXXX XXX" -n XX -w http://HOST:PORT/ +``` +Additional parameters: +- `-s` - skip get URL +- `-p` - postcode +- `-n` - house number +- `-w` - remote Selenium web driver URL (required for Home Assistant) + +Note: Pass the full address in the house number and postcode in + +--- + ### Coventry City Council ```commandline python collect_data.py CoventryCityCouncil https://www.coventry.gov.uk/directory_record/XXXXXX/XXXXXX