Skip to content

Commit

Permalink
feat: Adding Hertsmere Borough Council
Browse files Browse the repository at this point in the history
fix: #776
  • Loading branch information
m26dvd committed Nov 11, 2024
1 parent 3eb5e5f commit 7a37fde
Show file tree
Hide file tree
Showing 3 changed files with 185 additions and 0 deletions.
9 changes: 9 additions & 0 deletions uk_bin_collection/tests/input.json
Original file line number Diff line number Diff line change
Expand Up @@ -743,6 +743,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
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
import re
import time

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


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

URI_1 = "https://www.hertsmere.gov.uk/Environment-Refuse-and-Recycling/Recycling--Waste/Bin-collections/Collections-and-calendar.aspx"
URI_2 = "https://hertsmere-services.onmats.com/w/webpage/round-search"

# Create Selenium webdriver
driver = create_webdriver(web_driver, headless, None, __name__)
driver.get(URI_1)

soup = BeautifulSoup(driver.page_source, "html.parser")

current_week = (soup.find("li", class_="current")).text.strip()

strong = soup.find_all("strong", text=re.compile(r"^Week"))

bin_weeks = []
for tag in strong:
parent = tag.parent
bin_type = (
(parent.text).split("-")[1].strip().replace("\xa0", " ").split(" and ")
)
for bin in bin_type:
dict_data = {
"week": tag.text.replace("\xa0", " "),
"bin_type": bin,
}
bin_weeks.append(dict_data)

driver.get(URI_2)

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

WebDriverWait(driver, 10).until(
EC.element_to_be_clickable(
(
By.XPATH,
f"//ul[@class='result_list']/li[starts-with(@aria-label, '{user_paon}')]",
)
)
).click()

WebDriverWait(driver, timeout=10).until(
EC.element_to_be_clickable(
(
By.CSS_SELECTOR,
"input.fragment_presenter_template_edit.btn.bg-primary.btn-medium[type='submit']",
)
)
).click()

WebDriverWait(driver, timeout=10).until(
EC.presence_of_element_located(
(By.XPATH, "//h3[contains(text(), 'Collection days')]")
)
)

soup = BeautifulSoup(driver.page_source, "html.parser")

table = soup.find("table", class_="table listing table-striped")

# Check if the table was found
if table:
# Extract table rows and cells
table_data = []
for row in table.find("tbody").find_all("tr"):
# Extract cell data from each <td> tag
row_data = [cell.get_text(strip=True) for cell in row.find_all("td")]
table_data.append(row_data)

else:
print("Table not found.")

collection_day = (table_data[0])[1]

current_week_bins = [bin for bin in bin_weeks if bin["week"] == current_week]
next_week_bins = [bin for bin in bin_weeks if bin["week"] != current_week]

days_of_week = [
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday",
"Sunday",
]

today = datetime.now()
today_idx = today.weekday() # Monday is 0 and Sunday is 6
target_idx = days_of_week.index(collection_day)

days_until_target = (target_idx - today_idx) % 7
if days_until_target == 0:
next_day = today
else:
next_day = today + timedelta(days=days_until_target)

current_week_dates = get_dates_every_x_days(next_day, 14, 7)
next_week_date = next_day + timedelta(days=7)
next_week_dates = get_dates_every_x_days(next_week_date, 14, 7)

for date in current_week_dates:
for bin in current_week_bins:
dict_data = {
"type": bin["bin_type"],
"collectionDate": date,
}
bindata["bins"].append(dict_data)

for date in next_week_dates:
for bin in next_week_bins:
dict_data = {
"type": bin["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
15 changes: 15 additions & 0 deletions wiki/Councils.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ This document is still a work in progress, don't worry if your council isn't lis
- [Harborough District Council](#harborough-district-council)
- [Haringey Council](#haringey-council)
- [Harrogate Borough Council](#harrogate-borough-council)
- [Hertsmere Borough Council](#hertsmere-borough-council)
- [Highland Council](#highland-council)
- [High Peak Council](#high-peak-council)
- [Hounslow Council](#hounslow-council)
Expand Down Expand Up @@ -1345,6 +1346,20 @@ Note: Pass the UPRN, which can be found at [this site](https://secure.harrogate.

---

### Hertsmere Borough Council
```commandline
python collect_data.py HertsmereBoroughCouncil https://www.hertsmere.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: Provide your house number in the `house_number` parameter and postcode in the `postcode` parameter.

---

### Highland Council
```commandline
python collect_data.py HighlandCouncil https://www.highland.gov.uk -u XXXXXXXX
Expand Down

0 comments on commit 7a37fde

Please sign in to comment.