Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

2025 Council Pack 1 #1132

Merged
merged 16 commits into from
Jan 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 47 additions & 6 deletions uk_bin_collection/tests/input.json
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,13 @@
"wiki_name": "Breckland Council",
"wiki_note": "You will need to use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find the UPRN."
},
"BrentCouncil": {
"house_number": "25",
"postcode": "HA3 0QU",
"url": "https://recyclingservices.brent.gov.uk/waste",
"wiki_name": "Brent Council",
"wiki_note": "Pass the house number and postcode in their respective parameters."
},
"BrightonandHoveCityCouncil": {
"house_number": "44 Carden Avenue, Brighton, BN1 8NE",
"postcode": "BN1 8NE",
Expand Down Expand Up @@ -440,7 +447,7 @@
"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."
"wiki_note": "*****This has now been replaced by Cumberland Council****"
},
"CornwallCouncil": {
"skip_get_url": true,
Expand Down Expand Up @@ -486,6 +493,12 @@
"wiki_name": "Croydon Council",
"wiki_note": "Pass the house number and postcode in their respective parameters."
},
"CumberlandCouncil": {
"uprn": "100110734613",
"url": "https://waste.cumberland.gov.uk",
"wiki_name": "Cumberland Borough Council",
"wiki_note": "Use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find your UPRN."
},
"CumberlandAllerdaleCouncil": {
"house_number": "2",
"postcode": "CA13 0DE",
Expand All @@ -508,6 +521,12 @@
"wiki_name": "Dartford Borough Council",
"wiki_note": "Use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find your UPRN."
},
"DenbighshireCouncil": {
"url": "https://www.denbighshire.gov.uk/",
"uprn": "200004299351",
"wiki_name": "Denbighshire Council",
"wiki_note": "You will need to use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find the UPRN."
},
"DerbyCityCouncil": {
"url": "https://www.derby.gov.uk",
"uprn": "10010684240",
Expand Down Expand Up @@ -550,6 +569,12 @@
"wiki_name": "Dudley Council",
"wiki_note": "You will need to use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find the UPRN."
},
"DundeeCityCouncil": {
"url": "https://www.dundeecity.gov.uk/",
"uprn": "9059043390",
"wiki_name": "Dundee City Council",
"wiki_note": "You will need to use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find the UPRN."
},
"DurhamCouncil": {
"skip_get_url": true,
"uprn": "200003218818",
Expand Down Expand Up @@ -805,6 +830,12 @@
"wiki_name": "Guildford Council",
"wiki_note": "If the bin day is 'today' then the collectionDate will only show today's date if before 7 AM; else the date will be in 'previousCollectionDate'. To get the UPRN, you will need to use [FindMyAddress](https://www.findmyaddress.co.uk/search)."
},
"GwyneddCouncil": {
"url": "https://diogel.gwynedd.llyw.cymru",
"uprn": "10070350463",
"wiki_name": "Gwynedd Council",
"wiki_note": "You will need to use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find the UPRN."
},
"HackneyCouncil": {
"house_number": "101",
"postcode": "N16 9AS",
Expand Down Expand Up @@ -936,13 +967,11 @@
"wiki_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."
},
"KirkleesCouncil": {
"house_number": "24",
"postcode": "HD7 5DX",
"uprn": "83002937",
"skip_get_url": true,
"url": "https://www.kirklees.gov.uk/beta/your-property-bins-recycling/your-bins",
"web_driver": "http://selenium:4444",
"wiki_name": "Kirklees Council",
"wiki_note": "Pass the house number and postcode in their respective parameters. This parser requires a Selenium webdriver."
"wiki_note": "Provide your UPRN. Find your UPRN using [FindMyAddress](https://www.findmyaddress.co.uk/search)."
},
"KnowsleyMBCouncil": {
"house_number": "22",
Expand Down Expand Up @@ -1325,7 +1354,7 @@
"house_number": "22",
"postcode": "NE46 1UQ",
"skip_get_url": true,
"url": "https://www.northumberland.gov.uk/Waste/Bins/Bin-Calendars.aspx",
"url": "https://www.northumberland.gov.uk/Waste/Household-waste/Household-bin-collections/Bin-Calendars.aspx",
"web_driver": "http://selenium:4444",
"wiki_name": "Northumberland Council",
"wiki_note": "Pass the house number and postcode in their respective parameters. This parser requires a Selenium webdriver."
Expand All @@ -1344,6 +1373,12 @@
"house_number": "Newdigate Road",
"wiki_note": "Pass the name of the street ONLY in the house number parameter, wrapped in double quotes. Street name must match exactly as it appears on the council's website."
},
"OadbyAndWigstonBoroughCouncil": {
"url": "https://my.oadby-wigston.gov.uk",
"uprn": "10010149102",
"wiki_name": "Oadby & Wigston Borough Council",
"wiki_note": "You will need to use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find the UPRN."
},
"OldhamCouncil": {
"url": "https://portal.oldham.gov.uk/bincollectiondates/details?uprn=422000033556",
"wiki_name": "Oldham Council",
Expand Down Expand Up @@ -1985,6 +2020,12 @@
"wiki_name": "West Berkshire Council",
"wiki_note": "Provide your house number in the `house_number` parameter and postcode in the `postcode` parameter."
},
"WestDunbartonshireCouncil": {
"url": "https://www.west-dunbarton.gov.uk/",
"uprn": "129001383",
"wiki_name": "West Dunbartonshire Council",
"wiki_note": "You will need to use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find the UPRN."
},
"WestLancashireBoroughCouncil": {
"url": "https://www.westlancs.gov.uk",
"uprn": "10012343339",
Expand Down
115 changes: 115 additions & 0 deletions uk_bin_collection/uk_bin_collection/councils/BrentCouncil.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
from time import sleep

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:
data = {"bins": []}
user_postcode = kwargs.get("postcode")
user_paon = kwargs.get("paon")
check_postcode(user_postcode)
check_paon(user_paon)

URI = "https://recyclingservices.brent.gov.uk/waste"

payload = {"postcode": user_postcode}

s = requests.Session()

# Make the POST request
response = s.post(URI, data=payload)

# Make a BS4 object
soup = BeautifulSoup(response.content, features="html.parser")

address_list = soup.find_all("option")

current_year = datetime.now().year
next_year = current_year + 1

for address in address_list:
if user_paon in (address.text):
address_id = address.get("value")
URI = f"https://recyclingservices.brent.gov.uk/waste/{address_id}"

counter = 0
r = s.get(URI)
while "Loading your bin days..." in r.text:
counter = counter + 1
if counter == 20:
return data
sleep(2)
r = s.get(URI)

r.raise_for_status()

soup = BeautifulSoup(r.content, features="html.parser")

wastecollections = soup.find("div", {"class": "waste__collections"})

# Find all waste service sections
waste_services = wastecollections.find_all(
"h3", class_="govuk-heading-m waste-service-name"
)

for service in waste_services:
# Get the collection type (e.g., Rubbish, Recycling)
collection_type = (service.get_text(strip=True)).split("\n")[0]

# Find the sibling container holding details
service_details = service.find_next(
"dl", class_="govuk-summary-list"
)

if service_details:

# Extract next collection date
next_collection_row = service_details.find(
"dt", string="Next collection"
)
next_collection = (
next_collection_row.find_next_sibling("dd").get_text(
strip=True
)
if next_collection_row
else "Unknown"
)

# Parse dates into standard dd/mm/yyyy format
next_collection_date = datetime.strptime(
remove_ordinal_indicator_from_date_string(next_collection),
"%A, %d %B",
)

if (datetime.now().month == 12) and (
next_collection.month == 1
):
next_collection_date = next_collection_date.replace(
year=next_year
)
else:
next_collection_date = next_collection_date.replace(
year=current_year
)

dict_data = {
"type": collection_type.strip(),
"collectionDate": next_collection_date.strftime(
date_format
),
}
data["bins"].append(dict_data)

return data
13 changes: 9 additions & 4 deletions uk_bin_collection/uk_bin_collection/councils/CornwallCouncil.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
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
from dateutil.relativedelta import relativedelta


# import the wonderful Beautiful Soup and the URL grabber
Expand Down Expand Up @@ -52,9 +53,13 @@ def parse_data(self, page: str, **kwargs) -> dict:

for item in soup.find_all("div", class_="collection text-center service"):
bin_type = item.contents[1].text + " bin"
collection_date = datetime.strptime(item.contents[5].text, "%d %b").replace(
year=curr_date.year
)
try:
collection_date = datetime.strptime(
item.contents[5].text, "%d %b"
).replace(year=curr_date.year)
except:
continue

if curr_date.month == 12 and collection_date.month == 1:
collection_date = collection_date + relativedelta(years=1)
collections.append((bin_type, collection_date))
Expand Down
96 changes: 96 additions & 0 deletions uk_bin_collection/uk_bin_collection/councils/CumberlandCouncil.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
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 = "https://waste.cumberland.gov.uk/renderform?t=25&k=E43CEB1FB59F859833EF2D52B16F3F4EBE1CAB6A"

s = requests.Session()

# Make the GET request
response = s.get(URI)

# Make a BS4 object
soup = BeautifulSoup(response.content, features="html.parser")

# print(soup)

token = (soup.find("input", {"name": "__RequestVerificationToken"})).get(
"value"
)

formguid = (soup.find("input", {"name": "FormGuid"})).get("value")

# print(token)
# print(formguid)

headers = {
"Content-Type": "application/x-www-form-urlencoded",
"Origin": "https://waste.cumberland.gov.uk",
"Referer": "https://waste.cumberland.gov.uk/renderform?t=25&k=E43CEB1FB59F859833EF2D52B16F3F4EBE1CAB6A",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36 OPR/98.0.0.0",
"X-Requested-With": "XMLHttpRequest",
}

payload = {
"__RequestVerificationToken": token,
"FormGuid": formguid,
"ObjectTemplateID": "25",
"Trigger": "submit",
"CurrentSectionID": "33",
"TriggerCtl": "",
"FF265": f"U{user_uprn}",
"FF265lbltxt": "Please select your address",
}

# print(payload)

response = s.post(
"https://waste.cumberland.gov.uk/renderform/Form",
headers=headers,
data=payload,
)

soup = BeautifulSoup(response.content, features="html.parser")
for row in soup.find_all("div", class_="resirow"):
# Extract the type of collection (e.g., Recycling, Refuse)
collection_type_div = row.find("div", class_="col")
collection_type = (
collection_type_div.get("class")[1]
if collection_type_div
else "Unknown"
)

# Extract the collection date
date_div = row.find("div", style="width:360px;")
collection_date = date_div.text.strip() if date_div else "Unknown"

dict_data = {
"type": collection_type,
"collectionDate": datetime.strptime(
collection_date, "%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
Loading
Loading