From 1745ca3abeb9c9a4157b44facc6e2357a851799b Mon Sep 17 00:00:00 2001 From: m26dvd <31007572+m26dvd@users.noreply.github.com> Date: Tue, 12 Nov 2024 17:32:39 +0000 Subject: [PATCH 1/9] fix: Adding Garden collection to Babergh and MidSuffolk Council fix: #995 --- uk_bin_collection/tests/input.json | 6 +- .../councils/BaberghDistrictCouncil.py | 62 +++++++++++++++++++ .../councils/MidSuffolkDistrictCouncil.py | 62 +++++++++++++++++++ 3 files changed, 128 insertions(+), 2 deletions(-) diff --git a/uk_bin_collection/tests/input.json b/uk_bin_collection/tests/input.json index cb09cb81fa..d349352c3f 100644 --- a/uk_bin_collection/tests/input.json +++ b/uk_bin_collection/tests/input.json @@ -81,9 +81,10 @@ "BaberghDistrictCouncil": { "skip_get_url": true, "house_number": "Monday", + "postcode": "Week 1", "url": "https://www.babergh.gov.uk", "wiki_name": "Babergh District Council", - "wiki_note": "Use the House Number field to pass the DAY of the week for your collections. Monday/Tuesday/Wednesday/Thursday/Friday" + "wiki_note": "Use the House Number field to pass the DAY of the week for your collections. Monday/Tuesday/Wednesday/Thursday/Friday. [OPTIONAL] Use the 'postcode' field to pass the WEEK for your garden collection. [Week 1/Week 2]" }, "BCPCouncil": { "skip_get_url": true, @@ -1005,9 +1006,10 @@ "MidSuffolkDistrictCouncil": { "skip_get_url": true, "house_number": "Monday", + "postcode": "Week 2", "url": "https://www.midsuffolk.gov.uk", "wiki_name": "Mid Suffolk District Council", - "wiki_note": "Use the House Number field to pass the DAY of the week for your collections. Monday/Tuesday/Wednesday/Thursday/Friday" + "wiki_note": "Use the House Number field to pass the DAY of the week for your collections. Monday/Tuesday/Wednesday/Thursday/Friday. [OPTIONAL] Use the 'postcode' field to pass the WEEK for your garden collection. [Week 1/Week 2]" }, "MidSussexDistrictCouncil": { "house_number": "OAKLANDS, OAKLANDS ROAD RH16 1SS", diff --git a/uk_bin_collection/uk_bin_collection/councils/BaberghDistrictCouncil.py b/uk_bin_collection/uk_bin_collection/councils/BaberghDistrictCouncil.py index 562cb5d8fb..cc178d9bfb 100644 --- a/uk_bin_collection/uk_bin_collection/councils/BaberghDistrictCouncil.py +++ b/uk_bin_collection/uk_bin_collection/councils/BaberghDistrictCouncil.py @@ -23,6 +23,7 @@ class CouncilClass(AbstractGetBinDataClass): def parse_data(self, page: str, **kwargs) -> dict: collection_day = kwargs.get("paon") + garden_collection_week = kwargs.get("postcode") bindata = {"bins": []} days_of_week = [ @@ -35,10 +36,14 @@ def parse_data(self, page: str, **kwargs) -> dict: "Sunday", ] + garden_week = ["Week 1", "Week 2"] + refusestartDate = datetime(2024, 11, 4) recyclingstartDate = datetime(2024, 11, 11) offset_days = days_of_week.index(collection_day) + if garden_collection_week: + garden_collection = garden_week.index(garden_collection_week) refuse_dates = get_dates_every_x_days(refusestartDate, 14, 28) recycling_dates = get_dates_every_x_days(recyclingstartDate, 14, 28) @@ -125,6 +130,63 @@ def parse_data(self, page: str, **kwargs) -> dict: } bindata["bins"].append(dict_data) + if garden_collection_week: + if garden_collection == 0: + gardenstartDate = datetime(2024, 11, 11) + elif garden_collection == 1: + gardenstartDate = datetime(2024, 11, 4) + + garden_dates = get_dates_every_x_days(gardenstartDate, 14, 28) + + garden_bank_holidays = [ + ("23/12/2024", 1), + ("24/12/2024", 1), + ("25/12/2024", 1), + ("26/12/2024", 1), + ("27/12/2024", 1), + ("30/12/2024", 1), + ("31/12/2024", 1), + ("01/01/2025", 1), + ("02/01/2025", 1), + ("03/01/2025", 1), + ] + + for gardenDate in garden_dates: + + collection_date = ( + datetime.strptime(gardenDate, "%d/%m/%Y") + + timedelta(days=offset_days) + ).strftime("%d/%m/%Y") + + garden_holiday = next( + ( + value + for date, value in garden_bank_holidays + if date == collection_date + ), + 0, + ) + + if garden_holiday > 0: + continue + + holiday_offset = next( + (value for date, value in bank_holidays if date == collection_date), + 0, + ) + + if holiday_offset > 0: + collection_date = ( + datetime.strptime(collection_date, "%d/%m/%Y") + + timedelta(days=holiday_offset) + ).strftime("%d/%m/%Y") + + dict_data = { + "type": "Garden Bin", + "collectionDate": collection_date, + } + bindata["bins"].append(dict_data) + bindata["bins"].sort( key=lambda x: datetime.strptime(x.get("collectionDate"), "%d/%m/%Y") ) diff --git a/uk_bin_collection/uk_bin_collection/councils/MidSuffolkDistrictCouncil.py b/uk_bin_collection/uk_bin_collection/councils/MidSuffolkDistrictCouncil.py index 788d5dd311..a9e7d1458e 100644 --- a/uk_bin_collection/uk_bin_collection/councils/MidSuffolkDistrictCouncil.py +++ b/uk_bin_collection/uk_bin_collection/councils/MidSuffolkDistrictCouncil.py @@ -23,6 +23,7 @@ class CouncilClass(AbstractGetBinDataClass): def parse_data(self, page: str, **kwargs) -> dict: collection_day = kwargs.get("paon") + garden_collection_week = kwargs.get("postcode") bindata = {"bins": []} days_of_week = [ @@ -35,10 +36,14 @@ def parse_data(self, page: str, **kwargs) -> dict: "Sunday", ] + garden_week = ["Week 1", "Week 2"] + refusestartDate = datetime(2024, 11, 11) recyclingstartDate = datetime(2024, 11, 4) offset_days = days_of_week.index(collection_day) + if garden_collection_week: + garden_collection = garden_week.index(garden_collection_week) refuse_dates = get_dates_every_x_days(refusestartDate, 14, 28) recycling_dates = get_dates_every_x_days(recyclingstartDate, 14, 28) @@ -125,6 +130,63 @@ def parse_data(self, page: str, **kwargs) -> dict: } bindata["bins"].append(dict_data) + if garden_collection_week: + if garden_collection == 0: + gardenstartDate = datetime(2024, 11, 11) + elif garden_collection == 1: + gardenstartDate = datetime(2024, 11, 4) + + garden_dates = get_dates_every_x_days(gardenstartDate, 14, 28) + + garden_bank_holidays = [ + ("23/12/2024", 1), + ("24/12/2024", 1), + ("25/12/2024", 1), + ("26/12/2024", 1), + ("27/12/2024", 1), + ("30/12/2024", 1), + ("31/12/2024", 1), + ("01/01/2025", 1), + ("02/01/2025", 1), + ("03/01/2025", 1), + ] + + for gardenDate in garden_dates: + + collection_date = ( + datetime.strptime(gardenDate, "%d/%m/%Y") + + timedelta(days=offset_days) + ).strftime("%d/%m/%Y") + + garden_holiday = next( + ( + value + for date, value in garden_bank_holidays + if date == collection_date + ), + 0, + ) + + if garden_holiday > 0: + continue + + holiday_offset = next( + (value for date, value in bank_holidays if date == collection_date), + 0, + ) + + if holiday_offset > 0: + collection_date = ( + datetime.strptime(collection_date, "%d/%m/%Y") + + timedelta(days=holiday_offset) + ).strftime("%d/%m/%Y") + + dict_data = { + "type": "Garden Bin", + "collectionDate": collection_date, + } + bindata["bins"].append(dict_data) + bindata["bins"].sort( key=lambda x: datetime.strptime(x.get("collectionDate"), "%d/%m/%Y") ) From f38bbf91254598a979bf032ff2adb9b54cb6d701 Mon Sep 17 00:00:00 2001 From: m26dvd <31007572+m26dvd@users.noreply.github.com> Date: Thu, 14 Nov 2024 22:31:50 +0000 Subject: [PATCH 2/9] fix: CrawleyBoroughCouncil fix: #1005 --- .../councils/CrawleyBoroughCouncil.py | 131 ++++++++++++------ 1 file changed, 91 insertions(+), 40 deletions(-) diff --git a/uk_bin_collection/uk_bin_collection/councils/CrawleyBoroughCouncil.py b/uk_bin_collection/uk_bin_collection/councils/CrawleyBoroughCouncil.py index 498f45db41..4d5eceed4c 100644 --- a/uk_bin_collection/uk_bin_collection/councils/CrawleyBoroughCouncil.py +++ b/uk_bin_collection/uk_bin_collection/councils/CrawleyBoroughCouncil.py @@ -1,4 +1,6 @@ -from bs4 import BeautifulSoup +import time + +import requests from dateutil.relativedelta import relativedelta from uk_bin_collection.uk_bin_collection.common import * @@ -19,43 +21,92 @@ def parse_data(self, page: str, **kwargs) -> dict: usrn = kwargs.get("paon") check_uprn(uprn) check_usrn(usrn) + bindata = {"bins": []} + + SESSION_URL = "https://crawleybc-self.achieveservice.com/authapi/isauthenticated?uri=https%253A%252F%252Fcrawleybc-self.achieveservice.com%252Fen%252FAchieveForms%252F%253Fform_uri%253Dsandbox-publish%253A%252F%252FAF-Process-fb73f73e-e8f5-4441-9f83-8b5d04d889d6%252FAF-Stage-ec9ada91-d2d9-43bc-9730-597d15fc8108%252Fdefinition.json%2526redirectlink%253D%252Fen%2526cancelRedirectLink%253D%252Fen%2526noLoginPrompt%253D1%2526accept%253Dyes&hostname=crawleybc-self.achieveservice.com&withCredentials=true" + + API_URL = "https://crawleybc-self.achieveservice.com/apibroker/" + + currentdate = datetime.now().strftime("%d/%m/%Y") + + data = { + "formValues": { + "Address": { + "address": { + "value": { + "Address": { + "usrn": { + "value": usrn, + }, + "uprn": { + "value": uprn, + }, + } + }, + }, + "dayConverted": { + "value": currentdate, + }, + "getCollection": { + "value": "true", + }, + "getWorksheets": { + "value": "false", + }, + }, + }, + } + + headers = { + "Content-Type": "application/json", + "Accept": "application/json", + "User-Agent": "Mozilla/5.0", + "X-Requested-With": "XMLHttpRequest", + "Referer": "https://crawleybc-self.achieveservice.com/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 = { + "api": "RunLookup", + "id": "5b4f0ec5f13f4", + "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") + + # Extract each service's relevant details for the bin schedule + for key, value in rows_data.items(): + if key.endswith("DateNext"): + BinType = key.replace("DateNext", "Service") + for key2, value2 in rows_data.items(): + if key2 == BinType: + BinType = value2 + next_collection = datetime.strptime(value, "%A %d %B").replace( + year=datetime.now().year + ) + if datetime.now().month == 12 and next_collection.month == 1: + next_collection = next_collection + relativedelta(years=1) + + dict_data = { + "type": BinType, + "collectionDate": next_collection.strftime(date_format), + } + bindata["bins"].append(dict_data) - day = datetime.now().date().strftime("%d") - month = datetime.now().date().strftime("%m") - year = datetime.now().date().strftime("%Y") - - api_url = ( - f"https://my.crawley.gov.uk/appshost/firmstep/self/apps/custompage/waste?language=en&uprn={uprn}" - f"&usrn={usrn}&day={day}&month={month}&year={year}" - ) - response = requests.get(api_url) - - soup = BeautifulSoup(response.text, features="html.parser") - soup.prettify() - - data = {"bins": []} - - titles = [title.text for title in soup.select(".block-title")] - collection_tag = soup.body.find_all( - "div", {"class": "col-md-6 col-sm-6 col-xs-6"}, string="Next collection" - ) - bin_index = 0 - for tag in collection_tag: - for item in tag.next_elements: - if ( - str(item).startswith('
') - and str(item) != "" - ): - collection_date = datetime.strptime(item.text, "%A %d %B") - next_collection = collection_date.replace(year=datetime.now().year) - if datetime.now().month == 12 and next_collection.month == 1: - next_collection = next_collection + relativedelta(years=1) - - dict_data = { - "type": titles[bin_index].strip(), - "collectionDate": next_collection.strftime(date_format), - } - data["bins"].append(dict_data) - bin_index += 1 - break - return data + return bindata From bb78d6dd84685d07031e6f1e11756c48fba76ac1 Mon Sep 17 00:00:00 2001 From: m26dvd <31007572+m26dvd@users.noreply.github.com> Date: Thu, 14 Nov 2024 23:00:39 +0000 Subject: [PATCH 3/9] feat: Adding Rother District Council fix: #1009 --- uk_bin_collection/tests/input.json | 6 ++ .../councils/RotherDistrictCouncil.py | 84 +++++++++++++++++++ wiki/Councils.md | 22 ++++- 3 files changed, 108 insertions(+), 4 deletions(-) create mode 100644 uk_bin_collection/uk_bin_collection/councils/RotherDistrictCouncil.py diff --git a/uk_bin_collection/tests/input.json b/uk_bin_collection/tests/input.json index d349352c3f..ba127b7d9a 100644 --- a/uk_bin_collection/tests/input.json +++ b/uk_bin_collection/tests/input.json @@ -1305,6 +1305,12 @@ "wiki_name": "Rochford Council", "wiki_note": "No extra parameters are required. Dates presented should be read as 'week commencing'." }, + "RotherDistrictCouncil": { + "uprn": "100061937338", + "url": "https://www.rother.gov.uk", + "wiki_name": "Rother District Council", + "wiki_note": "Use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find your UPRN." + }, "RotherhamCouncil": { "url": "https://www.rotherham.gov.uk/bin-collections?address=100050866000&submit=Submit", "uprn": "100050866000", diff --git a/uk_bin_collection/uk_bin_collection/councils/RotherDistrictCouncil.py b/uk_bin_collection/uk_bin_collection/councils/RotherDistrictCouncil.py new file mode 100644 index 0000000000..6ece3b315e --- /dev/null +++ b/uk_bin_collection/uk_bin_collection/councils/RotherDistrictCouncil.py @@ -0,0 +1,84 @@ +from datetime import datetime + +import requests +from bs4 import BeautifulSoup +from dateutil.relativedelta import relativedelta + +from uk_bin_collection.uk_bin_collection.common import * +from uk_bin_collection.uk_bin_collection.get_bin_data import AbstractGetBinDataClass + + +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: + # Get and check UPRN + user_uprn = kwargs.get("uprn") + check_uprn(user_uprn) + bindata = {"bins": []} + + uri = "https://www.rother.gov.uk/wp-admin/admin-ajax.php" + params = { + "action": "get_address_data", + "uprn": "100061937338", + "context": "full-page", + } + + headers = { + "Content-Type": "application/x-www-form-urlencoded", + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36", + } + + # Send a POST request with form data and headers + r = requests.post(uri, data=params, headers=headers, verify=False) + + result = r.json() + + if result["success"]: + # Parse the HTML with BeautifulSoup + soup = BeautifulSoup(result["data"], "html.parser") + soup.prettify() + + # print(soup) + + # Find the div elements with class "bindays-item" + bin_days = soup.find_all("div", class_="bindays-item") + + # Loop through each bin item and extract type and date + for bin_day in bin_days: + # Extract bin type from the

