Skip to content

Commit

Permalink
Merge pull request #958 from m26dvd/master
Browse files Browse the repository at this point in the history
feat: Council Pack 12
  • Loading branch information
robbrad authored Nov 4, 2024
2 parents 5c544be + ebb8c24 commit 97c3daf
Show file tree
Hide file tree
Showing 8 changed files with 408 additions and 24 deletions.
39 changes: 37 additions & 2 deletions uk_bin_collection/tests/input.json
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,13 @@
"url": "https://www.birmingham.gov.uk/xfp/form/619",
"wiki_name": "Birmingham City Council"
},
"BlabyDistrictCouncil": {
"url": "https://www.blaby.gov.uk",
"wiki_command_url_override": "https://www.blaby.gov.uk",
"uprn": "100030401782",
"wiki_name": "Blaby District Council",
"wiki_note": "You will need to use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find the UPRN."
},
"BlackburnCouncil": {
"skip_get_url": true,
"uprn": "100010733027",
Expand Down Expand Up @@ -189,6 +196,13 @@
"wiki_name": "Bromley Borough Council",
"wiki_note": "Follow the instructions [here](https://recyclingservices.bromley.gov.uk/waste) until the \"Your bin days\" page then copy the URL and replace the URL in the command."
},
"BromsgroveDistrictCouncil": {
"url": "https://www.bromsgrove.gov.uk",
"wiki_command_url_override": "https://www.bromsgrove.gov.uk",
"uprn": "100120584652",
"wiki_name": "Bromsgrove District Council",
"wiki_note": "You will need to use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find the UPRN."
},
"BroxtoweBoroughCouncil": {
"postcode": "NG16 2LY",
"skip_get_url": true,
Expand Down Expand Up @@ -243,6 +257,13 @@
"url": "https://www.cardiff.gov.uk/ENG/resident/Rubbish-and-recycling/When-are-my-bins-collected/Pages/default.aspx",
"wiki_name": "Cardiff Council"
},
"CarmarthenshireCountyCouncil": {
"url": "https://www.carmarthenshire.gov.wales",
"wiki_command_url_override": "https://www.carmarthenshire.gov.wales",
"uprn": "10004859302",
"wiki_name": "Carmarthenshire County Council",
"wiki_note": "You will need to use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find the UPRN."
},
"CastlepointDistrictCouncil": {
"skip_get_url": true,
"uprn": "4525",
Expand Down Expand Up @@ -416,6 +437,13 @@
"url": "https://www.ealing.gov.uk/site/custom_scripts/WasteCollectionWS/home/FindCollection",
"wiki_name": "Ealing Council"
},
"EastAyrshireCouncil": {
"url": "https://www.east-ayrshire.gov.uk",
"wiki_command_url_override": "https://www.east-ayrshire.gov.uk",
"uprn": "127074727",
"wiki_name": "East Ayrshire Council",
"wiki_note": "You will need to use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find the UPRN."
},
"EastCambridgeshireCouncil": {
"skip_get_url": true,
"uprn": "10002597178",
Expand All @@ -436,8 +464,8 @@
"wiki_name": "East Herts Council"
},
"EastLindseyDistrictCouncil": {
"house_number": "Raf Coningsby",
"postcode": "LN4 4SY",
"house_number": "1",
"postcode": "PE22 0YD",
"skip_get_url": true,
"url": "https://www.e-lindsey.gov.uk/",
"web_driver": "http://selenium:4444",
Expand Down Expand Up @@ -1106,6 +1134,13 @@
"url": "https://www.salford.gov.uk/bins-and-recycling/bin-collection-days/your-bin-collections",
"wiki_name": "Salford City Council"
},
"SeftonCouncil": {
"house_number": "1",
"postcode": "L20 6GG",
"url": "https://www.sefton.gov.uk",
"wiki_name": "Sefton Council",
"wiki_note": "Pass the postcode and house number in their respective arguments, both wrapped in quotes."
},
"SevenoaksDistrictCouncil": {
"house_number": "60 Hever Road",
"postcode": "TN15 6EB",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
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://my.blaby.gov.uk/set-location.php?ref={user_uprn}&redirect=collections"

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

# Parse the HTML
soup = BeautifulSoup(response.content, "html.parser")

# Find each collection container based on the class "box-item"
for container in soup.find_all(class_="box-item"):

# Get the next collection dates from the <p> tag containing <strong>
dates_tag = (
container.find("p", string=lambda text: "Next" in text)
.find_next("p")
.find("strong")
)
collection_dates = (
dates_tag.text.strip().split(", and then ")
if dates_tag
else "No dates found"
)

for collection_date in collection_dates:
dict_data = {
"type": container.find("h2").text.strip(),
"collectionDate": collection_date,
}
bindata["bins"].append(dict_data)

bindata["bins"].sort(
key=lambda x: datetime.strptime(x.get("collectionDate"), "%d/%m/%Y")
)

return bindata
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
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://bincollections.bromsgrove.gov.uk/BinCollections/Details?uprn={user_uprn}"

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

# Parse the HTML
soup = BeautifulSoup(response.content, "html.parser")

# Find each collection container
for container in soup.find_all(class_="collection-container"):
# Get the bin type from the heading
bin_type = container.find(class_="heading").text.strip()

# Get the next collection date from the caption
next_collection = (
container.find(class_="caption")
.text.replace("Next collection ", "")
.strip()
)

dict_data = {
"type": bin_type,
"collectionDate": datetime.strptime(
next_collection,
"%A, %d %B %Y",
).strftime("%d/%m/%Y"),
}
bindata["bins"].append(dict_data)

bindata["bins"].sort(
key=lambda x: datetime.strptime(x.get("collectionDate"), "%d/%m/%Y")
)

return bindata
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
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.carmarthenshire.gov.wales/umbraco/Surface/SurfaceRecycling/Index/?uprn={user_uprn}&lang=en-GB"

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

# Parse the HTML
soup = BeautifulSoup(response.content, "html.parser")

# Find each bin collection container
for container in soup.find_all(class_="bin-day-container"):
# Get the bin type based on the class (e.g., Blue, Black, Garden, Nappy)
bin_type = container.get("class")[1] # Second class represents the bin type

# Find the next collection date
date_tag = container.find(class_="font11 text-center")
if date_tag:
collection_date = date_tag.text.strip()
else:
continue

dict_data = {
"type": bin_type,
"collectionDate": datetime.strptime(
collection_date,
"%A %d/%m/%Y",
).strftime("%d/%m/%Y"),
}
bindata["bins"].append(dict_data)

bindata["bins"].sort(
key=lambda x: datetime.strptime(x.get("collectionDate"), "%d/%m/%Y")
)

return bindata
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
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.east-ayrshire.gov.uk/Housing/RubbishAndRecycling/Collection-days/ViewYourRecyclingCalendar.aspx?r={user_uprn}"

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

# Parse the HTML
soup = BeautifulSoup(response.content, "html.parser")

# Find each <time> element in the schedule
for entry in soup.find_all("time"):

dict_data = {
"type": entry.find(class_="ScheduleItem").text.strip(),
"collectionDate": datetime.strptime(
entry["datetime"],
"%Y-%m-%d",
).strftime("%d/%m/%Y"),
}
bindata["bins"].append(dict_data)

bindata["bins"].sort(
key=lambda x: datetime.strptime(x.get("collectionDate"), "%d/%m/%Y")
)

return bindata
Original file line number Diff line number Diff line change
Expand Up @@ -28,22 +28,20 @@ def parse_data(self, page: str, **kwargs) -> dict:

# Create Selenium webdriver
driver = create_webdriver(web_driver, headless, None, __name__)
driver.get(
"https://www.e-lindsey.gov.uk/article/6714/Your-Waste-Collection-Days"
)
driver.get("https://www.e-lindsey.gov.uk/mywastecollections")

# Wait for the postcode field to appear then populate it
inputElement_postcode = WebDriverWait(driver, 30).until(
EC.presence_of_element_located(
(By.ID, "WASTECOLLECTIONDAYS202324_LOOKUP_ADDRESSLOOKUPPOSTCODE")
(By.ID, "WASTECOLLECTIONDAYS202425_LOOKUP_ADDRESSLOOKUPPOSTCODE")
)
)
inputElement_postcode.send_keys(user_postcode)

# Click search button
findAddress = WebDriverWait(driver, 10).until(
EC.presence_of_element_located(
(By.ID, "WASTECOLLECTIONDAYS202324_LOOKUP_ADDRESSLOOKUPSEARCH")
(By.ID, "WASTECOLLECTIONDAYS202425_LOOKUP_ADDRESSLOOKUPSEARCH")
)
)
findAddress.click()
Expand All @@ -53,7 +51,7 @@ def parse_data(self, page: str, **kwargs) -> dict:
EC.element_to_be_clickable(
(
By.XPATH,
"//select[@id='WASTECOLLECTIONDAYS202324_LOOKUP_ADDRESSLOOKUPADDRESS']//option[contains(., '"
"//select[@id='WASTECOLLECTIONDAYS202425_LOOKUP_ADDRESSLOOKUPADDRESS']//option[contains(., '"
+ user_paon
+ "')]",
)
Expand All @@ -63,7 +61,7 @@ def parse_data(self, page: str, **kwargs) -> dict:
# 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, "WASTECOLLECTIONDAYS202324_LOOKUP_FIELD2_NEXT")
(By.ID, "WASTECOLLECTIONDAYS202425_LOOKUP_FIELD2_NEXT")
)
)
submit.click()
Expand All @@ -77,25 +75,25 @@ def parse_data(self, page: str, **kwargs) -> dict:

# Get collections
for collection in soup.find_all("div", {"class": "waste-result"}):
ptags = collection.find_all("p")
dict_data = {
"type": collection.find("h3").get_text(strip=True),
"collectionDate": datetime.strptime(
remove_ordinal_indicator_from_date_string(
ptags[1]
.get_text()
.replace("The date of your next collection is", "")
.replace(".", "")
.strip()
),
"%A %d %B %Y",
).strftime(date_format),
}
data["bins"].append(dict_data)
collection_date = None
for p_tag in collection.find_all("p"):
if "next collection is" in p_tag.text:
collection_date = p_tag.find("strong").text
break
if collection_date:
dict_data = {
"type": collection.find("h3").get_text(strip=True),
"collectionDate": datetime.strptime(
remove_ordinal_indicator_from_date_string(collection_date),
"%A %d %B %Y",
).strftime(date_format),
}
data["bins"].append(dict_data)

data["bins"].sort(
key=lambda x: datetime.strptime(x.get("collectionDate"), "%d/%m/%Y")
)

except Exception as e:
# Here you can log the exception if needed
print(f"An error occurred: {e}")
Expand Down
Loading

0 comments on commit 97c3daf

Please sign in to comment.