add Port Adelaide Enfield, Austrailia

This commit is contained in:
5ila5
2023-05-18 14:53:12 +02:00
parent 52f3f3325e
commit b05645e507
4 changed files with 194 additions and 1 deletions

View File

@@ -45,6 +45,7 @@ Waste collection schedules in the following formats and countries are supported.
- [Melton City Council](/doc/source/melton_vic_gov_au.md) / melton.vic.gov.au
- [Nillumbik Shire Council](/doc/source/nillumbik_vic_gov_au.md) / nillumbik.vic.gov.au
- [North Adelaide Waste Management Authority](/doc/source/nawma_sa_gov_au.md) / nawma.sa.gov.au
- [Port Adelaide Enfield, South Australia](/doc/source/portenf_sa_gov_au.md) / ecouncil.portenf.sa.gov.au
- [RecycleSmart](/doc/source/recyclesmart_com.md) / recyclesmart.com
- [Stonnington City Council](/doc/source/stonnington_vic_gov_au.md) / stonnington.vic.gov.au
- [The Hills Shire Council, Sydney](/doc/source/thehills_nsw_gov_au.md) / thehills.nsw.gov.au

View File

@@ -0,0 +1,143 @@
import requests
from waste_collection_schedule import Collection # type: ignore[attr-defined]
from bs4 import BeautifulSoup
import logging
import datetime
# With verify=True the POST fails due to a SSLCertVerificationError.
# Using verify=False works, but is not ideal. The following links may provide a better way of dealing with this:
# https://urllib3.readthedocs.io/en/1.26.x/advanced-usage.html#ssl-warnings
# https://urllib3.readthedocs.io/en/1.26.x/user-guide.html#ssl
# These two lines areused to suppress the InsecureRequestWarning when using verify=False
import urllib3
urllib3.disable_warnings()
TITLE = "Port Adelaide Enfield, South Australia"
DESCRIPTION = "Source for City of Port Adelaide Enfield, South Australia."
URL = "https://ecouncil.portenf.sa.gov.au/"
TEST_CASES = {
"Broadview, Regency Road, 565 ": {"suburb": "Broadview", "street": "Regency Road", "house_number": 565, "unit_number": ""},
"48 Floriedale Rd ": {"suburb": "Greenacres", "street": "Floriedale Rd", "house_number": "48"},
"24 Margaret Terrace": {"suburb": "Rosewater", "street": "Margaret Terrace", "house_number": "24"},
"Addison Road 91 with unit": {"suburb": "Rosewater", "street": "Addison Road", "house_number": 91, "unit_number": 2},
}
ICON_MAP = {
"general-waste bin": "mdi:trash-can",
"organics bin": "mdi:leaf",
"recycling bin": "mdi:recycle",
}
LOGGER = logging.getLogger(__name__)
API_URL = "https://ecouncil.portenf.sa.gov.au/public/propertywastedates/public.aspx"
class Source:
def __init__(self, suburb: str, street: str, house_number: str | int, unit_number: str | int = ""):
self._suburb: str = suburb
self._street: str = street
self._house_number: str = str(house_number)
self._unit_number: str = str(unit_number)
def __set_args(self, soup: BeautifulSoup, event_taget=None, additonal: dict = {}) -> dict:
args = {
"ctl00$MainContent$txtSuburb": self._suburb,
"ctl00$MainContent$txtStreetName": self._street,
"ctl00$MainContent$txtHouseNumber": self._house_number,
"ctl00$MainContent$txtUnitNumber": self._unit_number,
}
if event_taget is not None:
args["__EVENTTARGET"] = event_taget
for hidden_val in soup.find_all("input", {"type": "hidden"}):
args[hidden_val["name"]] = hidden_val["value"]
for key, value in additonal.items():
args[key] = value
return args
def fetch(self):
session = requests.Session()
# get First page
r = session.get(API_URL, verify=False)
r.raise_for_status()
# extractt arguments
args = self.__set_args(BeautifulSoup(
r.text, "html.parser"), event_taget="ctl00$MainContent$btnSearch")
r = session.post(API_URL, data=args)
r.raise_for_status()
# get page to select an address
soup = BeautifulSoup(r.text, "html.parser")
selectable = soup.find_all(
"a", {"class": "anchor-button small"}, text="Select")
if len(selectable) == 0:
raise ValueError("No address found")
selected = selectable[0]
# If multiple addresses are found, try to find the one that matches the input and warn if there are multiple or none matches
if len(selectable) > 1:
found = [" ".join([y.text for y in x.parent.parent.find_all("td")[
1].find_all("span")]) for x in selectable]
using_index = 0
match = False
for index, entry in enumerate(found):
entry = entry.lower().strip().replace(" ", "")
if self._house_number.lower().strip().replace(" ", "") in entry and self._street.lower().strip().replace(" ", "") in entry and self._suburb.lower().strip().replace(" ", "") in entry and self._unit_number.lower().strip().replace(" ", "") in entry:
if match:
LOGGER.warning(
f"Multiple addresses found, using first one \nfound:{', '.join(found[:10])}{'...' if len(found) >= 10 else ''} \nusing:{found[using_index]}")
break
using_index = index
match = True
if not match:
LOGGER.warning(
f"no perfect addres match found, using:{found[using_index]}")
# request first address
args = self.__set_args(soup, event_taget="ctl00$MainContent$gvPropertyResults$ctl02$btnSelect", additonal={
selected["href"].split("'")[1]: ""})
r = session.post(API_URL, data=args)
r.raise_for_status()
soup = BeautifulSoup(r.text, "html.parser")
cal_header = soup.find(
"th", {"class": "header-month"}).find("span").text
main_month = cal_header.split("-")[0].strip()
secondary_month = cal_header.split("-")[1].strip().split(" ")[0]
secondary_year = main_year = cal_header.split("-")[1].strip().split(" ")[1]
# if main month contains a year, set it (mabe happens in december???)
if len(main_month.split(" ")) > 1:
main_year = main_month.split(" ")[1]
main_month = main_month.split(" ")[0]
entries = []
calendar = soup.find("table", {"class": "collection-day-calendar"})
# Iterate over all days with pickups
for pickup in calendar.find_all("div", {"class": "pickup"}):
parent_td = pickup.parent
month = main_month if parent_td.attrs["class"] == "main-month" else secondary_month
year = main_year if parent_td.attrs["class"] == "main-month" else secondary_year
day = parent_td.find("div", {"class": "daynumber"}).text
# Iterate over all pickup container types for this day
for container in pickup.find_all("div", {"class": "bin-container"}):
container_type = " ".join(container.find("div").attrs["class"])
container_icon = ICON_MAP.get(container_type)
date = datetime.datetime.strptime(f"{year}-{month}-{day}", "%Y-%B-%d").date()
entries.append(Collection(date=date, t=container_type, icon=container_icon))
return entries