tag + bin_type = bin_day.find("h3").get_text(strip=True).replace(":", "") + + # Extract date (or check if it's a subscription link for Garden Waste) + date_span = bin_day.find("span", class_="find-my-nearest-bindays-date") + if date_span: + if date_span.find("a"): + # If there is a link, this is the Garden bin signup link + continue + else: + # Otherwise, get the date text directly + date = date_span.get_text(strip=True) + else: + date = None + + date = datetime.strptime( + remove_ordinal_indicator_from_date_string(date), + "%A %d %B", + ).replace(year=datetime.now().year) + if datetime.now().month == 12 and date.month == 1: + date = date + relativedelta(years=1) + + 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"), "%d/%m/%Y") + ) + return bindata diff --git a/wiki/Councils.md b/wiki/Councils.md index 9508f147fe..8bbcce931a 100644 --- a/wiki/Councils.md +++ b/wiki/Councils.md @@ -176,6 +176,7 @@ This document is still a work in progress, don't worry if your council isn't lis - [Rhondda Cynon Taff Council](#rhondda-cynon-taff-council) - [Rochdale Council](#rochdale-council) - [Rochford Council](#rochford-council) +- [Rother District Council](#rother-district-council) - [Rotherham Council](#rotherham-council) - [Rugby Borough Council](#rugby-borough-council) - [Rushcliffe Borough Council](#rushcliffe-borough-council) @@ -372,13 +373,14 @@ Note: To get the UPRN, please use [FindMyAddress](https://www.findmyaddress.co.u ### Babergh District Council ```commandline -python collect_data.py BaberghDistrictCouncil https://www.babergh.gov.uk -s -n XX +python collect_data.py BaberghDistrictCouncil https://www.babergh.gov.uk -s -p "XXXX XXX" -n XX ``` Additional parameters: - `-s` - skip get URL +- `-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 +Note: Use the House Number field to pass the DAY of the week for your collections. Monday/Tuesday/Wednesday/Thursday/Friday. [OPTIONAL] Use the 'postcode' field to pass the WEEK for your garden collection. [Week 1/Week 2] --- @@ -1798,13 +1800,14 @@ Note: Pass the house name/number wrapped in double quotes along with the postcod ### Mid Suffolk District Council ```commandline -python collect_data.py MidSuffolkDistrictCouncil https://www.midsuffolk.gov.uk -s -n XX +python collect_data.py MidSuffolkDistrictCouncil https://www.midsuffolk.gov.uk -s -p "XXXX XXX" -n XX ``` Additional parameters: - `-s` - skip get URL +- `-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 +Note: Use the House Number field to pass the DAY of the week for your collections. Monday/Tuesday/Wednesday/Thursday/Friday. [OPTIONAL] Use the 'postcode' field to pass the WEEK for your garden collection. [Week 1/Week 2] --- @@ -2262,6 +2265,17 @@ Note: No extra parameters are required. Dates presented should be read as 'week --- +### Rother District Council +```commandline +python collect_data.py RotherDistrictCouncil https://www.rother.gov.uk -u XXXXXXXX +``` +Additional parameters: +- `-u` - UPRN + +Note: Use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find your UPRN. + +--- + ### Rotherham Council ```commandline python collect_data.py RotherhamCouncil https://www.rotherham.gov.uk/bin-collections?address=XXXXXXXXX&submit=Submit -u XXXXXXXX From c80b13ec37411a95941cb4df183c5ac04aad446a Mon Sep 17 00:00:00 2001 From: m26dvd <31007572+m26dvd@users.noreply.github.com> Date: Thu, 14 Nov 2024 23:12:50 +0000 Subject: [PATCH 4/9] fix: Rother District Council --- .../uk_bin_collection/councils/RotherDistrictCouncil.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uk_bin_collection/uk_bin_collection/councils/RotherDistrictCouncil.py b/uk_bin_collection/uk_bin_collection/councils/RotherDistrictCouncil.py index 6ece3b315e..60f3fa3d91 100644 --- a/uk_bin_collection/uk_bin_collection/councils/RotherDistrictCouncil.py +++ b/uk_bin_collection/uk_bin_collection/councils/RotherDistrictCouncil.py @@ -24,7 +24,7 @@ def parse_data(self, page: str, **kwargs) -> dict: uri = "https://www.rother.gov.uk/wp-admin/admin-ajax.php" params = { "action": "get_address_data", - "uprn": "100061937338", + "uprn": user_uprn, "context": "full-page", } From 02adfba1eb2b674f8fd723b3637158464d2007e0 Mon Sep 17 00:00:00 2001 From: m26dvd <31007572+m26dvd@users.noreply.github.com> Date: Thu, 14 Nov 2024 23:42:43 +0000 Subject: [PATCH 5/9] feat: Adding South Hams District Council fix: #1008 --- uk_bin_collection/tests/input.json | 6 ++ .../councils/SouthHamsDistrictCouncil.py | 90 +++++++++++++++++++ wiki/Councils.md | 24 +++++ 3 files changed, 120 insertions(+) create mode 100644 uk_bin_collection/uk_bin_collection/councils/SouthHamsDistrictCouncil.py diff --git a/uk_bin_collection/tests/input.json b/uk_bin_collection/tests/input.json index 383e62d43e..4cf8629deb 100644 --- a/uk_bin_collection/tests/input.json +++ b/uk_bin_collection/tests/input.json @@ -1420,6 +1420,12 @@ "wiki_name": "South Gloucestershire Council", "wiki_note": "Provide your UPRN. You can find it using [FindMyAddress](https://www.findmyaddress.co.uk/search)." }, + "SouthHamsDistrictCouncil": { + "uprn": "10004742851", + "url": "https://www.southhams.gov.uk", + "wiki_name": "South Hams District Council", + "wiki_note": "Use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find your UPRN." + }, "SouthKestevenDistrictCouncil": { "house_number": "2 Althorpe Close, Market Deeping, PE6 8BL", "postcode": "PE68BL", diff --git a/uk_bin_collection/uk_bin_collection/councils/SouthHamsDistrictCouncil.py b/uk_bin_collection/uk_bin_collection/councils/SouthHamsDistrictCouncil.py new file mode 100644 index 0000000000..0e933c4463 --- /dev/null +++ b/uk_bin_collection/uk_bin_collection/councils/SouthHamsDistrictCouncil.py @@ -0,0 +1,90 @@ +from datetime import datetime + +import requests +from bs4 import BeautifulSoup +from dateutil.relativedelta import relativedelta + +from uk_bin_collection.uk_bin_collection.common import * +from uk_bin_collection.uk_bin_collection.get_bin_data import AbstractGetBinDataClass + + +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: + # Get and check UPRN + user_uprn = kwargs.get("uprn") + check_uprn(user_uprn) + bindata = {"bins": []} + + uri = "https://waste.southhams.gov.uk/mycollections" + + s = requests.session() + r = s.get(uri) + for cookie in r.cookies: + if cookie.name == "fcc_session_cookie": + fcc_session_token = cookie.value + + uri = "https://waste.southhams.gov.uk/mycollections/getcollectiondetails" + + params = { + "fcc_session_token": fcc_session_token, + "uprn": user_uprn, + } + + headers = { + "Content-Type": "application/x-www-form-urlencoded", + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36", + "Referer": "https://waste.southhams.gov.uk/mycollections", + "X-Requested-With": "XMLHttpRequest", + } + + # Send a POST request with form data and headers + r = s.post(uri, data=params, headers=headers) + + result = r.json() + + for collection in result["binCollections"]["tile"]: + + # Parse the HTML with BeautifulSoup + soup = BeautifulSoup(collection[0], "html.parser") + soup.prettify() + + # Find all collectionDiv elements + collections = soup.find_all("div", class_="collectionDiv") + + # Process each collectionDiv + for collection in collections: + # Extract the service name + service_name = collection.find("h3").text.strip() + + # Extract collection frequency and day + details = collection.find("div", class_="detWrap").text.strip() + + # Extract the next collection date + next_collection = details.split("Your next scheduled collection is ")[ + 1 + ].split(".")[0] + + if next_collection.startswith("today"): + next_collection = next_collection.split("today, ")[1] + elif next_collection.startswith("tomorrow"): + next_collection = next_collection.split("tomorrow, ")[1] + + dict_data = { + "type": service_name, + "collectionDate": datetime.strptime( + next_collection, "%A, %d %B %Y" + ).strftime(date_format), + } + 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 8bbcce931a..34a6acdee2 100644 --- a/wiki/Councils.md +++ b/wiki/Councils.md @@ -192,11 +192,13 @@ This document is still a work in progress, don't worry if your council isn't lis - [South Cambridgeshire Council](#south-cambridgeshire-council) - [South Derbyshire District Council](#south-derbyshire-district-council) - [South Gloucestershire Council](#south-gloucestershire-council) +- [South Hams District Council](#south-hams-district-council) - [South Kesteven District Council](#south-kesteven-district-council) - [South Lanarkshire Council](#south-lanarkshire-council) - [South Norfolk Council](#south-norfolk-council) - [South Oxfordshire Council](#south-oxfordshire-council) - [South Ribble Council](#south-ribble-council) +- [South Staffordshire District Council](#south-staffordshire-district-council) - [South Tyneside Council](#south-tyneside-council) - [Southwark Council](#southwark-council) - [St Albans City and District Council](#st-albans-city-and-district-council) @@ -2450,6 +2452,17 @@ Note: Provide your UPRN. You can find it using [FindMyAddress](https://www.findm --- +### South Hams District Council +```commandline +python collect_data.py SouthHamsDistrictCouncil https://www.southhams.gov.uk -u XXXXXXXX +``` +Additional parameters: +- `-u` - UPRN + +Note: Use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find your UPRN. + +--- + ### South Kesteven District Council ```commandline python collect_data.py SouthKestevenDistrictCouncil https://pre.southkesteven.gov.uk/BinSearch.aspx -s -p "XXXX XXX" -n XX -w http://HOST:PORT/ @@ -2508,6 +2521,17 @@ Note: You will need to use [FindMyAddress](https://www.findmyaddress.co.uk/searc --- +### South Staffordshire District Council +```commandline +python collect_data.py SouthStaffordshireDistrictCouncil https://www.sstaffs.gov.uk/where-i-live?uprn=200004523954 -u XXXXXXXX +``` +Additional parameters: +- `-u` - UPRN + +Note: The URL needs to be `https://www.sstaffs.gov.uk/where-i-live?uprn=`. Replace `` with your UPRN. + +--- + ### South Tyneside Council ```commandline python collect_data.py SouthTynesideCouncil https://www.southtyneside.gov.uk/article/33352/Bin-collection-dates -s -p "XXXX XXX" -n XX From 1430fd8c0cc94e6eb090a4b440d7842261d0d5ca Mon Sep 17 00:00:00 2001 From: m26dvd <31007572+m26dvd@users.noreply.github.com> Date: Thu, 14 Nov 2024 23:55:43 +0000 Subject: [PATCH 6/9] feat: Adding Copeland Borough Council fix: #1006 --- uk_bin_collection/tests/input.json | 6 ++ .../councils/CopelandBoroughCouncil.py | 93 +++++++++++++++++++ wiki/Councils.md | 12 +++ 3 files changed, 111 insertions(+) create mode 100644 uk_bin_collection/uk_bin_collection/councils/CopelandBoroughCouncil.py diff --git a/uk_bin_collection/tests/input.json b/uk_bin_collection/tests/input.json index 4cf8629deb..48fbf06839 100644 --- a/uk_bin_collection/tests/input.json +++ b/uk_bin_collection/tests/input.json @@ -398,6 +398,12 @@ "wiki_name": "Conwy County Borough Council", "wiki_note": "Conwy County Borough Council uses a straight UPRN in the URL, e.g., `&uprn=XXXXXXXXXXXXX`." }, + "CopelandBoroughCouncil": { + "uprn": "100110734613", + "url": "https://www.copeland.gov.uk", + "wiki_name": "Copeland Borough Council", + "wiki_note": "Use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find your UPRN." + }, "CornwallCouncil": { "skip_get_url": true, "uprn": "100040128734", diff --git a/uk_bin_collection/uk_bin_collection/councils/CopelandBoroughCouncil.py b/uk_bin_collection/uk_bin_collection/councils/CopelandBoroughCouncil.py new file mode 100644 index 0000000000..521a73948f --- /dev/null +++ b/uk_bin_collection/uk_bin_collection/councils/CopelandBoroughCouncil.py @@ -0,0 +1,93 @@ +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 + + +class CouncilClass(AbstractGetBinDataClass): + """ + Concrete classes have to implement all abstract operations of the + baseclass. They can also override some + operations with a default implementation. + """ + + def parse_data(self, page: str, **kwargs) -> dict: + uprn = kwargs.get("uprn") + check_uprn(uprn) + council = "CPL" + + # Make SOAP request + headers = { + "Content-Type": "text/xml; charset=UTF-8", + "Referer": "https://collections-copeland.azurewebsites.net/calendar.html", + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36", + } + requests.packages.urllib3.disable_warnings() + post_data = ( + '' + '' + '' + "" + council + "" + uprn + "" + "Chtml" + ) + response = requests.post( + "https://collections-copeland.azurewebsites.net/WSCollExternal.asmx", + headers=headers, + data=post_data, + ) + + if response.status_code != 200: + raise ValueError("No bin data found for provided UPRN.") + + # Get HTML from SOAP response + xmltree = ElementTree.fromstring(response.text) + html = xmltree.find( + ".//{http://webaspx-collections.azurewebsites.net/}getRoundCalendarForUPRNResult" + ).text + # Parse with BS4 + soup = BeautifulSoup(html, features="html.parser") + soup.prettify() + + data = {"bins": []} + for bin_type in ["Refuse", "Recycling", "Garden"]: + bin_el = soup.find("b", string=bin_type) + if bin_el: + bin_info = bin_el.next_sibling.split(": ")[1] + collection_date = "" + results = re.search("([A-Za-z]+ \\d\\d? [A-Za-z]+) then", bin_info) + if results: + if results[1] == "Today": + date = datetime.now() + elif results[1] == "Tomorrow": + date = datetime.now() + timedelta(days=1) + else: + date = get_next_occurrence_from_day_month( + datetime.strptime( + results[1] + " " + datetime.now().strftime("%Y"), + "%a %d %b %Y", + ) + ) + if date: + collection_date = date.strftime(date_format) + else: + results2 = re.search("([A-Za-z]+) then", bin_info) + if results2: + if results2[1] == "Today": + collection_date = datetime.now().strftime(date_format) + elif results2[1] == "Tomorrow": + collection_date = ( + datetime.now() + timedelta(days=1) + ).strftime(date_format) + else: + collection_date = results2[1] + + if collection_date != "": + dict_data = { + "type": bin_type, + "collectionDate": collection_date, + } + data["bins"].append(dict_data) + + return data diff --git a/wiki/Councils.md b/wiki/Councils.md index 34a6acdee2..75b5beeda9 100644 --- a/wiki/Councils.md +++ b/wiki/Councils.md @@ -61,6 +61,7 @@ This document is still a work in progress, don't worry if your council isn't lis - [Chorley Council](#chorley-council) - [Colchester City Council](#colchester-city-council) - [Conwy County Borough Council](#conwy-county-borough-council) +- [Copeland Borough Council](#copeland-borough-council) - [Cornwall Council](#cornwall-council) - [Coventry City Council](#coventry-city-council) - [Cotswold District Council](#cotswold-district-council) @@ -884,6 +885,17 @@ Note: Conwy County Borough Council uses a straight UPRN in the URL, e.g., `&uprn --- +### Copeland Borough Council +```commandline +python collect_data.py CopelandBoroughCouncil https://www.copeland.gov.uk -u XXXXXXXX +``` +Additional parameters: +- `-u` - UPRN + +Note: Use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find your UPRN. + +--- + ### Cornwall Council ```commandline python collect_data.py CornwallCouncil https://www.cornwall.gov.uk/my-area/ -s -u XXXXXXXX From 3603117ae5c986e9ba87633ea344583d3959c120 Mon Sep 17 00:00:00 2001 From: m26dvd <31007572+m26dvd@users.noreply.github.com> Date: Fri, 15 Nov 2024 00:06:11 +0000 Subject: [PATCH 7/9] feat: Adding Thanet District Council fix: #1004 --- uk_bin_collection/tests/input.json | 6 +++ .../councils/ThanetDistrictCouncil.py | 51 +++++++++++++++++++ wiki/Councils.md | 12 +++++ 3 files changed, 69 insertions(+) create mode 100644 uk_bin_collection/uk_bin_collection/councils/ThanetDistrictCouncil.py diff --git a/uk_bin_collection/tests/input.json b/uk_bin_collection/tests/input.json index 48fbf06839..5f50dd8439 100644 --- a/uk_bin_collection/tests/input.json +++ b/uk_bin_collection/tests/input.json @@ -1650,6 +1650,12 @@ "wiki_name": "Test Valley Borough Council", "wiki_note": "Provide your UPRN and postcode. Use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find your UPRN." }, + "ThanetDistrictCouncil": { + "uprn": "100061111858", + "url": "https://www.thanet.gov.uk", + "wiki_name": "Thanet District Council", + "wiki_note": "Use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find your UPRN." + }, "ThreeRiversDistrictCouncil": { "postcode": "WD3 7AZ", "skip_get_url": true, diff --git a/uk_bin_collection/uk_bin_collection/councils/ThanetDistrictCouncil.py b/uk_bin_collection/uk_bin_collection/councils/ThanetDistrictCouncil.py new file mode 100644 index 0000000000..cbad92c44f --- /dev/null +++ b/uk_bin_collection/uk_bin_collection/councils/ThanetDistrictCouncil.py @@ -0,0 +1,51 @@ +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": []} + + URI = f"https://www.thanet.gov.uk/wp-content/mu-plugins/collection-day/incl/mu-collection-day-calls.php?pAddress={user_uprn}" + + headers = { + "x-requested-with": "XMLHttpRequest", + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36", + } + + # Make the GET request + response = requests.get(URI, headers=headers) + + # Parse the JSON response + bin_collection = response.json() + + # Loop through each collection in bin_collection + for collection in bin_collection: + bin_type = collection["type"] + collection_date = collection["nextDate"].split(" ")[0] + + dict_data = { + "type": bin_type, + "collectionDate": 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 75b5beeda9..bde58fb782 100644 --- a/wiki/Councils.md +++ b/wiki/Councils.md @@ -221,6 +221,7 @@ This document is still a work in progress, don't worry if your council isn't lis - [Telford and Wrekin Council](#telford-and-wrekin-council) - [Tendring District Council](#tendring-district-council) - [Test Valley Borough Council](#test-valley-borough-council) +- [Thanet District Council](#thanet-district-council) - [Three Rivers District Council](#three-rivers-district-council) - [Tonbridge and Malling Borough Council](#tonbridge-and-malling-borough-council) - [Torbay Council](#torbay-council) @@ -2800,6 +2801,17 @@ Note: Provide your UPRN and postcode. Use [FindMyAddress](https://www.findmyaddr --- +### Thanet District Council +```commandline +python collect_data.py ThanetDistrictCouncil https://www.thanet.gov.uk -u XXXXXXXX +``` +Additional parameters: +- `-u` - UPRN + +Note: Use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find your UPRN. + +--- + ### Three Rivers District Council ```commandline python collect_data.py ThreeRiversDistrictCouncil https://my.threerivers.gov.uk/en/AchieveForms/?mode=fill&consentMessage=yes&form_uri=sandbox-publish://AF-Process-52df96e3-992a-4b39-bba3-06cfaabcb42b/AF-Stage-01ee28aa-1584-442c-8d1f-119b6e27114a/definition.json&process=1&process_uri=sandbox-processes://AF-Process-52df96e3-992a-4b39-bba3-06cfaabcb42b&process_id=AF-Process-52df96e3-992a-4b39-bba3-06cfaabcb42b&noLoginPrompt=1 -s -u XXXXXXXX -p "XXXX XXX" -w http://HOST:PORT/ From 17cd12b093cb5fea56edda106bb53c08d59ebc48 Mon Sep 17 00:00:00 2001 From: m26dvd <31007572+m26dvd@users.noreply.github.com> Date: Fri, 15 Nov 2024 00:48:21 +0000 Subject: [PATCH 8/9] feat: Adding Stevenage Borough Council fix: #989 --- uk_bin_collection/tests/input.json | 6 ++ .../councils/StevenageBoroughCouncil.py | 101 ++++++++++++++++++ wiki/Councils.md | 12 +++ 3 files changed, 119 insertions(+) create mode 100644 uk_bin_collection/uk_bin_collection/councils/StevenageBoroughCouncil.py diff --git a/uk_bin_collection/tests/input.json b/uk_bin_collection/tests/input.json index 5f50dd8439..ce5bc0a29f 100644 --- a/uk_bin_collection/tests/input.json +++ b/uk_bin_collection/tests/input.json @@ -1496,6 +1496,12 @@ "wiki_name": "St Albans City and District Council", "wiki_note": "Provide your UPRN. You can find it using [FindMyAddress](https://www.findmyaddress.co.uk/search)." }, + "StevenageBoroughCouncil": { + "uprn": "100080878852", + "url": "https://www.stevenage.gov.uk", + "wiki_name": "Stevenage Borough Council", + "wiki_note": "Use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find your UPRN." + }, "StHelensBC": { "house_number": "15", "postcode": "L34 2GA", diff --git a/uk_bin_collection/uk_bin_collection/councils/StevenageBoroughCouncil.py b/uk_bin_collection/uk_bin_collection/councils/StevenageBoroughCouncil.py new file mode 100644 index 0000000000..c9dda087c4 --- /dev/null +++ b/uk_bin_collection/uk_bin_collection/councils/StevenageBoroughCouncil.py @@ -0,0 +1,101 @@ +import time + +import requests +from dateutil.relativedelta import relativedelta + +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: + # Make a BS4 object + uprn = kwargs.get("uprn") + check_uprn(uprn) + bindata = {"bins": []} + + SESSION_URL = "https://stevenage-self.achieveservice.com/authapi/isauthenticated?uri=https%253A%252F%252Fstevenage-self.achieveservice.com%252Fservice%252Fmy_bin_collection_schedule&hostname=stevenage-self.achieveservice.com&withCredentials=true" + TOKEN_URL = "https://stevenage-self.achieveservice.com/apibroker/runLookup?id=5e55337a540d4" + API_URL = "https://stevenage-self.achieveservice.com/apibroker/runLookup" + + data = { + "formValues": { + "Section 1": { + "token": {"value": ""}, + "LLPGUPRN": { + "value": uprn, + }, + "MinimumDateLookAhead": { + "value": time.strftime("%Y-%m-%d"), + }, + "MaximumDateLookAhead": { + "value": str(int(time.strftime("%Y")) + 1) + + time.strftime("-%m-%d"), + }, + }, + }, + } + + headers = { + "Content-Type": "application/json", + "Accept": "application/json", + "User-Agent": "Mozilla/5.0", + "X-Requested-With": "XMLHttpRequest", + "Referer": "https://stevenage-self.achieveservice.com/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"] + + t = s.get(TOKEN_URL) + t.raise_for_status() + token_data = t.json() + data["formValues"]["Section 1"]["token"]["value"] = token_data["integration"][ + "transformed" + ]["rows_data"]["0"]["token"] + + params = { + "id": "64ba8cee353e6", + "repeat_against": "", + "noRetry": "false", + "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"] + if not isinstance(rows_data, dict): + raise ValueError("Invalid data returned from API") + + for key in rows_data: + value = rows_data[key] + bin_type = value["bintype"].strip() + + try: + date = datetime.strptime(value["collectiondate"], "%A %d %B %Y").date() + except ValueError: + continue + + dict_data = { + "type": bin_type, + "collectionDate": date.strftime(date_format), + } + bindata["bins"].append(dict_data) + + return bindata diff --git a/wiki/Councils.md b/wiki/Councils.md index bde58fb782..af69f6046f 100644 --- a/wiki/Councils.md +++ b/wiki/Councils.md @@ -203,6 +203,7 @@ 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) @@ -2581,6 +2582,17 @@ 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/ From db3c6be2c1cbee3f460243de231940cac0ae4436 Mon Sep 17 00:00:00 2001 From: m26dvd <31007572+m26dvd@users.noreply.github.com> Date: Fri, 15 Nov 2024 01:03:35 +0000 Subject: [PATCH 9/9] feat: Adding Wolverhampton City Council fix: #966 --- uk_bin_collection/tests/input.json | 7 +++ .../councils/WolverhamptonCityCouncil.py | 57 +++++++++++++++++++ wiki/Councils.md | 13 +++++ 3 files changed, 77 insertions(+) create mode 100644 uk_bin_collection/uk_bin_collection/councils/WolverhamptonCityCouncil.py diff --git a/uk_bin_collection/tests/input.json b/uk_bin_collection/tests/input.json index ce5bc0a29f..fa1afb7fad 100644 --- a/uk_bin_collection/tests/input.json +++ b/uk_bin_collection/tests/input.json @@ -1929,6 +1929,13 @@ "wiki_name": "Worcester City Council", "wiki_note": "Provide your UPRN. You can find it using [FindMyAddress](https://www.findmyaddress.co.uk/search)." }, + "WolverhamptonCityCouncil": { + "uprn": "100071205205", + "postcode": "WV3 9NZ", + "url": "https://www.wolverhampton.gov.uk", + "wiki_name": "Wolverhampton City Council", + "wiki_note": "Use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find your UPRN." + }, "WorcesterCityCouncil": { "url": "https://www.Worcester.gov.uk", "wiki_command_url_override": "https://www.Worcester.gov.uk", diff --git a/uk_bin_collection/uk_bin_collection/councils/WolverhamptonCityCouncil.py b/uk_bin_collection/uk_bin_collection/councils/WolverhamptonCityCouncil.py new file mode 100644 index 0000000000..15041d9ca3 --- /dev/null +++ b/uk_bin_collection/uk_bin_collection/councils/WolverhamptonCityCouncil.py @@ -0,0 +1,57 @@ +import time + +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") + user_postcode = kwargs.get("postcode") + check_uprn(user_uprn) + check_postcode(user_postcode) + bindata = {"bins": []} + + user_postcode = user_postcode.replace(" ", "%20") + + URI = f"https://www.wolverhampton.gov.uk/find-my-nearest/{user_postcode}/{user_uprn}" + + # Make the GET request + response = requests.get(URI) + + soup = BeautifulSoup(response.content, "html.parser") + + jumbotron = soup.find("div", {"class": "jumbotron jumbotron-fluid"}) + + # Find all bin entries in the row + for bin_div in jumbotron.select("div.col-md-4"): + service_name = bin_div.h3.text.strip() + next_date = bin_div.find( + "h4", text=lambda x: x and "Next date" in x + ).text.split(": ")[1] + + dict_data = { + "type": service_name, + "collectionDate": datetime.strptime( + next_date, + "%B %d, %Y", + ).strftime(date_format), + } + 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 af69f6046f..3f6919219c 100644 --- a/wiki/Councils.md +++ b/wiki/Councils.md @@ -256,6 +256,7 @@ This document is still a work in progress, don't worry if your council isn't lis - [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) - [Wychavon District Council](#wychavon-district-council) - [Wyre Council](#wyre-council) - [York Council](#york-council) @@ -3236,6 +3237,18 @@ Note: You will need to use [FindMyAddress](https://www.findmyaddress.co.uk/searc --- +### Wolverhampton City Council +```commandline +python collect_data.py WolverhamptonCityCouncil https://www.wolverhampton.gov.uk -u XXXXXXXX -p "XXXX XXX" +``` +Additional parameters: +- `-u` - UPRN +- `-p` - postcode + +Note: Use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find your UPRN. + +--- + ### Wychavon District Council ```commandline python collect_data.py WychavonDistrictCouncil https://selfservice.wychavon.gov.uk/wdcroundlookup/wdc_search.jsp -s -u XXXXXXXX -p "XXXX XXX" -w http://HOST:PORT/