added awb_mainz_bingen_de

This commit is contained in:
5ila5
2023-04-09 19:07:48 +02:00
parent aa31d2217d
commit 589870ea52
4 changed files with 218 additions and 1 deletions

View File

@@ -120,6 +120,7 @@ Waste collection schedules in the following formats and countries are supported.
- [Abfallwirtschaftsbetrieb Landkreis Augsburg](/doc/source/c_trace_de.md) / awb-landkreis-augsburg.de
- [Abfallwirtschaftsbetrieb Landkreis Aurich](/doc/source/c_trace_de.md) / mkw-grossefehn.de
- [Abfallwirtschaftsbetrieb Landkreis Karlsruhe](/doc/ics/awb_landkreis_karlsruhe_de.md) / awb-landkreis-karlsruhe.de
- [Abfallwirtschaftsbetrieb LK Mainz-Bingen](/doc/source/awb_mainz_bingen_de.md) / awb-mainz-bingen.de
- [Abfallwirtschaftsbetrieb München](/doc/ics/awm_muenchen_de.md) / awm-muenchen.de
- [Abfallwirtschaftsbetriebe Münster](/doc/source/muellmax_de.md) / stadt-muenster.de
- [Abfallwirtschaftsgesellschaft Landkreis Schaumburg](/doc/ics/aws_shg_de.md) / aws-shg.de

View File