View File

@@ -0,0 +1,49 @@
# City of Port Adelaide Enfield, South Australia
Support for schedules provided by [City of Port Adelaide Enfield, South Australia](https://ecouncil.portenf.sa.gov.au/), serving City of Port Adelaide Enfield, South Australia, South Australia.
## Configuration via configuration.yaml
```yaml
waste_collection_schedule:
sources:
- name: portenf_sa_gov_au
args:
suburb: SUBURB
street: STREET NAME
house_number: "HOUSE NUMBER"
unit_number: UNIT NUMBER
```
### Configuration Variables
**suburb**
*(String) (required)*
**street**
*(String) (required)*
**house_number**
*(String | Integer) (required)*
**unit_number**
*(String | Integer) (optional)*
## Example
```yaml
waste_collection_schedule:
sources:
- name: portenf_sa_gov_au
args:
suburb: Rosewater
street: Addison Road
house_number: 91
unit_number: 2
```
## How to get the source argument
Find the parameter of your address using [https://www.cityofpae.sa.gov.au/live/waste/bin-collection](https://www.cityofpae.sa.gov.au/live/waste/bin-collection) and write them exactly like the address you get searching for your address.

View File

@@ -16,7 +16,7 @@ Waste collection schedules from service provider web sites are updated daily, de
|--|--|
| Generic | ICS / iCal files |
| Static | User-defined dates or repeating date patterns |<!--Begin of country section-->
| Australia | Banyule City Council, Belmont City Council, Brisbane City Council, Campbelltown City Council (NSW), Cardinia Shire Council, City of Canada Bay Council, City of Kingston, City of Onkaparinga Council, Gold Coast City Council, Hume City Council, Inner West Council (NSW), Ipswich City Council, Ku-ring-gai Council, Lake Macquarie City Council, Macedon Ranges Shire Council, Maribyrnong Council, Maroondah City Council, Melton City Council, Nillumbik Shire Council, North Adelaide Waste Management Authority, RecycleSmart, Stonnington City Council, The Hills Shire Council, Sydney, Unley City Council (SA), Whittlesea City Council, Wollongong City Council, Wyndham City Council, Melbourne |
| Australia | Banyule City Council, Belmont City Council, Brisbane City Council, Campbelltown City Council (NSW), Cardinia Shire Council, City of Canada Bay Council, City of Kingston, City of Onkaparinga Council, Gold Coast City Council, Hume City Council, Inner West Council (NSW), Ipswich City Council, Ku-ring-gai Council, Lake Macquarie City Council, Macedon Ranges Shire Council, Maribyrnong Council, Maroondah City Council, Melton City Council, Nillumbik Shire Council, North Adelaide Waste Management Authority, Port Adelaide Enfield, South Australia, RecycleSmart, Stonnington City Council, The Hills Shire Council, Sydney, Unley City Council (SA), Whittlesea City Council, Wollongong City Council, Wyndham City Council, Melbourne |
| Austria | Andau, Apetlon, App CITIES, Bad Blumau, Bad Gleichenberg, Bad Loipersdorf, Bad Radkersburg, Bad Tatzmannsdorf, Bildein, Breitenbrunn am Neusiedler See, Breitenstein, Bruckneudorf, Buch - St. Magdalena, Burgau, Burgenländischer Müllverband, Dechantskirchen, Deutsch Goritz, Deutsch Jahrndorf, Deutsch Kaltenbrunn, Deutschkreutz, Dobl-Zwaring, Draßmarkt, Eberau, Eberndorf, Eberstein, Edelsbach bei Feldbach, Eggersdorf bei Graz, Eisenstadt, Fehring, Feistritz ob Bleiburg, Feldbach, Frankenau-Unterpullendorf, Frauenkirchen, Freistadt, Friedberg, Fürstenfeld, Gabersdorf, Gattendorf, Gols, Grafendorf bei Hartberg, Grafenstein, Gratkorn, Großwarasdorf, Großwilfersdorf, Gutenberg-Stenzengreith, Güssing, Hartberg, Heiligenkreuz am Waasen, Hofstätten an der Raab, Horitschon, Hornstein, Hüttenberg, Ilz, infeo, Innsbrucker Kommunalbetriebe, Jabing, Jagerberg, Kaindorf, Kaisersdorf, Kalsdorf bei Graz, Kapfenstein, Kirchberg an der Raab, Kleinmürbisch, Klingenbach, Klöch, Kohfidisch, Korneuburg, Laa an der Thaya, Leithaprodersdorf, Lieboch, Litzelsdorf, Loipersbach im Burgenland, Mariasdorf, Markt Hartmannsdorf, Markt Neuhodis, Marz, Mattersburg, Melk, Mettersdorf am Saßbach, Mischendorf, Mistelbach, Mitterdorf an der Raab, Mureck, Mörbisch am See, Neudorf bei Parndorf, Neufeld an der Leitha, Neusiedl am See, Nickelsdorf, Oberpullendorf, Oberwart, Oslip, Ottendorf an der Rittschein, Paldau, Pamhagen, Parndorf, Peggau, Pernegg an der Mur, Pilgersdorf, Pinggau, Pinkafeld, Podersdorf am See, Poggersdorf, Potzneusiedl, Poysdorf, Pöchlarn, Radmer, Ragnitz, Raiding, Rudersdorf, Rust, Saalfelden am Steinernen Meer, Sankt Oswald bei Plankenwarth, Schäffern, Schützen am Gebirge, Seiersberg-Pirka, Sigleß, Sinabelkirchen, St. Andrä, St. Anna am Aigen, St. Johann in der Haide, St. Lorenzen am Wechsel, St. Margarethen an der Raab, St. Margarethen im Burgenland, St. Peter - Freienstein, St. Peter am Ottersbach, St. Ruprecht an der Raab, St. Veit in der Südsteiermark, Stadt Salzburg, Stadtservice Korneuburg, Stegersbach, Steinbrunn, Steuerberg, Stinatz, Stiwoll, Stockerau, Söchau, Thal, Tieschen, Tulln an der Donau, Umweltprofis, Unterfrauenhaid, Unterkohlstätten, Unterlamm, Vasoldsberg, Vordernberg, Völkermarkt, Weiz, Werfenweng, Wies, Wiesen, Wiesfleck, Wimpassing an der Leitha, Winden am See, Wolfsberg, Wolkersdorf im Weinviertel, WSZ Moosburg, Zagersdorf, Zillingtal, Zurndorf, Übelbach |
| Belgium | Hygea, Limburg.net, Recycle! |
| Canada | City of Toronto |