76 lines
1.9 KiB
Python
76 lines
1.9 KiB
Python
import contextlib
|
|
import datetime
|
|
import locale
|
|
|
|
import httpx
|
|
from bs4 import BeautifulSoup
|
|
|
|
import berlin
|
|
|
|
http = httpx.Client(
|
|
headers={
|
|
'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36'
|
|
},
|
|
follow_redirects=True,
|
|
)
|
|
|
|
|
|
@contextlib.contextmanager
|
|
def override_locale(category: int, val: str) -> None:
|
|
prev = locale.getlocale(category)
|
|
locale.setlocale(category, val)
|
|
yield
|
|
locale.setlocale(category, prev)
|
|
|
|
|
|
def get_available_slots():
|
|
res = http.get('https://service.berlin.de/dienstleistung/120686/')
|
|
res.raise_for_status()
|
|
|
|
soup = BeautifulSoup(res.text, 'html.parser')
|
|
link = soup.select_one('[role="complementary"] .zmstermin-multi a')
|
|
calendar_url = link.attrs['href']
|
|
|
|
try:
|
|
# redirect fails, we just need the cookies
|
|
_ = http.get(calendar_url)
|
|
except:
|
|
pass
|
|
res = http.get('https://service.berlin.de/terminvereinbarung/termin/day/')
|
|
res.raise_for_status()
|
|
|
|
return extract_days(res.text)
|
|
|
|
|
|
def extract_days(html: str) -> list[datetime.date]:
|
|
soup = BeautifulSoup(html, 'html.parser')
|
|
|
|
found = []
|
|
for it in soup.select('.calendar-month-table .buchbar'):
|
|
month_year = it.find_parent(attrs={'class': 'calendar-month-table'}).select_one('thead .month').text.strip()
|
|
day = it.text.strip()
|
|
found.append(f'{day} {month_year}')
|
|
|
|
with override_locale(locale.LC_TIME, 'de_DE'):
|
|
days = [datetime.datetime.strptime(it, '%d %B %Y').date() for it in found]
|
|
|
|
return days
|
|
|
|
|
|
def main():
|
|
days = get_available_slots()
|
|
good_days = [it for it in days if it < datetime.date(2023, 1, 27)]
|
|
|
|
if not good_days:
|
|
print('no slots')
|
|
return
|
|
|
|
print('found slots')
|
|
berlin.book_slot()
|
|
for it in days:
|
|
print(it)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|