Skip to content

Commit

Permalink
Merge pull request #986 from m26dvd/master
Browse files Browse the repository at this point in the history
fix: Council Pack 14
  • Loading branch information
robbrad authored Nov 11, 2024
2 parents 2ff004f + 07fdde6 commit d02a46c
Show file tree
Hide file tree
Showing 8 changed files with 904 additions and 143 deletions.
36 changes: 36 additions & 0 deletions uk_bin_collection/tests/input.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,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."
},
"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",
"wiki_name": "Antrim & Newtonabbey Council",
"wiki_note": "Navigate to [https://antrimandnewtownabbey.gov.uk/residents/bins-recycling/bins-schedule] and search for your street name. Use the URL with the ID to replace XXXXXXXX with your specific ID."
},
"ArdsAndNorthDownCouncil": {
"url": "https://www.ardsandnorthdown.gov.uk",
"wiki_command_url_override": "https://www.ardsandnorthdown.gov.uk",
Expand Down Expand Up @@ -230,6 +236,13 @@
"wiki_name": "Bromsgrove District Council",
"wiki_note": "You will need to use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find the UPRN."
},
"BroxbourneCouncil": {
"url": "https://www.broxbourne.gov.uk",
"uprn": "148048608",
"postcode": "EN8 7FL",
"wiki_name": "Broxbourne 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 @@ -736,6 +749,15 @@
"wiki_name": "Harrogate Borough Council",
"wiki_note": "Pass the UPRN, which can be found at [this site](https://secure.harrogate.gov.uk/inmyarea). URL doesn't need to be passed."
},
"HertsmereBoroughCouncil": {
"house_number": "1",
"postcode": "WD7 9HZ",
"skip_get_url": true,
"url": "https://www.hertsmere.gov.uk",
"web_driver": "http://selenium:4444",
"wiki_name": "Hertsmere Borough Council",
"wiki_note": "Provide your house number in the `house_number` parameter and postcode in the `postcode` parameter."
},
"HighlandCouncil": {
"url": "https://www.highland.gov.uk",
"wiki_command_url_override": "https://www.highland.gov.uk",
Expand Down Expand Up @@ -1664,6 +1686,13 @@
"wiki_name": "Waltham Forest",
"wiki_note": "Use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find your UPRN."
},
"WarringtonBoroughCouncil": {
"url": "https://www.warrington.gov.uk",
"wiki_command_url_override": "https://www.warrington.gov.uk",
"uprn": "10094964379",
"wiki_name": "Warrington Borough Council",
"wiki_note": "You will need to use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find the UPRN."
},
"WarwickDistrictCouncil": {
"url": "https://estates7.warwickdc.gov.uk/PropertyPortal/Property/Recycling/100070263793",
"wiki_command_url_override": "https://estates7.warwickdc.gov.uk/PropertyPortal/Property/Recycling/XXXXXXXX",
Expand Down Expand Up @@ -1715,6 +1744,13 @@
"wiki_name": "West Berkshire Council",
"wiki_note": "Provide your house number in the `house_number` parameter and postcode in the `postcode` parameter."
},
"WestLancashireBoroughCouncil": {
"url": "https://www.westlancs.gov.uk",
"uprn": "10012343339",
"postcode": "WN8 0HR",
"wiki_name": "West Lancashire Borough Council",
"wiki_note": "You will need to use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find the UPRN."
},
"WestLindseyDistrictCouncil": {
"house_number": "PRIVATE ACCOMMODATION",
"postcode": "LN8 2AR",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
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:

bindata = {"bins": []}

soup = BeautifulSoup(page.content, "html.parser")
soup.prettify

collection_divs = soup.select("div.feature-box.bins")
if not collection_divs:
raise Exception("No collections found")

for collection_div in collection_divs:
date_p = collection_div.select_one("p.date")
if not date_p:
continue

# Thu 22 Aug, 2024
date_ = datetime.strptime(date_p.text.strip(), "%a %d %b, %Y").strftime(
"%d/%m/%Y"
)
bins = collection_div.select("li")
if not bins:
continue
for bin in bins:
if not bin.text.strip():
continue
bin_type = bin.text.strip()

dict_data = {
"type": bin_type,
"collectionDate": date_,
}
bindata["bins"].append(dict_data)

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

return bindata
42 changes: 36 additions & 6 deletions uk_bin_collection/uk_bin_collection/councils/BradfordMDC.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import re

import requests
from bs4 import BeautifulSoup

Expand Down Expand Up @@ -89,12 +91,40 @@ def parse_data(self, page: str, **kwargs) -> dict:
)
).strftime(date_format)

# Build data dict for each entry
dict_data = {
"type": bin_type,
"collectionDate": bin_date,
}
data["bins"].append(dict_data)
# Build data dict for each entry
dict_data = {
"type": bin_type,
"collectionDate": bin_date,
}
data["bins"].append(dict_data)

for bin in soup.find_all(attrs={"id": re.compile(r"CTID-D0TUYGxO-\d+-A")}):
dict_data = {
"type": "General Waste",
"collectionDate": datetime.strptime(
bin.text.strip(),
"%a %b %d %Y",
).strftime(date_format),
}
data["bins"].append(dict_data)
for bin in soup.find_all(attrs={"id": re.compile(r"CTID-d3gapLk-\d+-A")}):
dict_data = {
"type": "Recycling Waste",
"collectionDate": datetime.strptime(
bin.text.strip(),
"%a %b %d %Y",
).strftime(date_format),
}
data["bins"].append(dict_data)
for bin in soup.find_all(attrs={"id": re.compile(r"CTID-L8OidMPA-\d+-A")}):
dict_data = {
"type": "Garden Waste (Subscription Only)",
"collectionDate": datetime.strptime(
bin.text.strip(),
"%a %b %d %Y",
).strftime(date_format),
}
data["bins"].append(dict_data)

data["bins"].sort(
key=lambda x: datetime.strptime(x.get("collectionDate"), date_format)
Expand Down
71 changes: 71 additions & 0 deletions uk_bin_collection/uk_bin_collection/councils/BroxbourneCouncil.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
from datetime import datetime

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


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": []}

API_URL = "https://www.broxbourne.gov.uk/xfp/form/205"

post_data = {
"page": "490",
"locale": "en_GB",
"qacf7e570cf99fae4cb3a2e14d5a75fd0d6561058_0_0": user_postcode,
"qacf7e570cf99fae4cb3a2e14d5a75fd0d6561058_1_0": user_uprn,
"next": "Next",
}

r = requests.post(API_URL, data=post_data)
r.raise_for_status()

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

form__instructions = soup.find(attrs={"class": "form__instructions"})
table = form__instructions.find("table")

rows = table.find_all("tr")

current_year = datetime.now().year

# Process each row into a list of dictionaries
for row in rows[1:]: # Skip the header row
columns = row.find_all("td")
collection_date = (
columns[0].get_text(separator=" ").replace("\xa0", " ").strip()
)
service = columns[1].get_text(separator=" ").replace("\xa0", " ").strip()

collection_date = datetime.strptime(collection_date, "%a %d %b")

if collection_date.month == 1:
collection_date = collection_date.replace(year=current_year + 1)
else:
collection_date = collection_date.replace(year=current_year)

dict_data = {
"type": service,
"collectionDate": (collection_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
Loading

0 comments on commit d02a46c

Please sign in to comment.