From 986af3c9084a25ec6ad114ac9722cb54946dfb5d Mon Sep 17 00:00:00 2001 From: Wiki GitHub Action Date: Tue, 4 Feb 2025 21:21:57 +0000 Subject: [PATCH 01/18] docs: Update Councils.md from input.json --- wiki/Councils.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/wiki/Councils.md b/wiki/Councils.md index 1ee54816f0..3fedae6541 100644 --- a/wiki/Councils.md +++ b/wiki/Councils.md @@ -127,6 +127,7 @@ This document is still a work in progress, don't worry if your council isn't lis - [Harrogate Borough Council](#harrogate-borough-council) - [Hart District Council](#hart-district-council) - [Hartlepool Borough Council](#hartlepool-borough-council) +- [Herefordshire Council](#herefordshire-council) - [Hertsmere Borough Council](#hertsmere-borough-council) - [Highland Council](#highland-council) - [High Peak Council](#high-peak-council) @@ -1723,6 +1724,15 @@ Note: You will need to use [FindMyAddress](https://www.findmyaddress.co.uk/searc --- +### Herefordshire Council +```commandline +python collect_data.py HerefordshireCouncil https://www.herefordshire.gov.uk/rubbish-recycling/check-bin-collection-day?blpu_uprn=XXXXXXXXXXXX +``` + +Note: Replace 'XXXXXXXXXX' with your property's UPRN. You can find it using [FindMyAddress](https://www.findmyaddress.co.uk/search). + +--- + ### Hertsmere Borough Council ```commandline python collect_data.py HertsmereBoroughCouncil https://www.hertsmere.gov.uk -s -p "XXXX XXX" -n XX -w http://HOST:PORT/ From 256ae61f58defa44c58f3d8961103ba5e5ccd282 Mon Sep 17 00:00:00 2001 From: m26dvd <31007572+m26dvd@users.noreply.github.com> Date: Tue, 4 Feb 2025 21:42:39 +0000 Subject: [PATCH 02/18] fix: Neath Port Talbot fix: #1213 --- .../uk_bin_collection/councils/NeathPortTalbotCouncil.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/uk_bin_collection/uk_bin_collection/councils/NeathPortTalbotCouncil.py b/uk_bin_collection/uk_bin_collection/councils/NeathPortTalbotCouncil.py index 9dcbc649dd..16ac1c24ec 100644 --- a/uk_bin_collection/uk_bin_collection/councils/NeathPortTalbotCouncil.py +++ b/uk_bin_collection/uk_bin_collection/councils/NeathPortTalbotCouncil.py @@ -100,6 +100,8 @@ def parse_data(self, page: str, **kwargs) -> dict: {"id": "contentInner"}, ) + soup = soup.find("div", class_="umb-block-grid__layout-item") + # Get the dates for date in soup.find_all("h2"): if date.get_text(strip=True) != "Bank Holidays": From 42c86659e50f97945b2a6c92268e859577d5287a Mon Sep 17 00:00:00 2001 From: m26dvd <31007572+m26dvd@users.noreply.github.com> Date: Tue, 4 Feb 2025 22:17:38 +0000 Subject: [PATCH 03/18] fix: Torridge District Council fix: #1204 --- .../councils/TorridgeDistrictCouncil.py | 36 +------------------ 1 file changed, 1 insertion(+), 35 deletions(-) diff --git a/uk_bin_collection/uk_bin_collection/councils/TorridgeDistrictCouncil.py b/uk_bin_collection/uk_bin_collection/councils/TorridgeDistrictCouncil.py index 7f1fa9f03e..cf22bac173 100644 --- a/uk_bin_collection/uk_bin_collection/councils/TorridgeDistrictCouncil.py +++ b/uk_bin_collection/uk_bin_collection/councils/TorridgeDistrictCouncil.py @@ -1,6 +1,7 @@ from xml.etree import ElementTree from bs4 import BeautifulSoup + from uk_bin_collection.uk_bin_collection.common import * from uk_bin_collection.uk_bin_collection.get_bin_data import AbstractGetBinDataClass @@ -13,41 +14,6 @@ class CouncilClass(AbstractGetBinDataClass): operations with a default implementation. """ - def get_data(cls, **kwargs) -> str: - """This method makes the request to the council - - Keyword arguments: - url -- the url to get the data from - """ - # Set a user agent so we look like a browser ;-) - user_agent = "Mozilla/5.0 (Windows NT 6.1; Win64; x64)" - headers = {"User-Agent": user_agent, "Content-Type": "text/xml"} - - uprn = kwargs.get("uprn") - try: - if uprn is None or uprn == "": - raise ValueError("Invalid UPRN") - except Exception as ex: - print(f"Exception encountered: {ex}") - print( - "Please check the provided UPRN. If this error continues, please first trying setting the " - "UPRN manually on line 115 before raising an issue." - ) - - # Make the Request - change the URL - find out your property number - # URL - url = "https://collections-torridge.azurewebsites.net/WebService2.asmx" - # Post data - post_data = ( - 'TOR' - + uprn - + "wax01653" - ) - requests.packages.urllib3.disable_warnings() - full_page = requests.post(url, headers=headers, data=post_data) - - return full_page - def parse_data(self, page, **kwargs) -> dict: """This method makes the request to the council From c7efe697fc0cd90ea44cdf42d2a9bbcf9fed691c Mon Sep 17 00:00:00 2001 From: m26dvd <31007572+m26dvd@users.noreply.github.com> Date: Tue, 4 Feb 2025 23:53:48 +0000 Subject: [PATCH 04/18] feat: Adding Bolsover Council fix: #990 --- uk_bin_collection/tests/input.json | 8 +- .../councils/BolsoverCouncil.py | 298 ++++++++++++++++++ wiki/Councils.md | 12 + 3 files changed, 317 insertions(+), 1 deletion(-) create mode 100644 uk_bin_collection/uk_bin_collection/councils/BolsoverCouncil.py diff --git a/uk_bin_collection/tests/input.json b/uk_bin_collection/tests/input.json index 0f5d3d0add..b10562f5d5 100755 --- a/uk_bin_collection/tests/input.json +++ b/uk_bin_collection/tests/input.json @@ -196,6 +196,12 @@ "wiki_name": "Blaenau Gwent County Borough Council", "wiki_note": "You will need to use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find the UPRN." }, + "BolsoverCouncil": { + "url": "https://bolsover.gov.uk", + "uprn": "100030066827", + "wiki_name": "Bolsover Council", + "wiki_note": "You will need to use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find the UPRN." + }, "BoltonCouncil": { "postcode": "BL1 5PQ", "skip_get_url": true, @@ -1485,7 +1491,7 @@ "wiki_name": "Rhondda Cynon Taff Council", "wiki_note": "To get the UPRN, you can use [FindMyAddress](https://www.findmyaddress.co.uk/search)." }, -"RochdaleCouncil": { + "RochdaleCouncil": { "postcode": "OL11 5BE", "skip_get_url": true, "uprn": "23049922", diff --git a/uk_bin_collection/uk_bin_collection/councils/BolsoverCouncil.py b/uk_bin_collection/uk_bin_collection/councils/BolsoverCouncil.py new file mode 100644 index 0000000000..41c256bafc --- /dev/null +++ b/uk_bin_collection/uk_bin_collection/councils/BolsoverCouncil.py @@ -0,0 +1,298 @@ +import time + +import requests + +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: + + user_uprn = kwargs.get("uprn") + check_uprn(user_uprn) + bindata = {"bins": []} + + SESSION_URL = "https://selfservice.bolsover.gov.uk/authapi/isauthenticated?uri=https%253A%252F%252Fselfservice.bolsover.gov.uk%252Fservice%252FCheck_your_Bin_Day&hostname=selfservice.bolsover.gov.uk&withCredentials=true" + + API_URL = "https://selfservice.bolsover.gov.uk/apibroker/runLookup" + + data = { + "formValues": {"Bin Collection": {"uprnLoggedIn": {"value": user_uprn}}}, + } + headers = { + "Content-Type": "application/json", + "Accept": "application/json", + "User-Agent": "Mozilla/5.0", + "X-Requested-With": "XMLHttpRequest", + "Referer": "https://selfservice.bolsover.gov.uk/fillform/?iframe_id=fillform-frame-1&db_id=", + } + s = requests.session() + r = s.get(SESSION_URL) + r.raise_for_status() + session_data = r.json() + sid = session_data["auth-session"] + params = { + "id": "6023d37e037c3", + "repeat_against": "", + "noRetry": "true", + "getOnlyTokens": "undefined", + "log_id": "", + "app_name": "AF-Renderer::Self", + # unix_timestamp + "_": str(int(time.time() * 1000)), + "sid": sid, + } + + r = s.post(API_URL, json=data, headers=headers, params=params) + r.raise_for_status() + + data = r.json() + rows_data = data["integration"]["transformed"]["rows_data"]["0"] + if not isinstance(rows_data, dict): + raise ValueError("Invalid data returned from API") + + # print(rows_data) + + route = rows_data["Route"] + + # print(route) + + def get_route_number(route): + if route[:2] == "Mo": + return 0 + elif route[:2] == "Tu": + return 1 + elif route[:2] == "We": + return 2 + elif route[:2] == "Th": + return 3 + elif route[:2] == "Fr": + return 4 + else: + return None # Default case if none of the conditions match + + dayOfCollectionAsNumber = get_route_number(route) + # print(dayOfCollectionAsNumber) + + def calculate_collection_date( + dayOfCollectionAsNumber, + currentDayAsNumber, + today, + dayDiffPlus, + dayDiffMinus, + ): + if dayOfCollectionAsNumber == currentDayAsNumber: + return today + elif dayOfCollectionAsNumber > currentDayAsNumber: + return today + timedelta(days=dayDiffPlus) + else: + return today + timedelta(days=dayDiffMinus) + + # Example usage + today = datetime.today() # Current date + currentDayAsNumber = today.weekday() + dayDiffPlus = dayOfCollectionAsNumber - currentDayAsNumber + dayDiffMinus = dayOfCollectionAsNumber - currentDayAsNumber + 7 + + week1 = calculate_collection_date( + dayOfCollectionAsNumber, + currentDayAsNumber, + today, + dayDiffPlus, + dayDiffMinus, + ) + week2 = week1 + timedelta(days=7) + week3 = week2 + timedelta(days=7) + week4 = week3 + timedelta(days=7) + + # print(week1.strftime(date_format)) + # print(week2.strftime(date_format)) + # print(week3.strftime(date_format)) + # print(week4.strftime(date_format)) + + greenSusStart = datetime.strptime("2024-11-08", "%Y-%m-%d") + greenSusEnd = datetime.strptime("2025-03-18", "%Y-%m-%d") + + def is_within_green_sus(dtDay0, greenSusStart, greenSusEnd): + return "Yes" if greenSusStart <= dtDay0 < greenSusEnd else "No" + + week1InSus = is_within_green_sus(week1, greenSusStart, greenSusEnd) + week2InSus = is_within_green_sus(week2, greenSusStart, greenSusEnd) + week3InSus = is_within_green_sus(week3, greenSusStart, greenSusEnd) + week4InSus = is_within_green_sus(week4, greenSusStart, greenSusEnd) + + # print(week1InSus) + # print(week2InSus) + # print(week3InSus) + # print(week4InSus) + + WeekBlack = rows_data["WeekBlack"] + WeekBandG = rows_data["WeekBandG"] + + if WeekBlack == "1": + WeekBandG = "" + if WeekBandG == "1": + WeekBlack = "" + + def determine_bin_collection_week1( + txtBlack, txtBurgGreen, dtDay0, today, week1InSus + ): + # Check for empty values + if txtBlack == "" and txtBurgGreen == "": + return "" + + # Black Bin Collection + if txtBlack == "1" and dtDay0 >= today: + return "Black Bin" + + # Burgundy Bin Collection + if txtBurgGreen == "1" and dtDay0 > today: + if week1InSus == "Yes": + return "Burgundy Bin" + elif week1InSus == "No": + return "Burgundy Bin & Green Bin" + + # Default cases based on week1InSus + if txtBlack == "" and dtDay0 >= today: + if week1InSus == "Yes": + return "Burgundy Bin" + elif week1InSus == "No": + return "Burgundy Bin & Green Bin" + + return "" # Default empty case + + def determine_bin_collection_week2( + txtBlack, txtBurgGreen, dtDay7, today, week2InSus + ): + # Check for empty values + if txtBlack == "" and txtBurgGreen == "": + return "" + + # Black Bin Collection + if txtBlack == "" and dtDay7 >= today: + return "Black Bin" + + # Burgundy Bin Collection (week2InSus check) + if txtBurgGreen == "1" and dtDay7 > today: + if week2InSus == "Yes": + return "Burgundy Bin" + elif week2InSus == "No": + return "Burgundy Bin & Green Bin" + + # Burgundy Bin Collection for txtBlack = '1' + if txtBlack == "1" and dtDay7 >= today: + if week2InSus == "Yes": + return "Burgundy Bin" + elif week2InSus == "No": + return "Burgundy Bin & Green Bin" + + return "" # Default empty case + + def determine_bin_collection_week3( + txtBlack, txtBurgGreen, dtDay14, today, week3InSus + ): + # Check for empty values + if txtBlack == "" and txtBurgGreen == "": + return "" + + # Black Bin Collection + if txtBlack == "1" and dtDay14 >= today: + return "Black Bin" + + # Burgundy Bin Collection (week3InSus check) + if txtBurgGreen == "1" and dtDay14 > today: + if week3InSus == "Yes": + return "Burgundy Bin" + elif week3InSus == "No": + return "Burgundy Bin & Green Bin" + + # Burgundy Bin Collection for txtBlack = '' + if txtBlack == "" and dtDay14 >= today: + if week3InSus == "Yes": + return "Burgundy Bin" + elif week3InSus == "No": + return "Burgundy Bin & Green Bin" + + return "" # Default empty case + + def determine_bin_collection_week4( + txtBlack, txtBurgGreen, dtDay21, today, week4InSus + ): + # Check for empty values + if txtBlack == "" and txtBurgGreen == "": + return "" + + # Black Bin Collection + if txtBlack == "" and dtDay21 >= today: + return "Black Bin" + + # Burgundy Bin Collection (week4InSus check) + if txtBurgGreen == "1" and dtDay21 > today: + if week4InSus == "Yes": + return "Burgundy Bin" + elif week4InSus == "No": + return "Burgundy Bin & Green Bin" + + # Burgundy Bin Collection for txtBlack = '1' + if txtBlack == "1" and dtDay21 >= today: + if week4InSus == "Yes": + return "Burgundy Bin" + elif week4InSus == "No": + return "Burgundy Bin & Green Bin" + + return "" # Default empty case + + week1Text = determine_bin_collection_week1( + WeekBlack, WeekBandG, week1, today, week1InSus + ) + week2Text = determine_bin_collection_week2( + WeekBlack, WeekBandG, week2, today, week2InSus + ) + week3Text = determine_bin_collection_week3( + WeekBlack, WeekBandG, week3, today, week3InSus + ) + week4Text = determine_bin_collection_week4( + WeekBlack, WeekBandG, week4, today, week4InSus + ) + + # print(week1Text) + # print(week2Text) + # print(week3Text) + # print(week4Text) + + week_data = [ + (week1Text, week1), + (week2Text, week2), + (week3Text, week3), + (week4Text, week4), + ] + + # print(week_data) + + # Iterate through the array + for week_text, week_date in week_data: + # Check if '&' exists and split + if "&" in week_text: + split_texts = [text.strip() for text in week_text.split("&")] + for text in split_texts: + dict_data = { + "type": text, + "collectionDate": week_date.strftime(date_format), + } + bindata["bins"].append(dict_data) + else: + dict_data = { + "type": week_text, + "collectionDate": week_date.strftime(date_format), + } + bindata["bins"].append(dict_data) + + return bindata diff --git a/wiki/Councils.md b/wiki/Councils.md index 3fedae6541..e39d5c3452 100644 --- a/wiki/Councils.md +++ b/wiki/Councils.md @@ -36,6 +36,7 @@ This document is still a work in progress, don't worry if your council isn't lis - [Blaby District Council](#blaby-district-council) - [Blackburn Council](#blackburn-council) - [Blaenau Gwent County Borough Council](#blaenau-gwent-county-borough-council) +- [Bolsover Council](#bolsover-council) - [Bolton Council](#bolton-council) - [Boston Borough Council](#boston-borough-council) - [Bracknell Forest Council](#bracknell-forest-council) @@ -621,6 +622,17 @@ Note: You will need to use [FindMyAddress](https://www.findmyaddress.co.uk/searc --- +### Bolsover Council +```commandline +python collect_data.py BolsoverCouncil https://bolsover.gov.uk -u XXXXXXXX +``` +Additional parameters: +- `-u` - UPRN + +Note: You will need to use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find the UPRN. + +--- + ### Bolton Council ```commandline python collect_data.py BoltonCouncil https://carehomes.bolton.gov.uk/bins.aspx -s -u XXXXXXXX -p "XXXX XXX" -w http://HOST:PORT/ From 1b0bdcf8e6687dc2f9d096a3772153fc02a4384d Mon Sep 17 00:00:00 2001 From: m26dvd <31007572+m26dvd@users.noreply.github.com> Date: Wed, 5 Feb 2025 00:39:02 +0000 Subject: [PATCH 05/18] feat: Adding Amber Valley Borough Council fix: #903 --- uk_bin_collection/tests/input.json | 6 ++ .../councils/AmberValleyBoroughCouncil.py | 60 +++++++++++++++++++ wiki/Councils.md | 12 ++++ 3 files changed, 78 insertions(+) create mode 100644 uk_bin_collection/uk_bin_collection/councils/AmberValleyBoroughCouncil.py diff --git a/uk_bin_collection/tests/input.json b/uk_bin_collection/tests/input.json index b10562f5d5..55343454a9 100755 --- a/uk_bin_collection/tests/input.json +++ b/uk_bin_collection/tests/input.json @@ -18,6 +18,12 @@ "wiki_name": "Adur and Worthing Councils", "wiki_note": "Replace XXXXXXXX with your UPRN. You will need to use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find it." }, + "AmberValleyBoroughCouncil": { + "url": "https://ambervalley.gov.uk", + "uprn": "100030026621", + "wiki_name": "Amber Valley Borough Council", + "wiki_note": "You will need to use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find the UPRN." + }, "AntrimAndNewtonabbeyCouncil": { "url": "https://antrimandnewtownabbey.gov.uk/residents/bins-recycling/bins-schedule/?Id=643", "wiki_command_url_override": "https://antrimandnewtownabbey.gov.uk/residents/bins-recycling/bins-schedule/?Id=XXXX", diff --git a/uk_bin_collection/uk_bin_collection/councils/AmberValleyBoroughCouncil.py b/uk_bin_collection/uk_bin_collection/councils/AmberValleyBoroughCouncil.py new file mode 100644 index 0000000000..2450d1d32d --- /dev/null +++ b/uk_bin_collection/uk_bin_collection/councils/AmberValleyBoroughCouncil.py @@ -0,0 +1,60 @@ +from datetime import datetime + +import requests + +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: + + user_uprn = kwargs.get("uprn") + check_uprn(user_uprn) + bindata = {"bins": []} + + WASTE_TYPES_DATE_KEY = { + "REFUSE": "refuseNextDate", + "RECYCLING": "recyclingNextDate", + "GREEN": "greenNextDate", + "COMMUNAL REFUSE": "communalRefNextDate", + "COMMUNAL RECYCLING": "communalRycNextDate", + } + + URI = f"https://info.ambervalley.gov.uk/WebServices/AVBCFeeds/WasteCollectionJSON.asmx/GetCollectionDetailsByUPRN?uprn={user_uprn}" + + # Make the GET request + response = requests.get(URI) + + # Parse the JSON response + bin_collection = response.json() + + # print(bin_collection) + + for bin, datge_key in WASTE_TYPES_DATE_KEY.items(): + date_ = datetime.strptime( + bin_collection[datge_key], "%Y-%m-%dT%H:%M:%S" + ).strftime(date_format) + if date_ == "01/01/1": + continue + elif date_ == "01/01/1900": + continue + + dict_data = { + "type": bin, + "collectionDate": date_, + } + bindata["bins"].append(dict_data) + + bindata["bins"].sort( + key=lambda x: datetime.strptime(x.get("collectionDate"), "%d/%m/%Y") + ) + + return bindata diff --git a/wiki/Councils.md b/wiki/Councils.md index e39d5c3452..b84507d14b 100644 --- a/wiki/Councils.md +++ b/wiki/Councils.md @@ -13,6 +13,7 @@ This document is still a work in progress, don't worry if your council isn't lis - [Aberdeenshire Council](#aberdeenshire-council) - [Aberdeen City Council](#aberdeen-city-council) - [Adur and Worthing Councils](#adur-and-worthing-councils) +- [Amber Valley Borough Council](#amber-valley-borough-council) - [Antrim & Newtonabbey Council](#antrim-&-newtonabbey-council) - [Ards and North Down Council](#ards-and-north-down-council) - [Argyll and Bute Council](#argyll-and-bute-council) @@ -336,6 +337,17 @@ Note: Replace XXXXXXXX with your UPRN. You will need to use [FindMyAddress](http --- +### Amber Valley Borough Council +```commandline +python collect_data.py AmberValleyBoroughCouncil https://ambervalley.gov.uk -u XXXXXXXX +``` +Additional parameters: +- `-u` - UPRN + +Note: You will need to use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find the UPRN. + +--- + ### Antrim & Newtonabbey Council ```commandline python collect_data.py AntrimAndNewtonabbeyCouncil https://antrimandnewtownabbey.gov.uk/residents/bins-recycling/bins-schedule/?Id=XXXX From 32314e63d7ab922f54851d4532a28de9cbcfbe07 Mon Sep 17 00:00:00 2001 From: m26dvd <31007572+m26dvd@users.noreply.github.com> Date: Wed, 5 Feb 2025 22:52:41 +0000 Subject: [PATCH 06/18] feat: Adding Redcar and Cleveland Council fix: #841 --- uk_bin_collection/tests/input.json | 8 ++ .../councils/RedcarandClevelandCouncil.py | 108 ++++++++++++++++++ wiki/Councils.md | 14 +++ 3 files changed, 130 insertions(+) create mode 100644 uk_bin_collection/uk_bin_collection/councils/RedcarandClevelandCouncil.py diff --git a/uk_bin_collection/tests/input.json b/uk_bin_collection/tests/input.json index 55343454a9..f4b0073095 100755 --- a/uk_bin_collection/tests/input.json +++ b/uk_bin_collection/tests/input.json @@ -1465,6 +1465,14 @@ "wiki_name": "Reading Borough Council", "wiki_note": "Replace XXXXXXXX with your property's UPRN." }, + "RedcarandClevelandCouncil": { + "house_number": "11", + "postcode": "TS10 2RE", + "skip_get_url": true, + "url": "https://www.redcar-cleveland.gov.uk", + "wiki_name": "Redcar and Cleveland Council", + "wiki_note": "Pass the house name/number and postcode in their respective parameters" + }, "RedditchBoroughCouncil": { "url": "https://redditchbc.gov.uk", "wiki_command_url_override": "https://redditchbc.gov.uk", diff --git a/uk_bin_collection/uk_bin_collection/councils/RedcarandClevelandCouncil.py b/uk_bin_collection/uk_bin_collection/councils/RedcarandClevelandCouncil.py new file mode 100644 index 0000000000..8639306680 --- /dev/null +++ b/uk_bin_collection/uk_bin_collection/councils/RedcarandClevelandCouncil.py @@ -0,0 +1,108 @@ +import time + +import requests + +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: + + user_postcode = kwargs.get("postcode") + user_paon = kwargs.get("paon") + check_postcode(user_postcode) + check_paon(user_paon) + bindata = {"bins": []} + + URI = "https://api.eu.recollect.net/api/areas/RedcarandClevelandUK/services/50006/address-suggest" + + params = { + "q": user_postcode, + "locale": "en-GB", + "_": str(int(time.time() * 1000)), + } + + # print(params) + + # Send GET request + response = requests.get(URI, params=params) + + addresses = response.json() + + place_id = next( + ( + item["place_id"] + for item in addresses + if item.get("name", "").startswith(user_paon) + ), + None, + ) + + # print(addresses) + # print(place_id) + + URI = ( + f"https://api.eu.recollect.net/api/places/{place_id}/services/50006/events" + ) + + after = datetime.today() + before = after + timedelta(days=30) + + after = after.strftime("%Y-%m-%d") + before = before.strftime("%Y-%m-%d") + + # print(after) + # print(before) + + params = { + "nomerge": 1, + "hide": "reminder_only", + "after": after, + "before": before, + "locale": "en-GB", + "include_message": "email", + "_": str(int(time.time() * 1000)), + } + + # print(params) + + # Send GET request + response = requests.get(URI, params=params) + + response = response.json() + + bin_collection = response["events"] + + # print(bin_collection) + + # Extract "end_day" and "name" + events = [ + (event["end_day"], flag["name"]) + for event in bin_collection + for flag in event.get("flags", []) + ] + + # Print results + for end_day, bin_type in events: + + date = datetime.strptime(end_day, "%Y-%m-%d") + + dict_data = { + "type": bin_type, + "collectionDate": date.strftime(date_format), + } + bindata["bins"].append(dict_data) + + bindata["bins"].sort( + key=lambda x: datetime.strptime(x.get("collectionDate"), date_format) + ) + + return bindata diff --git a/wiki/Councils.md b/wiki/Councils.md index b84507d14b..d65a832234 100644 --- a/wiki/Councils.md +++ b/wiki/Councils.md @@ -207,6 +207,7 @@ This document is still a work in progress, don't worry if your council isn't lis - [Powys Council](#powys-council) - [Preston City Council](#preston-city-council) - [Reading Borough Council](#reading-borough-council) +- [Redcar and Cleveland Council](#redcar-and-cleveland-council) - [Redditch Borough Council](#redditch-borough-council) - [Reigate and Banstead Borough Council](#reigate-and-banstead-borough-council) - [Renfrewshire Council](#renfrewshire-council) @@ -2672,6 +2673,19 @@ Note: Replace XXXXXXXX with your property's UPRN. --- +### Redcar and Cleveland Council +```commandline +python collect_data.py RedcarandClevelandCouncil https://www.redcar-cleveland.gov.uk -s -p "XXXX XXX" -n XX +``` +Additional parameters: +- `-s` - skip get URL +- `-p` - postcode +- `-n` - house number + +Note: Pass the house name/number and postcode in their respective parameters + +--- + ### Redditch Borough Council ```commandline python collect_data.py RedditchBoroughCouncil https://redditchbc.gov.uk -u XXXXXXXX From 7b634d71858a63ed53d0f8aee6e5c5599fc028cd Mon Sep 17 00:00:00 2001 From: m26dvd <31007572+m26dvd@users.noreply.github.com> Date: Wed, 5 Feb 2025 23:49:37 +0000 Subject: [PATCH 07/18] feat: Adding Epsom and Ewell Borough Council fix: #895 --- uk_bin_collection/tests/input.json | 6 ++ .../councils/EpsomandEwellBoroughCouncil.py | 86 +++++++++++++++++++ wiki/Councils.md | 12 +++ 3 files changed, 104 insertions(+) create mode 100644 uk_bin_collection/uk_bin_collection/councils/EpsomandEwellBoroughCouncil.py diff --git a/uk_bin_collection/tests/input.json b/uk_bin_collection/tests/input.json index f4b0073095..53512456c9 100755 --- a/uk_bin_collection/tests/input.json +++ b/uk_bin_collection/tests/input.json @@ -718,6 +718,12 @@ "wiki_name": "Epping Forest District Council", "wiki_note": "Replace the postcode in the URL with your own." }, + "EpsomandEwellBoroughCouncil": { + "uprn": "100061349083", + "url": "https://www.epsom-ewell.gov.uk", + "wiki_name": "Epsom and Ewell Borough Council", + "wiki_note": "Use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find your UPRN." + }, "ErewashBoroughCouncil": { "skip_get_url": true, "uprn": "10003582028", diff --git a/uk_bin_collection/uk_bin_collection/councils/EpsomandEwellBoroughCouncil.py b/uk_bin_collection/uk_bin_collection/councils/EpsomandEwellBoroughCouncil.py new file mode 100644 index 0000000000..052402eeff --- /dev/null +++ b/uk_bin_collection/uk_bin_collection/councils/EpsomandEwellBoroughCouncil.py @@ -0,0 +1,86 @@ +from datetime import datetime, timedelta + +import requests +from bs4 import BeautifulSoup + +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: + + user_uprn = kwargs.get("uprn") + check_uprn(user_uprn) + bindata = {"bins": []} + + URI = f"https://maps.epsom-ewell.gov.uk/myeebc.aspx?action=SetAddress&UniqueId={user_uprn}" + + # Make the GET request + response = requests.get(URI) + + soup = BeautifulSoup(response.text, "html.parser") + + # print(soup) + + div = soup.find_all("div", class_="atPanelContent atAlt1 atLast") + + # print(div[1]) + + panels = div[1].find_all("div", class_="atPanelData") + + # print(panels) + + def get_full_date(date_str): + # Get the current year + current_year = datetime.today().year + + # Convert the input string to a datetime object (assuming the current year first) + date_obj = datetime.strptime(f"{date_str} {current_year}", "%A %d %B %Y") + + # If the date has already passed this year, use next year + if date_obj < datetime.today(): + date_obj = datetime.strptime( + f"{date_str} {current_year + 1}", "%A %d %B %Y" + ) + + return date_obj.strftime(date_format) # Return in YYYY-MM-DD format + + for panel in panels: + bin_type_tag = panel.find("h4") # Extracts bin type + date_text = panel.find_all("td") # Extracts collection date + + date_text = date_text[1] + + if bin_type_tag and date_text: + bin_type = bin_type_tag.text.strip() + try: + collection_date = date_text.text.strip().split(":")[1] + except IndexError: + continue + + bin_type = ( + (" ".join(bin_type.splitlines())).replace(" ", " ") + ).lstrip() + collection_date = ( + (" ".join(collection_date.splitlines())).replace(" ", " ") + ).lstrip() + + dict_data = { + "type": bin_type, + "collectionDate": get_full_date(collection_date), + } + bindata["bins"].append(dict_data) + + bindata["bins"].sort( + key=lambda x: datetime.strptime(x.get("collectionDate"), "%d/%m/%Y") + ) + + return bindata diff --git a/wiki/Councils.md b/wiki/Councils.md index d65a832234..7653108dbc 100644 --- a/wiki/Councils.md +++ b/wiki/Councils.md @@ -106,6 +106,7 @@ This document is still a work in progress, don't worry if your council isn't lis - [Enfield Council](#enfield-council) - [Environment First](#environment-first) - [Epping Forest District Council](#epping-forest-district-council) +- [Epsom and Ewell Borough Council](#epsom-and-ewell-borough-council) - [Erewash Borough Council](#erewash-borough-council) - [Exeter City Council](#exeter-city-council) - [Falkirk Council](#falkirk-council) @@ -1471,6 +1472,17 @@ Note: Replace the postcode in the URL with your own. --- +### Epsom and Ewell Borough Council +```commandline +python collect_data.py EpsomandEwellBoroughCouncil https://www.epsom-ewell.gov.uk -u XXXXXXXX +``` +Additional parameters: +- `-u` - UPRN + +Note: Use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find your UPRN. + +--- + ### Erewash Borough Council ```commandline python collect_data.py ErewashBoroughCouncil https://map.erewash.gov.uk/isharelive.web/myerewash.aspx -s -u XXXXXXXX From 589af894a4c4547a726b6c7b98abb73b186e8d15 Mon Sep 17 00:00:00 2001 From: m26dvd <31007572+m26dvd@users.noreply.github.com> Date: Thu, 6 Feb 2025 00:13:36 +0000 Subject: [PATCH 08/18] feat: Adding Cherwell District Council fix: #923 --- uk_bin_collection/tests/input.json | 6 ++ .../councils/CherwellDistrictCouncil.py | 75 +++++++++++++++++++ wiki/Councils.md | 12 +++ 3 files changed, 93 insertions(+) create mode 100644 uk_bin_collection/uk_bin_collection/councils/CherwellDistrictCouncil.py diff --git a/uk_bin_collection/tests/input.json b/uk_bin_collection/tests/input.json index 53512456c9..9489ccfa4d 100755 --- a/uk_bin_collection/tests/input.json +++ b/uk_bin_collection/tests/input.json @@ -402,6 +402,12 @@ "wiki_name": "Cheltenham Borough Council", "wiki_note": "Use the House Number field to pass the DAY of the week for your collections. [Monday/Tuesday/Wednesday/Thursday/Friday]. Use the 'postcode' field to pass the WEEK (wrapped in quotes) for your collections. [Week 1/Week 2]." }, + "CherwellDistrictCouncil": { + "uprn": "100121292407", + "url": "https://www.cherwell.gov.uk", + "wiki_name": "Cherwell District Council", + "wiki_note": "Use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find your UPRN." + }, "CheshireEastCouncil": { "url": "https://online.cheshireeast.gov.uk/MyCollectionDay/SearchByAjax/GetBartecJobList?uprn=100012791226&onelineaddress=3%20COBBLERS%20YARD,%20SK9%207DZ&_=1689413260149", "wiki_command_url_override": "https://online.cheshireeast.gov.uk/MyCollectionDay/SearchByAjax/GetBartecJobList?uprn=XXXXXXXX&onelineaddress=XXXXXXXX&_=1689413260149", diff --git a/uk_bin_collection/uk_bin_collection/councils/CherwellDistrictCouncil.py b/uk_bin_collection/uk_bin_collection/councils/CherwellDistrictCouncil.py new file mode 100644 index 0000000000..4ea346e737 --- /dev/null +++ b/uk_bin_collection/uk_bin_collection/councils/CherwellDistrictCouncil.py @@ -0,0 +1,75 @@ +from datetime import datetime, timedelta + +import requests +from bs4 import BeautifulSoup + +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: + + user_uprn = kwargs.get("uprn") + check_uprn(user_uprn) + bindata = {"bins": []} + + URI = f"https://www.cherwell.gov.uk/homepage/129/bin-collection-search?uprn={user_uprn}" + + # Make the GET request + response = requests.get(URI) + + soup = BeautifulSoup(response.text, "html.parser") + + def get_full_date(date_str): + # Get the current year + current_year = datetime.today().year + + date_str = remove_ordinal_indicator_from_date_string(date_str) + + # Convert the input string to a datetime object (assuming the current year first) + date_obj = datetime.strptime(f"{date_str} {current_year}", "%d %B %Y") + + # If the date has already passed this year, use next year + if date_obj < datetime.today(): + date_obj = datetime.strptime( + f"{date_str} {current_year + 1}", "%d %B %Y" + ) + + return date_obj.strftime(date_format) # Return in YYYY-MM-DD format + + # print(soup) + + div = soup.find("div", class_="bin-collection-results__tasks") + + for item in div.find_all("li", class_="list__item"): + # Extract bin type + bin_type_tag = item.find("h3", class_="bin-collection-tasks__heading") + bin_type = ( + "".join(bin_type_tag.find_all(text=True, recursive=False)).strip() + if bin_type_tag + else "Unknown Bin" + ) + + # Extract collection date + date_tag = item.find("p", class_="bin-collection-tasks__date") + collection_date = date_tag.text.strip() if date_tag else "Unknown Date" + + dict_data = { + "type": bin_type, + "collectionDate": get_full_date(collection_date), + } + bindata["bins"].append(dict_data) + + bindata["bins"].sort( + key=lambda x: datetime.strptime(x.get("collectionDate"), date_format) + ) + + return bindata diff --git a/wiki/Councils.md b/wiki/Councils.md index 7653108dbc..bb0ae4e4ce 100644 --- a/wiki/Councils.md +++ b/wiki/Councils.md @@ -63,6 +63,7 @@ This document is still a work in progress, don't worry if your council isn't lis - [Charnwood Borough Council](#charnwood-borough-council) - [Chelmsford City Council](#chelmsford-city-council) - [Cheltenham Borough Council](#cheltenham-borough-council) +- [Cherwell District Council](#cherwell-district-council) - [Cheshire East Council](#cheshire-east-council) - [Cheshire West and Chester Council](#cheshire-west-and-chester-council) - [Chesterfield Borough Council](#chesterfield-borough-council) @@ -957,6 +958,17 @@ Note: Use the House Number field to pass the DAY of the week for your collection --- +### Cherwell District Council +```commandline +python collect_data.py CherwellDistrictCouncil https://www.cherwell.gov.uk -u XXXXXXXX +``` +Additional parameters: +- `-u` - UPRN + +Note: Use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find your UPRN. + +--- + ### Cheshire East Council ```commandline python collect_data.py CheshireEastCouncil https://online.cheshireeast.gov.uk/MyCollectionDay/SearchByAjax/GetBartecJobList?uprn=XXXXXXXX&onelineaddress=XXXXXXXX&_=1689413260149 From bb54c5da2f7087fb7f93a54139ad3be1587bf4d0 Mon Sep 17 00:00:00 2001 From: m26dvd <31007572+m26dvd@users.noreply.github.com> Date: Thu, 6 Feb 2025 00:48:30 +0000 Subject: [PATCH 09/18] feat: Adding Runnymede Borough Council fix: #1214 --- uk_bin_collection/tests/input.json | 7 +++ .../councils/RunnymedeBoroughCouncil.py | 54 +++++++++++++++++++ wiki/Councils.md | 13 +++++ 3 files changed, 74 insertions(+) create mode 100644 uk_bin_collection/uk_bin_collection/councils/RunnymedeBoroughCouncil.py diff --git a/uk_bin_collection/tests/input.json b/uk_bin_collection/tests/input.json index 9489ccfa4d..32d4af7d96 100755 --- a/uk_bin_collection/tests/input.json +++ b/uk_bin_collection/tests/input.json @@ -1559,6 +1559,13 @@ "wiki_name": "Rugby Borough Council", "wiki_note": "Provide your UPRN and postcode. You can find your UPRN using [FindMyAddress](https://www.findmyaddress.co.uk/search)." }, + "RunnymedeBoroughCouncil": { + "skip_get_url": true, + "uprn": "100061483636", + "url": "https://www.runnymede.gov.uk/", + "wiki_name": "Runnymede Borough Council", + "wiki_note": "You will need to use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find the UPRN." + }, "RushcliffeBoroughCouncil": { "postcode": "NG13 8TZ", "skip_get_url": true, diff --git a/uk_bin_collection/uk_bin_collection/councils/RunnymedeBoroughCouncil.py b/uk_bin_collection/uk_bin_collection/councils/RunnymedeBoroughCouncil.py new file mode 100644 index 0000000000..382bf6e1e4 --- /dev/null +++ b/uk_bin_collection/uk_bin_collection/councils/RunnymedeBoroughCouncil.py @@ -0,0 +1,54 @@ +from datetime import datetime, timedelta + +import requests +from bs4 import BeautifulSoup + +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: + + user_uprn = kwargs.get("uprn") + check_uprn(user_uprn) + bindata = {"bins": []} + + URI = f"https://www.runnymede.gov.uk/homepage/150/check-your-bin-collection-day?address={user_uprn}" + + # Make the GET request + response = requests.get(URI) + + soup = BeautifulSoup(response.text, "html.parser") + + div = soup.find("div", class_="widget-bin-collection") + + table = div.find("table") + + tbody = table.find("tbody") + + for tr in tbody.find_all("tr"): + tds = tr.find_all("td") + bin_type = tds[0].text.strip() + date_text = tds[1].text.strip() + + dict_data = { + "type": bin_type, + "collectionDate": ( + datetime.strptime(date_text, "%A, %d %B %Y") + ).strftime(date_format), + } + bindata["bins"].append(dict_data) + + bindata["bins"].sort( + key=lambda x: datetime.strptime(x.get("collectionDate"), date_format) + ) + + return bindata diff --git a/wiki/Councils.md b/wiki/Councils.md index bb0ae4e4ce..7acdf7a794 100644 --- a/wiki/Councils.md +++ b/wiki/Councils.md @@ -220,6 +220,7 @@ This document is still a work in progress, don't worry if your council isn't lis - [Rotherham Council](#rotherham-council) - [Royal Borough of Greenwich](#royal-borough-of-greenwich) - [Rugby Borough Council](#rugby-borough-council) +- [Runnymede Borough Council](#runnymede-borough-council) - [Rushcliffe Borough Council](#rushcliffe-borough-council) - [Rushmoor Council](#rushmoor-council) - [Salford City Council](#salford-city-council) @@ -2830,6 +2831,18 @@ Note: Provide your UPRN and postcode. You can find your UPRN using [FindMyAddres --- +### Runnymede Borough Council +```commandline +python collect_data.py RunnymedeBoroughCouncil https://www.runnymede.gov.uk/ -s -u XXXXXXXX +``` +Additional parameters: +- `-s` - skip get URL +- `-u` - UPRN + +Note: You will need to use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find the UPRN. + +--- + ### Rushcliffe Borough Council ```commandline python collect_data.py RushcliffeBoroughCouncil https://www.rushcliffe.gov.uk/ -s -u XXXXXXXX -p "XXXX XXX" -w http://HOST:PORT/ From e39093e49d2e7d4afe9d92e0d23e54cea39ff1b1 Mon Sep 17 00:00:00 2001 From: Wiki GitHub Action Date: Tue, 11 Feb 2025 22:42:24 +0000 Subject: [PATCH 10/18] docs: Update Councils.md from input.json --- wiki/Councils.md | 204 +++++++++++++++++++++++++---------------------- 1 file changed, 108 insertions(+), 96 deletions(-) diff --git a/wiki/Councils.md b/wiki/Councils.md index 7acdf7a794..ecf11e7b73 100644 --- a/wiki/Councils.md +++ b/wiki/Councils.md @@ -10,8 +10,8 @@ For scripts that need postcodes, these should be provided in double quotes and w This document is still a work in progress, don't worry if your council isn't listed - it will be soon! ## Contents -- [Aberdeenshire Council](#aberdeenshire-council) - [Aberdeen City Council](#aberdeen-city-council) +- [Aberdeenshire Council](#aberdeenshire-council) - [Adur and Worthing Councils](#adur-and-worthing-councils) - [Amber Valley Borough Council](#amber-valley-borough-council) - [Antrim & Newtonabbey Council](#antrim-&-newtonabbey-council) @@ -22,8 +22,8 @@ This document is still a work in progress, don't worry if your council isn't lis - [Ashfield District Council](#ashfield-district-council) - [Ashford Borough Council](#ashford-borough-council) - [Aylesbury Vale Council (Buckinghamshire)](#aylesbury-vale-council-(buckinghamshire)) -- [Babergh District Council](#babergh-district-council) - [BCP Council](#bcp-council) +- [Babergh District Council](#babergh-district-council) - [Barnet Council](#barnet-council) - [Barnsley Metropolitan Borough Council](#barnsley-metropolitan-borough-council) - [Basildon Council](#basildon-council) @@ -77,8 +77,8 @@ This document is still a work in progress, don't worry if your council isn't lis - [Coventry City Council](#coventry-city-council) - [Crawley Borough Council](#crawley-borough-council) - [Croydon Council](#croydon-council) -- [Cumberland Borough Council](#cumberland-borough-council) - [Cumberland Council - Allerdale District](#cumberland-council---allerdale-district) +- [Cumberland Borough Council](#cumberland-borough-council) - [Dacorum Borough Council](#dacorum-borough-council) - [Dartford Borough Council](#dartford-borough-council) - [Denbighshire Council](#denbighshire-council) @@ -133,12 +133,13 @@ This document is still a work in progress, don't worry if your council isn't lis - [Hartlepool Borough Council](#hartlepool-borough-council) - [Herefordshire Council](#herefordshire-council) - [Hertsmere Borough Council](#hertsmere-borough-council) -- [Highland Council](#highland-council) - [High Peak Council](#high-peak-council) +- [Highland Council](#highland-council) - [Hinckley and Bosworth Borough Council](#hinckley-and-bosworth-borough-council) - [Hounslow Council](#hounslow-council) - [Hull City Council](#hull-city-council) - [Huntingdon District Council](#huntingdon-district-council) +- [Ipswich Borough Council](#ipswich-borough-council) - [Islington Council](#islington-council) - [Kings Lynn and West Norfolk Borough Council](#kings-lynn-and-west-norfolk-borough-council) - [Kingston Upon Thames Council](#kingston-upon-thames-council) @@ -152,12 +153,12 @@ This document is still a work in progress, don't worry if your council isn't lis - [Lisburn and Castlereagh City Council](#lisburn-and-castlereagh-city-council) - [Liverpool City Council](#liverpool-city-council) - [London Borough Ealing](#london-borough-ealing) -- [London Borough Of Richmond Upon Thames](#london-borough-of-richmond-upon-thames) - [London Borough Harrow](#london-borough-harrow) - [London Borough Havering](#london-borough-havering) - [London Borough Hounslow](#london-borough-hounslow) - [London Borough Lambeth](#london-borough-lambeth) - [London Borough Lewisham](#london-borough-lewisham) +- [London Borough Of Richmond Upon Thames](#london-borough-of-richmond-upon-thames) - [London Borough Redbridge](#london-borough-redbridge) - [London Borough Sutton](#london-borough-sutton) - [Luton Borough Council](#luton-borough-council) @@ -169,9 +170,9 @@ This document is still a work in progress, don't worry if your council isn't lis - [Merton Council](#merton-council) - [Mid and East Antrim Borough Council](#mid-and-east-antrim-borough-council) - [Mid Devon Council](#mid-devon-council) -- [Midlothian Council](#midlothian-council) - [Mid Suffolk District Council](#mid-suffolk-district-council) - [Mid Sussex District Council](#mid-sussex-district-council) +- [Midlothian Council](#midlothian-council) - [Milton Keynes City Council](#milton-keynes-city-council) - [Mole Valley District Council](#mole-valley-district-council) - [Monmouthshire County Council](#monmouthshire-county-council) @@ -196,8 +197,8 @@ This document is still a work in progress, don't worry if your council isn't lis - [North Tyneside Council](#north-tyneside-council) - [North West Leicestershire Council](#north-west-leicestershire-council) - [North Yorkshire Council](#north-yorkshire-council) -- [Norwich City Council](#norwich-city-council) - [Northumberland Council](#northumberland-council) +- [Norwich City Council](#norwich-city-council) - [Nottingham City Council](#nottingham-city-council) - [Nuneaton and Bedworth Borough Council](#nuneaton-and-bedworth-borough-council) - [Oadby & Wigston Borough Council](#oadby-&-wigston-borough-council) @@ -245,10 +246,10 @@ This document is still a work in progress, don't worry if your council isn't lis - [South Tyneside Council](#south-tyneside-council) - [Southwark Council](#southwark-council) - [St Albans City and District Council](#st-albans-city-and-district-council) -- [Stevenage Borough Council](#stevenage-borough-council) - [St Helens Borough Council](#st-helens-borough-council) - [Stafford Borough Council](#stafford-borough-council) - [Staffordshire Moorlands District Council](#staffordshire-moorlands-district-council) +- [Stevenage Borough Council](#stevenage-borough-council) - [Stockport Borough Council](#stockport-borough-council) - [Stockton On Tees Council](#stockton-on-tees-council) - [Stoke-on-Trent City Council](#stoke-on-trent-city-council) @@ -301,8 +302,8 @@ This document is still a work in progress, don't worry if your council isn't lis - [Wirral Council](#wirral-council) - [Woking Borough Council / Joint Waste Solutions](#woking-borough-council-/-joint-waste-solutions) - [Wokingham Borough Council](#wokingham-borough-council) -- [Worcester City Council](#worcester-city-council) - [Wolverhampton City Council](#wolverhampton-city-council) +- [Worcester City Council](#worcester-city-council) - [Wychavon District Council](#wychavon-district-council) - [Wyre Council](#wyre-council) - [Wyre Forest District Council](#wyre-forest-district-council) @@ -310,9 +311,9 @@ This document is still a work in progress, don't worry if your council isn't lis --- -### Aberdeenshire Council +### Aberdeen City Council ```commandline -python collect_data.py AberdeenshireCouncil https://online.aberdeenshire.gov.uk -u XXXXXXXX +python collect_data.py AberdeenCityCouncil https://www.aberdeencity.gov.uk -u XXXXXXXX ``` Additional parameters: - `-u` - UPRN @@ -321,9 +322,9 @@ Note: You will need to use [FindMyAddress](https://www.findmyaddress.co.uk/searc --- -### Aberdeen City Council +### Aberdeenshire Council ```commandline -python collect_data.py AberdeenCityCouncil https://www.aberdeencity.gov.uk -u XXXXXXXX +python collect_data.py AberdeenshireCouncil https://online.aberdeenshire.gov.uk -u XXXXXXXX ``` Additional parameters: - `-u` - UPRN @@ -446,29 +447,29 @@ Note: To get the UPRN, please use [FindMyAddress](https://www.findmyaddress.co.u --- -### Babergh District Council +### BCP Council ```commandline -python collect_data.py BaberghDistrictCouncil https://www.babergh.gov.uk -s -u XXXXXXXX -p "XXXX XXX" -n XX +python collect_data.py BCPCouncil https://online.bcpcouncil.gov.uk/bindaylookup/ -s -u XXXXXXXX ``` Additional parameters: - `-s` - skip get URL - `-u` - UPRN -- `-p` - postcode -- `-n` - house number -Note: Use the House Number field to pass the DAY of the week for your NORMAL collections. [Monday/Tuesday/Wednesday/Thursday/Friday]. [OPTIONAL] Use the 'postcode' field to pass the WEEK for your garden collection. [Week 1/Week 2]. [OPTIONAL] Use the 'uprn' field to pass the DAY for your garden collection. [Monday/Tuesday/Wednesday/Thursday/Friday] +Note: You will need to use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find the UPRN. --- -### BCP Council +### Babergh District Council ```commandline -python collect_data.py BCPCouncil https://online.bcpcouncil.gov.uk/bindaylookup/ -s -u XXXXXXXX +python collect_data.py BaberghDistrictCouncil https://www.babergh.gov.uk -s -u XXXXXXXX -p "XXXX XXX" -n XX ``` Additional parameters: - `-s` - skip get URL - `-u` - UPRN +- `-p` - postcode +- `-n` - house number -Note: You will need to use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find the UPRN. +Note: Use the House Number field to pass the DAY of the week for your NORMAL collections. [Monday/Tuesday/Wednesday/Thursday/Friday]. [OPTIONAL] Use the 'postcode' field to pass the WEEK for your garden collection. [Week 1/Week 2]. [OPTIONAL] Use the 'uprn' field to pass the DAY for your garden collection. [Monday/Tuesday/Wednesday/Thursday/Friday] --- @@ -948,14 +949,14 @@ Note: Follow the instructions [here](https://www.chelmsford.gov.uk/myhome/) unti ### Cheltenham Borough Council ```commandline -python collect_data.py CheltenhamBoroughCouncil https://www.cheltenham.gov.uk -s -p "XXXX XXX" -n XX +python collect_data.py CheltenhamBoroughCouncil https://www.cheltenham.gov.uk -s -u XXXXXXXX -p "XXXX XXX" ``` Additional parameters: - `-s` - skip get URL +- `-u` - UPRN - `-p` - postcode -- `-n` - house number -Note: Use the House Number field to pass the DAY of the week for your collections. [Monday/Tuesday/Wednesday/Thursday/Friday]. Use the 'postcode' field to pass the WEEK (wrapped in quotes) for your collections. [Week 1/Week 2]. +Note: Pass the UPRN. You will need to use [FindMyAddress](https://www.findmyaddress.co.uk/search). --- @@ -1129,26 +1130,26 @@ Note: Pass the house number and postcode in their respective parameters. --- -### Cumberland Borough Council +### Cumberland Council - Allerdale District ```commandline -python collect_data.py CumberlandCouncil https://waste.cumberland.gov.uk -u XXXXXXXX +python collect_data.py CumberlandAllerdaleCouncil https://www.allerdale.gov.uk -p "XXXX XXX" -n XX ``` Additional parameters: -- `-u` - UPRN +- `-p` - postcode +- `-n` - house number -Note: Use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find your UPRN. +Note: Pass the house number and postcode in their respective parameters. --- -### Cumberland Council - Allerdale District +### Cumberland Borough Council ```commandline -python collect_data.py CumberlandAllerdaleCouncil https://www.allerdale.gov.uk -p "XXXX XXX" -n XX +python collect_data.py CumberlandCouncil https://waste.cumberland.gov.uk -u XXXXXXXX ``` Additional parameters: -- `-p` - postcode -- `-n` - house number +- `-u` - UPRN -Note: Pass the house number and postcode in their respective parameters. +Note: Use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find your UPRN. --- @@ -1797,17 +1798,6 @@ Note: Provide your house number in the `house_number` parameter and postcode in --- -### Highland Council -```commandline -python collect_data.py HighlandCouncil https://www.highland.gov.uk -u XXXXXXXX -``` -Additional parameters: -- `-u` - UPRN - -Note: You will need to use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find the UPRN. - ---- - ### High Peak Council ```commandline python collect_data.py HighPeakCouncil https://www.highpeak.gov.uk/findyourbinday -s -p "XXXX XXX" -n XX -w http://HOST:PORT/ @@ -1822,6 +1812,17 @@ Note: Pass the name of the street with the house number parameter, wrapped in do --- +### Highland Council +```commandline +python collect_data.py HighlandCouncil https://www.highland.gov.uk -u XXXXXXXX +``` +Additional parameters: +- `-u` - UPRN + +Note: You will need to use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find the UPRN. + +--- + ### Hinckley and Bosworth Borough Council ```commandline python collect_data.py HinckleyandBosworthBoroughCouncil https://www.hinckley-bosworth.gov.uk -u XXXXXXXX @@ -1869,6 +1870,17 @@ Note: Replace XXXXXXXX with your UPRN. --- +### Ipswich Borough Council +```commandline +python collect_data.py IpswichBoroughCouncil https://app.ipswich.gov.uk/bin-collection/ -n XX +``` +Additional parameters: +- `-n` - house number + +Note: Provide only the street name (no house number) as the PAON + +--- + ### Islington Council ```commandline python collect_data.py IslingtonCouncil https://www.islington.gov.uk/your-area?Postcode=unused&Uprn=XXXXXXXX -u XXXXXXXX @@ -2022,18 +2034,6 @@ Note: Pass the UPRN. You can find it using [FindMyAddress](https://www.findmyadd --- -### London Borough Of Richmond Upon Thames -```commandline -python collect_data.py LondonBoroughOfRichmondUponThames https://www.richmond.gov.uk/services/waste_and_recycling/collection_days/ -s -n XX -``` -Additional parameters: -- `-s` - skip get URL -- `-n` - house number - -Note: Pass the name of the street ONLY in the house number parameter, unfortunately post code's are not allowed. - ---- - ### London Borough Harrow ```commandline python collect_data.py LondonBoroughHarrow https://www.harrow.gov.uk -u XXXXXXXX @@ -2094,6 +2094,18 @@ Note: Pass the UPRN and postcode. To get the UPRN, you can use [FindMyAddress](h --- +### London Borough Of Richmond Upon Thames +```commandline +python collect_data.py LondonBoroughOfRichmondUponThames https://www.richmond.gov.uk/services/waste_and_recycling/collection_days/ -s -n XX +``` +Additional parameters: +- `-s` - skip get URL +- `-n` - house number + +Note: Pass the name of the street ONLY in the house number parameter, unfortunately post code's are not allowed. + +--- + ### London Borough Redbridge ```commandline python collect_data.py LondonBoroughRedbridge https://my.redbridge.gov.uk/RecycleRefuse -u XXXXXXXX -p "XXXX XXX" -w http://HOST:PORT/ @@ -2222,44 +2234,44 @@ Note: You will need to use [FindMyAddress](https://www.findmyaddress.co.uk/searc --- -### Midlothian Council +### Mid Suffolk District Council ```commandline -python collect_data.py MidlothianCouncil https://www.midlothian.gov.uk/info/1054/bins_and_recycling/343/bin_collection_days -s -p "XXXX XXX" -n XX +python collect_data.py MidSuffolkDistrictCouncil https://www.midsuffolk.gov.uk -s -u XXXXXXXX -p "XXXX XXX" -n XX ``` Additional parameters: - `-s` - skip get URL +- `-u` - UPRN - `-p` - postcode - `-n` - house number -Note: Pass the house name/number wrapped in double quotes along with the postcode parameter. +Note: Use the House Number field to pass the DAY of the week for your NORMAL collections. [Monday/Tuesday/Wednesday/Thursday/Friday]. [OPTIONAL] Use the 'postcode' field to pass the WEEK for your garden collection. [Week 1/Week 2]. [OPTIONAL] Use the 'uprn' field to pass the DAY for your garden collection. [Monday/Tuesday/Wednesday/Thursday/Friday] --- -### Mid Suffolk District Council +### Mid Sussex District Council ```commandline -python collect_data.py MidSuffolkDistrictCouncil https://www.midsuffolk.gov.uk -s -u XXXXXXXX -p "XXXX XXX" -n XX +python collect_data.py MidSussexDistrictCouncil https://www.midsussex.gov.uk/waste-recycling/bin-collection/ -s -p "XXXX XXX" -n XX -w http://HOST:PORT/ ``` Additional parameters: - `-s` - skip get URL -- `-u` - UPRN - `-p` - postcode - `-n` - house number +- `-w` - remote Selenium web driver URL (required for Home Assistant) -Note: Use the House Number field to pass the DAY of the week for your NORMAL collections. [Monday/Tuesday/Wednesday/Thursday/Friday]. [OPTIONAL] Use the 'postcode' field to pass the WEEK for your garden collection. [Week 1/Week 2]. [OPTIONAL] Use the 'uprn' field to pass the DAY for your garden collection. [Monday/Tuesday/Wednesday/Thursday/Friday] +Note: Pass the name of the street with the house number parameter, wrapped in double quotes. This parser requires a Selenium webdriver. --- -### Mid Sussex District Council +### Midlothian Council ```commandline -python collect_data.py MidSussexDistrictCouncil https://www.midsussex.gov.uk/waste-recycling/bin-collection/ -s -p "XXXX XXX" -n XX -w http://HOST:PORT/ +python collect_data.py MidlothianCouncil https://www.midlothian.gov.uk/info/1054/bins_and_recycling/343/bin_collection_days -s -p "XXXX XXX" -n XX ``` Additional parameters: - `-s` - skip get URL - `-p` - postcode - `-n` - house number -- `-w` - remote Selenium web driver URL (required for Home Assistant) -Note: Pass the name of the street with the house number parameter, wrapped in double quotes. This parser requires a Selenium webdriver. +Note: Pass the house name/number wrapped in double quotes along with the postcode parameter. --- @@ -2546,17 +2558,6 @@ Note: Pass the UPRN. You can find it using [FindMyAddress](https://www.findmyadd --- -### Norwich City Council -```commandline -python collect_data.py NorwichCityCouncil https://www.norwich.gov.uk -u XXXXXXXX -``` -Additional parameters: -- `-u` - UPRN - -Note: You will need to use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find the UPRN. - ---- - ### Northumberland Council ```commandline python collect_data.py NorthumberlandCouncil https://www.northumberland.gov.uk/Waste/Household-waste/Household-bin-collections/Bin-Calendars.aspx -s -p "XXXX XXX" -n XX -w http://HOST:PORT/ @@ -2571,6 +2572,17 @@ Note: Pass the house number and postcode in their respective parameters. This pa --- +### Norwich City Council +```commandline +python collect_data.py NorwichCityCouncil https://www.norwich.gov.uk -u XXXXXXXX +``` +Additional parameters: +- `-u` - UPRN + +Note: You will need to use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find the UPRN. + +--- + ### Nottingham City Council ```commandline python collect_data.py NottinghamCityCouncil https://geoserver.nottinghamcity.gov.uk/bincollections2/api/collection/100031540180 -s -u XXXXXXXX @@ -3121,17 +3133,6 @@ Note: Provide your UPRN. You can find it using [FindMyAddress](https://www.findm --- -### Stevenage Borough Council -```commandline -python collect_data.py StevenageBoroughCouncil https://www.stevenage.gov.uk -u XXXXXXXX -``` -Additional parameters: -- `-u` - UPRN - -Note: Use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find your UPRN. - ---- - ### St Helens Borough Council ```commandline python collect_data.py StHelensBC https://www.sthelens.gov.uk/ -s -p "XXXX XXX" -n XX -w http://HOST:PORT/ @@ -3171,6 +3172,17 @@ Note: Provide your UPRN and postcode. Use [FindMyAddress](https://www.findmyaddr --- +### Stevenage Borough Council +```commandline +python collect_data.py StevenageBoroughCouncil https://www.stevenage.gov.uk -u XXXXXXXX +``` +Additional parameters: +- `-u` - UPRN + +Note: Use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find your UPRN. + +--- + ### Stockport Borough Council ```commandline python collect_data.py StockportBoroughCouncil https://myaccount.stockport.gov.uk/bin-collections/show/XXXXXXXX @@ -3812,26 +3824,26 @@ Note: Provide your house number in the `house_number` parameter and postcode in --- -### Worcester City Council +### Wolverhampton City Council ```commandline -python collect_data.py WorcesterCityCouncil https://www.Worcester.gov.uk -u XXXXXXXX +python collect_data.py WolverhamptonCityCouncil https://www.wolverhampton.gov.uk -u XXXXXXXX -p "XXXX XXX" ``` Additional parameters: - `-u` - UPRN +- `-p` - postcode -Note: You will need to use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find the UPRN. +Note: Use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find your UPRN. --- -### Wolverhampton City Council +### Worcester City Council ```commandline -python collect_data.py WolverhamptonCityCouncil https://www.wolverhampton.gov.uk -u XXXXXXXX -p "XXXX XXX" +python collect_data.py WorcesterCityCouncil https://www.Worcester.gov.uk -u XXXXXXXX ``` Additional parameters: - `-u` - UPRN -- `-p` - postcode -Note: Use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find your UPRN. +Note: You will need to use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find the UPRN. --- From 86acabcf85d204c63789b40876e5299e52de6703 Mon Sep 17 00:00:00 2001 From: m26dvd <31007572+m26dvd@users.noreply.github.com> Date: Tue, 11 Feb 2025 22:50:16 +0000 Subject: [PATCH 11/18] fix: Tendring District Council fix: #1221 --- .../uk_bin_collection/councils/TendringDistrictCouncil.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uk_bin_collection/uk_bin_collection/councils/TendringDistrictCouncil.py b/uk_bin_collection/uk_bin_collection/councils/TendringDistrictCouncil.py index b211d0ba44..5c8355d4e2 100644 --- a/uk_bin_collection/uk_bin_collection/councils/TendringDistrictCouncil.py +++ b/uk_bin_collection/uk_bin_collection/councils/TendringDistrictCouncil.py @@ -84,7 +84,7 @@ def parse_data(self, page: str, **kwargs) -> dict: if bin: if bin[1].get_text(strip=True) != "": bin_date = datetime.strptime( - bin[1].get_text(strip=True), "%d/%m/%Y" + bin[1].get_text(strip=True), "%d/%m/%Y %H:%M:%S" ) dict_data = { "type": re.sub( From f20394850e8401b351040b23761f45ce32e946c3 Mon Sep 17 00:00:00 2001 From: m26dvd <31007572+m26dvd@users.noreply.github.com> Date: Tue, 11 Feb 2025 23:03:36 +0000 Subject: [PATCH 12/18] fix: Sunderland City Council fix: #1219 --- .../councils/SunderlandCityCouncil.py | 36 +++++++++++-------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/uk_bin_collection/uk_bin_collection/councils/SunderlandCityCouncil.py b/uk_bin_collection/uk_bin_collection/councils/SunderlandCityCouncil.py index 855dc4b30a..2b27911d08 100644 --- a/uk_bin_collection/uk_bin_collection/councils/SunderlandCityCouncil.py +++ b/uk_bin_collection/uk_bin_collection/councils/SunderlandCityCouncil.py @@ -62,21 +62,27 @@ def parse_data(self, page: str, **kwargs) -> dict: soup = BeautifulSoup(driver.page_source, features="html.parser") soup.prettify() - household_bin_date = datetime.strptime( - soup.find("span", {"id": "ContentPlaceHolder1_LabelHouse"}).get_text( - strip=True - ), - "%A %d %B %Y", - ) - collections.append(("Household bin", household_bin_date)) - - recycling_bin_date = datetime.strptime( - soup.find("span", {"id": "ContentPlaceHolder1_LabelRecycle"}).get_text( - strip=True - ), - "%A %d %B %Y", - ) - collections.append(("Recycling bin", recycling_bin_date)) + try: + household_bin_date = datetime.strptime( + soup.find( + "span", {"id": "ContentPlaceHolder1_LabelHouse"} + ).get_text(strip=True), + "%A %d %B %Y", + ) + collections.append(("Household bin", household_bin_date)) + except AttributeError: + pass + + try: + recycling_bin_date = datetime.strptime( + soup.find( + "span", {"id": "ContentPlaceHolder1_LabelRecycle"} + ).get_text(strip=True), + "%A %d %B %Y", + ) + collections.append(("Recycling bin", recycling_bin_date)) + except AttributeError: + pass ordered_data = sorted(collections, key=lambda x: x[1]) for item in ordered_data: From 9fe78a486405d5b61da5c425e9054ff4db47e62a Mon Sep 17 00:00:00 2001 From: m26dvd <31007572+m26dvd@users.noreply.github.com> Date: Tue, 11 Feb 2025 23:38:09 +0000 Subject: [PATCH 13/18] fix: Conwy County Borough --- uk_bin_collection/tests/input.json | 5 ++--- .../councils/ConwyCountyBorough.py | 14 +++++++++++--- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/uk_bin_collection/tests/input.json b/uk_bin_collection/tests/input.json index 00cd73bef5..ce8350ab96 100755 --- a/uk_bin_collection/tests/input.json +++ b/uk_bin_collection/tests/input.json @@ -457,11 +457,10 @@ "wiki_note": "Pass the house name/number in the house number parameter, wrapped in double quotes." }, "ConwyCountyBorough": { - "postcode": "LL30 2DF", "uprn": "100100429249", - "url": "https://www.conwy.gov.uk/Contensis-Forms/erf/collection-result-soap-xmas.asp?ilangid=1&uprn=100100429249", + "url": "https://www.conwy.gov.uk", "wiki_name": "Conwy County Borough Council", - "wiki_note": "Conwy County Borough Council uses a straight UPRN in the URL, e.g., `&uprn=XXXXXXXXXXXXX`." + "wiki_note": "Use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find your UPRN." }, "CopelandBoroughCouncil": { "uprn": "100110734613", diff --git a/uk_bin_collection/uk_bin_collection/councils/ConwyCountyBorough.py b/uk_bin_collection/uk_bin_collection/councils/ConwyCountyBorough.py index ee1fc645f3..49f6724623 100644 --- a/uk_bin_collection/uk_bin_collection/councils/ConwyCountyBorough.py +++ b/uk_bin_collection/uk_bin_collection/councils/ConwyCountyBorough.py @@ -1,12 +1,20 @@ +from datetime import datetime + +import requests from bs4 import BeautifulSoup -from uk_bin_collection.uk_bin_collection.get_bin_data import AbstractGetBinDataClass + from uk_bin_collection.uk_bin_collection.common import * -from datetime import datetime +from uk_bin_collection.uk_bin_collection.get_bin_data import AbstractGetBinDataClass class CouncilClass(AbstractGetBinDataClass): def parse_data(self, page: str, **kwargs) -> dict: - soup = BeautifulSoup(page.text, features="html.parser") + user_uprn = kwargs.get("uprn") + check_uprn(user_uprn) + uri = f"https://www.conwy.gov.uk/Contensis-Forms/erf/collection-result-soap-xmas2025.asp?ilangid=1&uprn={user_uprn}" + + response = requests.get(uri) + soup = BeautifulSoup(response.content, features="html.parser") data = {"bins": []} for bin_section in soup.select('div[class*="containererf"]'): From c7ee80e08be7f4cf1d7c9b0032bcd383c8958d20 Mon Sep 17 00:00:00 2001 From: Wiki GitHub Action Date: Tue, 11 Feb 2025 23:38:47 +0000 Subject: [PATCH 14/18] docs: Update Councils.md from input.json --- wiki/Councils.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/wiki/Councils.md b/wiki/Councils.md index ecf11e7b73..af1b7cf83b 100644 --- a/wiki/Councils.md +++ b/wiki/Councils.md @@ -1048,13 +1048,12 @@ Note: Pass the house name/number in the house number parameter, wrapped in doubl ### Conwy County Borough Council ```commandline -python collect_data.py ConwyCountyBorough https://www.conwy.gov.uk/Contensis-Forms/erf/collection-result-soap-xmas.asp?ilangid=1&uprn=100100429249 -u XXXXXXXX -p "XXXX XXX" +python collect_data.py ConwyCountyBorough https://www.conwy.gov.uk -u XXXXXXXX ``` Additional parameters: - `-u` - UPRN -- `-p` - postcode -Note: Conwy County Borough Council uses a straight UPRN in the URL, e.g., `&uprn=XXXXXXXXXXXXX`. +Note: Use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find your UPRN. --- From f4890eb80b740af3403d014c48fcc4dc35db5e9c Mon Sep 17 00:00:00 2001 From: m26dvd <31007572+m26dvd@users.noreply.github.com> Date: Wed, 12 Feb 2025 00:14:41 +0000 Subject: [PATCH 15/18] fix: Derbyshire Dales District Council --- uk_bin_collection/tests/input.json | 1 - .../DerbyshireDalesDistrictCouncil.py | 104 +++++++++--------- wiki/Councils.md | 8 +- 3 files changed, 57 insertions(+), 56 deletions(-) diff --git a/uk_bin_collection/tests/input.json b/uk_bin_collection/tests/input.json index ce8350ab96..dbb1098ee4 100755 --- a/uk_bin_collection/tests/input.json +++ b/uk_bin_collection/tests/input.json @@ -551,7 +551,6 @@ "skip_get_url": true, "uprn": "10070102161", "url": "https://www.derbyshiredales.gov.uk/", - "web_driver": "http://selenium:4444", "wiki_name": "Derbyshire Dales District Council", "wiki_note": "Pass the UPRN and postcode. To get the UPRN, you can use [FindMyAddress](https://www.findmyaddress.co.uk/search)." }, diff --git a/uk_bin_collection/uk_bin_collection/councils/DerbyshireDalesDistrictCouncil.py b/uk_bin_collection/uk_bin_collection/councils/DerbyshireDalesDistrictCouncil.py index dd10e04037..8688e45fd9 100644 --- a/uk_bin_collection/uk_bin_collection/councils/DerbyshireDalesDistrictCouncil.py +++ b/uk_bin_collection/uk_bin_collection/councils/DerbyshireDalesDistrictCouncil.py @@ -1,8 +1,5 @@ +import requests from bs4 import BeautifulSoup -from selenium.webdriver.common.by import By -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 @@ -19,63 +16,70 @@ class CouncilClass(AbstractGetBinDataClass): def parse_data(self, page: str, **kwargs) -> dict: driver = None try: - page = "https://selfserve.derbyshiredales.gov.uk/renderform.aspx?t=103&k=9644C066D2168A4C21BCDA351DA2642526359DFF" + uri = "https://selfserve.derbyshiredales.gov.uk/renderform.aspx?t=103&k=9644C066D2168A4C21BCDA351DA2642526359DFF" - data = {"bins": []} + bindata = {"bins": []} user_uprn = kwargs.get("uprn") user_postcode = kwargs.get("postcode") - web_driver = kwargs.get("web_driver") - headless = kwargs.get("headless") check_uprn(user_uprn) check_postcode(user_postcode) - # Create Selenium webdriver - driver = create_webdriver(web_driver, headless, None, __name__) - driver.get(page) + # Start a session + session = requests.Session() - # Populate postcode field - inputElement_postcode = driver.find_element( - By.ID, - "ctl00_ContentPlaceHolder1_FF2924TB", - ) - inputElement_postcode.send_keys(user_postcode) - - # Click search button - driver.find_element( - By.ID, - "ctl00_ContentPlaceHolder1_FF2924BTN", - ).click() - - # Wait for the 'Select address' dropdown to appear and select option matching UPRN - dropdown = WebDriverWait(driver, 10).until( - EC.presence_of_element_located( - (By.ID, "ctl00_ContentPlaceHolder1_FF2924DDL") - ) - ) - # Create a 'Select' for it, then select the matching URPN option - dropdownSelect = Select(dropdown) - dropdownSelect.select_by_value("U" + user_uprn) - - # Wait for the submit button to appear, then click it to get the collection dates - submit = WebDriverWait(driver, 10).until( - EC.presence_of_element_located( - (By.ID, "ctl00_ContentPlaceHolder1_btnSubmit") - ) - ) - submit.click() + response = session.get(uri) - soup = BeautifulSoup(driver.page_source, features="html.parser") + soup = BeautifulSoup(response.content, features="html.parser") - bin_rows = ( - soup.find("div", id="ctl00_ContentPlaceHolder1_pnlConfirmation") - .find("div", {"class": "row"}) - .find_all("div", {"class": "row"}) - ) + # Function to extract hidden input values + def get_hidden_value(soup, name): + element = soup.find("input", {"name": name}) + return element["value"] if element else None + + # Extract the required values + data = { + "__RequestVerificationToken": get_hidden_value( + soup, "__RequestVerificationToken" + ), + "FormGuid": get_hidden_value(soup, "FormGuid"), + "ObjectTemplateID": get_hidden_value(soup, "ObjectTemplateID"), + "Trigger": "submit", + "CurrentSectionID": get_hidden_value(soup, "CurrentSectionID"), + "TriggerCtl": "", + "FF2924": "U" + user_uprn, + "FF2924lbltxt": "Collection address", + "FF2924-text": user_postcode, + } + + # Print extracted data + # print("Extracted Data:", data) + + # Step 2: Submit the extracted data via a POST request + headers = { + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36", + "Referer": uri, + "Content-Type": "application/x-www-form-urlencoded", + } + + URI = "https://selfserve.derbyshiredales.gov.uk/renderform/Form" + + # Make the POST request + post_response = session.post(URI, data=data, headers=headers) + + soup = BeautifulSoup(post_response.content, features="html.parser") + + # print(soup) + + bin_rows = soup.find("div", {"class": "ss_confPanel"}) + + bin_rows = bin_rows.find_all("div", {"class": "row"}) if bin_rows: for bin_row in bin_rows: bin_data = bin_row.find_all("div") if bin_data and bin_data[0] and bin_data[1]: + if bin_data[0].get_text(strip=True) == "Your Collections": + continue collection_date = datetime.strptime( bin_data[0].get_text(strip=True), "%A%d %B, %Y" ) @@ -83,9 +87,9 @@ def parse_data(self, page: str, **kwargs) -> dict: "type": bin_data[1].get_text(strip=True), "collectionDate": collection_date.strftime(date_format), } - data["bins"].append(dict_data) + bindata["bins"].append(dict_data) - data["bins"].sort( + bindata["bins"].sort( key=lambda x: datetime.strptime(x.get("collectionDate"), date_format) ) except Exception as e: @@ -97,4 +101,4 @@ def parse_data(self, page: str, **kwargs) -> dict: # This block ensures that the driver is closed regardless of an exception if driver: driver.quit() - return data + return bindata diff --git a/wiki/Councils.md b/wiki/Councils.md index ecf11e7b73..83d58992f0 100644 --- a/wiki/Councils.md +++ b/wiki/Councils.md @@ -1048,13 +1048,12 @@ Note: Pass the house name/number in the house number parameter, wrapped in doubl ### Conwy County Borough Council ```commandline -python collect_data.py ConwyCountyBorough https://www.conwy.gov.uk/Contensis-Forms/erf/collection-result-soap-xmas.asp?ilangid=1&uprn=100100429249 -u XXXXXXXX -p "XXXX XXX" +python collect_data.py ConwyCountyBorough https://www.conwy.gov.uk -u XXXXXXXX ``` Additional parameters: - `-u` - UPRN -- `-p` - postcode -Note: Conwy County Borough Council uses a straight UPRN in the URL, e.g., `&uprn=XXXXXXXXXXXXX`. +Note: Use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find your UPRN. --- @@ -1202,13 +1201,12 @@ Note: You will need to use [FindMyAddress](https://www.findmyaddress.co.uk/searc ### Derbyshire Dales District Council ```commandline -python collect_data.py DerbyshireDalesDistrictCouncil https://www.derbyshiredales.gov.uk/ -s -u XXXXXXXX -p "XXXX XXX" -w http://HOST:PORT/ +python collect_data.py DerbyshireDalesDistrictCouncil https://www.derbyshiredales.gov.uk/ -s -u XXXXXXXX -p "XXXX XXX" ``` Additional parameters: - `-s` - skip get URL - `-u` - UPRN - `-p` - postcode -- `-w` - remote Selenium web driver URL (required for Home Assistant) Note: Pass the UPRN and postcode. To get the UPRN, you can use [FindMyAddress](https://www.findmyaddress.co.uk/search). From 1838b235b7cbb22e9ac2d0e50c66c97bfcf2da39 Mon Sep 17 00:00:00 2001 From: Wiki GitHub Action Date: Mon, 17 Feb 2025 21:22:29 +0000 Subject: [PATCH 16/18] docs: Update Councils.md from input.json --- wiki/Councils.md | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/wiki/Councils.md b/wiki/Councils.md index 83d58992f0..3bc6469306 100644 --- a/wiki/Councils.md +++ b/wiki/Councils.md @@ -425,11 +425,12 @@ Note: Pass the house name/number and postcode in their respective parameters, bo ### Ashford Borough Council ```commandline -python collect_data.py AshfordBoroughCouncil https://ashford.gov.uk -u XXXXXXXX -p "XXXX XXX" +python collect_data.py AshfordBoroughCouncil https://ashford.gov.uk -u XXXXXXXX -p "XXXX XXX" -w http://HOST:PORT/ ``` Additional parameters: - `-u` - UPRN - `-p` - postcode +- `-w` - remote Selenium web driver URL (required for Home Assistant) Note: You will need to use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find the UPRN. @@ -1325,12 +1326,13 @@ Note: Replace XXXXXXXX with your UPRN. ### East Herts Council ```commandline -python collect_data.py EastHertsCouncil https://www.eastherts.gov.uk -s -p "XXXX XXX" -n XX +python collect_data.py EastHertsCouncil https://www.eastherts.gov.uk -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 house number and postcode in their respective parameters. @@ -1475,10 +1477,11 @@ Note: For properties with collections managed by Environment First, such as Lewe ### Epping Forest District Council ```commandline -python collect_data.py EppingForestDistrictCouncil https://eppingforestdc.maps.arcgis.com/apps/instant/lookup/index.html?appid=bfca32b46e2a47cd9c0a84f2d8cdde17&find=IG9%206EP -p "XXXX XXX" +python collect_data.py EppingForestDistrictCouncil https://eppingforestdc.maps.arcgis.com/apps/instant/lookup/index.html?appid=bfca32b46e2a47cd9c0a84f2d8cdde17&find=IG9%206EP -p "XXXX XXX" -w http://HOST:PORT/ ``` Additional parameters: - `-p` - postcode +- `-w` - remote Selenium web driver URL (required for Home Assistant) Note: Replace the postcode in the URL with your own. @@ -1903,8 +1906,10 @@ Note: Provide your UPRN. Find your UPRN using [FindMyAddress](https://www.findmy ### Kingston Upon Thames Council ```commandline -python collect_data.py KingstonUponThamesCouncil https://waste-services.kingston.gov.uk/waste/XXXXXXX +python collect_data.py KingstonUponThamesCouncil https://waste-services.kingston.gov.uk/waste/XXXXXXX -w http://HOST:PORT/ ``` +Additional parameters: +- `-w` - remote Selenium web driver URL (required for Home Assistant) Note: Follow the instructions [here](https://waste-services.kingston.gov.uk/waste) until the "Your bin days" page, then copy the URL and replace the URL in the command. @@ -2094,11 +2099,12 @@ Note: Pass the UPRN and postcode. To get the UPRN, you can use [FindMyAddress](h ### London Borough Of Richmond Upon Thames ```commandline -python collect_data.py LondonBoroughOfRichmondUponThames https://www.richmond.gov.uk/services/waste_and_recycling/collection_days/ -s -n XX +python collect_data.py LondonBoroughOfRichmondUponThames https://www.richmond.gov.uk/services/waste_and_recycling/collection_days/ -s -n XX -w http://HOST:PORT/ ``` Additional parameters: - `-s` - skip get URL - `-n` - house number +- `-w` - remote Selenium web driver URL (required for Home Assistant) Note: Pass the name of the street ONLY in the house number parameter, unfortunately post code's are not allowed. From f1b558d32f154396cd6ac01709e8c93836e269e6 Mon Sep 17 00:00:00 2001 From: m26dvd <31007572+m26dvd@users.noreply.github.com> Date: Mon, 17 Feb 2025 21:33:04 +0000 Subject: [PATCH 17/18] fix: Leeds City Council fix: #1222 --- .../uk_bin_collection/councils/LeedsCityCouncil.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/uk_bin_collection/uk_bin_collection/councils/LeedsCityCouncil.py b/uk_bin_collection/uk_bin_collection/councils/LeedsCityCouncil.py index 065bf2d6d5..23e1b8da50 100644 --- a/uk_bin_collection/uk_bin_collection/councils/LeedsCityCouncil.py +++ b/uk_bin_collection/uk_bin_collection/councils/LeedsCityCouncil.py @@ -104,7 +104,8 @@ def parse_data(self, page: str, **kwargs) -> dict: bin_types = soup.find_all("ul", class_="binCollectionTimesList") for bin_collection_dates in bin_types: - bin_collection_list = bin_collection_dates.find_all("li", class_="") + + bin_collection_list = bin_collection_dates.find_all("li") if bin_collection_list: collection_dates = [ From 29bd623b541399817ad1751a7cb454eb4f35619b Mon Sep 17 00:00:00 2001 From: m26dvd <31007572+m26dvd@users.noreply.github.com> Date: Mon, 17 Feb 2025 21:50:41 +0000 Subject: [PATCH 18/18] fix: Cotswold District Council fix: #1238 --- .../uk_bin_collection/councils/CotswoldDistrictCouncil.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/uk_bin_collection/uk_bin_collection/councils/CotswoldDistrictCouncil.py b/uk_bin_collection/uk_bin_collection/councils/CotswoldDistrictCouncil.py index 509b1cb9a2..d19f1dcdef 100644 --- a/uk_bin_collection/uk_bin_collection/councils/CotswoldDistrictCouncil.py +++ b/uk_bin_collection/uk_bin_collection/councils/CotswoldDistrictCouncil.py @@ -41,15 +41,13 @@ def parse_data(self, page: str, **kwargs) -> dict: # 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-20"]') - ) + EC.element_to_be_clickable((By.XPATH, '//*[@id="combobox-input-22"]')) ) address_entry_field.send_keys(str(full_address)) address_entry_field = wait.until( - EC.element_to_be_clickable((By.XPATH, '//*[@id="combobox-input-20"]')) + EC.element_to_be_clickable((By.XPATH, '//*[@id="combobox-input-22"]')) ) address_entry_field.click() address_entry_field.send_keys(Keys.BACKSPACE) @@ -57,7 +55,7 @@ def parse_data(self, page: str, **kwargs) -> dict: first_found_address = wait.until( EC.element_to_be_clickable( - (By.XPATH, '//*[@id="dropdown-element-20"]/ul') + (By.XPATH, '//*[@id="dropdown-element-22"]/ul') ) )