Adding tauranga_govt_nz (#1757)

* Add Tauranga City Council source

* Update tcc reademe name

* dynanmically fetch asp.net form data, tidy up code for PR

* minor reformatting

---------

Co-authored-by: 5ila5 <5ila5@users.noreply.github.com>
This commit is contained in:
Kronoc123
2024-02-03 23:32:06 +13:00
committed by GitHub
parent 9ccb0f78ad
commit 79bf869aa1
4 changed files with 163 additions and 1 deletions

View File

@@ -1043,6 +1043,7 @@ Waste collection schedules in the following formats and countries are supported.
- [Hamilton City Council](/doc/source/hcc_govt_nz.md) / fightthelandfill.co.nz
- [Horowhenua District Council](/doc/source/horowhenua_govt_nz.md) / horowhenua.govt.nz
- [Hutt City Council](/doc/source/toogoodtowaste_co_nz.md) / toogoodtowaste.co.nz
- [Tauranga City Council](/doc/source/tauranga_govt_nz.md) / tauranga.govt.nz
- [Waipa District Council](/doc/source/waipa_nz.md) / waipadc.govt.nz
- [Wellington City Council](/doc/source/wellington_govt_nz.md) / wellington.govt.nz
</details>

View File

@@ -0,0 +1,129 @@
import json
from datetime import datetime
from typing import Dict, List, Tuple
from urllib.parse import quote, urlencode
import requests
from bs4 import BeautifulSoup
from waste_collection_schedule import Collection # type: ignore[attr-defined]
TITLE = "Tauranga City Council"
DESCRIPTION = "Source script for Tauranga City Council"
URL = "https://www.tauranga.govt.nz/"
TEST_CASES = {
"121 Castlewold Drive": {"address": "121 Castlewold Drive"},
"70 Santa Monica Drive": {"address": " 70 Santa Monica Drive"},
"21 Wells Avenue": {"address": " 21 Wells Avenue"},
}
API_URL = "https://www.tauranga.govt.nz/living/rubbish-and-recycling/kerbside-collections/when-to-put-your-bins-out"
ICON_MAP = {
"Rubbish": "mdi:trash-can",
"Recycling": "mdi:recycle",
"Glass": "mdi:glass-fragile",
"Garden waste": "mdi:leaf",
"Food scraps": "mdi:food-apple",
}
class Source:
def __init__(self, address: str) -> None:
self._address: str = address
self._session: requests.Session = requests.Session()
ADDRESS_URL = "https://www.tauranga.govt.nz/Services/SearchService.asmx/DoRIDStreetPredictiveSearch"
WASTE_URL = "https://www.tauranga.govt.nz/living/rubbish-and-recycling/kerbside-collections/when-to-put-your-bins-out"
def fetch(self):
addr_1, addr_2 = self.get_address_detail()
form_data = self.generate_form_data(addr_1, addr_2)
waste_response = self.get_waste_pickup_dates(form_data)
return self.parse_waste_pickup_dates(waste_response)
def get_address_detail(self) -> Tuple[str, str]:
address_response = self._session.post(
self.ADDRESS_URL,
json={"prefixText": self._address, "count": 12, "contextKey": "test"},
headers={"Content-Type": "application/json; charset=UTF-8"},
).json()
if len(address_response.get("d")) == 0:
raise Exception("Address not found within TCC records")
# Parse address data from initial request
address_dict = json.loads(address_response.get("d")[0])
addr_1 = address_dict.get("First")
addr_2 = address_dict.get("Second")
return addr_1, addr_2
def get_waste_pickup_dates(self, form_data: Dict[str, str]) -> requests.Response:
pickup_date_response = self._session.post(
self.WASTE_URL,
data=form_data,
headers={
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8"
},
)
return pickup_date_response
def generate_form_data(self, addr_1: str, addr_2: str) -> str:
state_response = self._session.get(self.WASTE_URL)
soup = BeautifulSoup(state_response.content, "html.parser")
view_state = soup.find("input", attrs={"id": "__VIEWSTATE"})["value"]
event_validation = soup.find("input", attrs={"id": "__EVENTVALIDATION"})[
"value"
]
form_data = {
"dnn$ctr2863$MasterView$CollectionDaysv2$Address": addr_1,
"dnn$ctr2863$MasterView$CollectionDaysv2$hdnValue": f"{addr_1}||{addr_2}",
"__VIEWSTATE": view_state,
"__EVENTVALIDATION": event_validation,
}
encoded_form_data = urlencode(form_data, quote_via=quote)
return encoded_form_data
def parse_waste_pickup_dates(
self, pickup_date_response: requests.Response
) -> List[Collection]:
soup = BeautifulSoup(pickup_date_response.text, "html.parser")
bin_type_containers = soup.find_all("div", class_="binTypeContainer")
entries = []
for container in bin_type_containers:
date = container.find("h5").text.strip()
bin_types = [
item.text
for item in container.find_all("p")
if item.find("span", class_="dot")
]
if date == "Not subscribed":
continue # Skip waste types that aren't being paid for/subscribed to.
else:
current_date = datetime.now()
pickup_datetime = datetime.strptime(date, "%A %d %B")
if current_date.month == 12 and pickup_datetime.month == 1:
# Date responses have no year, handle adding a year and also year end/new year collections
pickup_date = pickup_datetime.replace(
year=datetime.now().year + 1
).date()
pickup_date = pickup_datetime.replace(year=datetime.now().year).date()
for bin_type in bin_types:
entries.append(
Collection(
date=pickup_date,
t=bin_type,
icon=ICON_MAP.get(bin_type),
)
)
return entries

View File

@@ -0,0 +1,32 @@
# Tauranga City Council
Support for schedules provided by [Tauranga City Council](https://www.tauranga.govt.nz/).
## Configuration via configuration.yaml
```yaml
waste_collection_schedule:
sources:
- name: tauranga_govt_nz
args:
address: ADDRESS # see 'How to get the source argument below'
```
### Configuration Variables
**address**
*(string) (required)*
## Example
```yaml
waste_collection_schedule:
sources:
- name: tauranga_govt_nz
args:
address: "1 Santa Monica Drive"
```
## How to get the source argument
Simply enter your street number and name as if you're searching on the online tool. Note that the first result will be selected if there are multiple search results.

View File

@@ -28,7 +28,7 @@ Waste collection schedules from service provider web sites are updated daily, de
| Lithuania | Kauno švara |
| Luxembourg | Esch-sur-Alzette |
| Netherlands | ACV Group, Alpen an den Rijn, Area Afval, Avalex, Avri, Bar Afvalbeheer, Circulus, Cyclus NV, Dar, Den Haag, GAD, Gemeente Almere, Gemeente Berkelland, Gemeente Cranendonck, Gemeente Hellendoorn, Gemeente Lingewaard, Gemeente Meppel, Gemeente Middelburg + Vlissingen, Gemeente Peel en Maas, Gemeente Schouwen-Duiveland, Gemeente Sudwest-Fryslan, Gemeente Venray, Gemeente Voorschoten, Gemeente Waalre, Gemeente Westland, HVC Groep, Meerlanden, Mijn Blink, PreZero, Purmerend, RAD BV, Reinis, Spaarnelanden, Twente Milieu, Waardlanden, Ximmio, ZRD |
| New Zealand | Auckland Council, Christchurch City Council, Dunedin District Council, Gore, Invercargill & Southland, Hamilton City Council, Horowhenua District Council, Hutt City Council, Waipa District Council, Wellington City Council |
| New Zealand | Auckland Council, Christchurch City Council, Dunedin District Council, Gore, Invercargill & Southland, Hamilton City Council, Horowhenua District Council, Hutt City Council, Tauranga City Council, Waipa District Council, Wellington City Council |
| Norway | BIR (Bergensområdets Interkommunale Renovasjonsselskap), IRiS, Min Renovasjon, Movar IKS, Oslo Kommune, ReMidt Orkland muni, Sandnes Kommune, Stavanger Kommune, Trondheim |
| Poland | Ecoharmonogram, Poznań/Koziegłowy/Objezierze/Oborniki, Warsaw, Wrocław |
| Slovenia | Moji odpadki, Ljubljana |