@@ -0,0 +1,172 @@
import requests
from waste_collection_schedule import Collection # type: ignore[attr-defined]
from waste_collection_schedule.service.ICS import ICS
from bs4 import BeautifulSoup
import re
TITLE = "Abfallwirtschaftsbetrieb LK Mainz-Bingen"
DESCRIPTION = "Source for Abfallwirtschaftsbetrieb LK Mainz-Bingen."
URL = "https://www.awb-mainz-bingen.de/"
TEST_CASES = {
"Stadt Ingelheim Ingelheim Süd Albert-Schweitzer-Straße": {
"bezirk": "Stadt Ingelheim",
"ort": "Ingelheim Süd",
"strasse": "Albert-Schweitzer-Straße"
},
"Verbandsgemeinde Rhein-Selz, Mommenheim": {
"bezirk": "Verbandsgemeinde Rhein-Selz",
"ort": "mOmMenHeiM",
},
"Stadt Bingen, Bingen-Stadt, Martinstraße (Haus-Nr.: 5 - 11, 10 - 18)": {
"bezirk": "Stadt Bingen",
"ort": "Bingen-Stadt",
"strasse": "Martinstraße (Haus-Nr.: 5 - 11, 10 - 18)"
},
}
ICON_MAP = {
"Restmüll": "mdi:trash-can",
"Glass": "mdi:bottle-soda",
"Biomüll": "mdi:leaf",
"Papier": "mdi:package-variant",
"Gelbe/r Tonne / Sack": "mdi:recycle",
"Problemmüll": "mdi:toxic",
}
API_URL = "https://abfallkalender.awb-mainz-bingen.de/"
class Source:
def __init__(self, bezirk: str, ort: str, strasse: str = None):
self._bezirk: str = bezirk
self._ort: str = ort
self._strasse: str = strasse
self._ics = ICS()
def fetch(self):
session = requests.Session()
# Get bezirk id from main page
r = session.get(API_URL)
r.raise_for_status()
soup = BeautifulSoup(r.text, "html.parser")
bezirk = soup.find("select", {"id": "Abfuhrbezirk"}).find(
"option", text=re.compile(re.escape(self._bezirk), re.IGNORECASE))
if not bezirk:
found = [i.text for i in soup.find_all("option")][1:]
raise Exception(
f"No matching bezirk found search for: {self._bezirk} found: {str(found)}")
bezirk_id = bezirk.get("value")
# set arguemnts to imitate xajax call
xjxargs_string = "<xjxobj>"
for key, value in {
"Abfuhrbezirk": "{bezirk_id}",
"Ortschaft": "{ort_id}",
"Strasse": "{strasse_id}",
}.items():
xjxargs_string += "<e><k>"+key+"</k><v>S"+value+"</v></e>"
xjxargs_string += "</xjxobj>"
args = {
"xjxfun": "show_ortsteil_dropdown",
"xjxargs[]": xjxargs_string.format(bezirk_id=bezirk_id, ort_id=0, strasse_id=0),
}
# send request to get dropdown with for ort id
r = session.post(API_URL, data=args)
r.raise_for_status()
soup = BeautifulSoup(r.text, "xml")
teilorte_div = soup.find("cmd", {"id": "divTeilort"})
if not teilorte_div:
raise Exception("invalid resonse from server", soup)
teilorte = BeautifulSoup(teilorte_div.text.replace(
"<![CDATA[", "").replace("]]>", ""), "html.parser")
ort = teilorte.find("option", text=re.compile(
re.escape(self._ort), re.IGNORECASE))
if not ort:
raise Exception(
f"No matching ort found. Searched for: {self._ort}. Found {str([i.text for i in teilorte.find_all('option')][1:])})")
ort_id = ort.get("value")
args = {
"xjxfun": "show_strasse_dropdown_or_abfuhrtermine",
"xjxargs[]": xjxargs_string.format(bezirk_id=bezirk_id, ort_id=ort_id, strasse_id=0),
}
r = session.post(API_URL, data=args)
r.raise_for_status()
soup = BeautifulSoup(r.text, "xml")
div_strasse = soup.find("cmd", {"id": "divStrasse"})
if not div_strasse:
raise Exception("invalid resonse from server")
strassen_soup = BeautifulSoup(div_strasse.text.replace(
"<![CDATA[", "").replace("]]>", ""), "html.parser")
# If strasse is needed
if strassen_soup.find("option"):
if not self._strasse:
raise Exception("Street needed but not provided")
# get strasse id
strasse_id = strassen_soup.find("option", text=re.compile(
re.escape(self._strasse), re.IGNORECASE))
if not strasse_id:
found = [i.text for i in strassen_soup.find_all("option")][1:]
raise Exception(
f"Street wanted but no matching street found. Searched for: {self._strasse}. Found {str(found)})")
strasse_id = strasse_id.get("value")
xjxargs = {"bezirk_id": bezirk_id,
"ort_id": ort_id, "strasse_id": strasse_id}
args = {
"xjxfun": "show_abfuhrtermine",
"xjxargs[]": xjxargs_string.format(**xjxargs),
}
# get main calendar
r = session.post(API_URL, data=args)
r.raise_for_status()
soup = BeautifulSoup(r.text, "xml")
cal_wrapper = soup.find("cmd", {"id": "divKalenderWrapper"})
if not cal_wrapper:
raise Exception("No calendar found", r.text)
cal_soup = BeautifulSoup(cal_wrapper.text.replace(
"<![CDATA[", "").replace("]]>", ""), "html.parser")
# get ical file url
ical_path = cal_soup.find(
"a", {"href": re.compile("ical")}).get("href")
# get ical file
r = requests.get(API_URL+ical_path)
r.raise_for_status()
r.encoding = "utf-8"
# remove DURATION because the returned icalendar has invalid DURATION syntax
ical_string = re.sub(r'^DURATION.*\n?', "", r.text, flags=re.MULTILINE)
dates = self._ics.convert(ical_string)
entries = []
for d in dates:
bin_type = d[1].split(" am ")[0].replace(
"Abfuhrtermin", "").strip()
entries.append(Collection(d[0], bin_type, ICON_MAP.get(bin_type)))
return entries

View File

@@ -0,0 +1,44 @@
# Abfallwirtschaftsbetrieb LK Mainz-Bingen
Support for schedules provided by [Abfallwirtschaftsbetrieb LK Mainz-Bingen](https://www.awb-mainz-bingen.de/), serving Landkreis Mainz-Bingen, Germany.
## Configuration via configuration.yaml
```yaml
waste_collection_schedule:
sources:
- name: awb_mainz_bingen_de
args:
bezirk: Abfuhrbezirk
ort: Ortschaft
strasse: Straße
```
### Configuration Variables
**bezirk**
*(String) (required)*
**ort**
*(String) (required)*
**strasse**
*(String) (optional)*
## Example
```yaml
waste_collection_schedule:
sources:
- name: awb_mainz_bingen_de
args:
bezirk: Stadt Ingelheim
ort: Ingelheim Süd
strasse: Albert-Schweitzer-Straße
```
## How to get the source argument
Find the parameter of your address using [https://abfallkalender.awb-mainz-bingen.de/](https://abfallkalender.awb-mainz-bingen.de/) and copy them exactly misspelled arguments or additional or missing spaces will result in an Exception.

File diff suppressed because one or more lines are too long