Skip to content

Instantly share code, notes, and snippets.

@shredding
Last active May 16, 2021 11:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save shredding/e94df43f0abee6cc27f878305b415373 to your computer and use it in GitHub Desktop.
Save shredding/e94df43f0abee6cc27f878305b415373 to your computer and use it in GitHub Desktop.
Get notified when there are new slots availale at the IMPFZENTREN in BERLIN
import os
from datetime import datetime
from time import sleep
from selenium import webdriver
from selenium.common.exceptions import NoSuchElementException, ElementClickInterceptedException
"""
Installation requirements:
$ brew install terminal-notifier
$ brew install --cask chromedriver
$ pip3 install selenium
Change the latest date (open appointments after this date will be ignored)
$ python3 run.py
"""
latest_date = '2021-05-29'
urls = [
"https://www.doctolib.de/institut/berlin/ciz-berlin-berlin?pid=practice-158436",
"https://www.doctolib.de/institut/berlin/ciz-berlin-berlin?pid=practice-158433",
"https://www.doctolib.de/institut/berlin/ciz-berlin-berlin?pid=practice-158435",
"https://www.doctolib.de/institut/berlin/ciz-berlin-berlin?pid=practice-158437",
"https://www.doctolib.de/institut/berlin/ciz-berlin-berlin?pid=practice-158434",
"https://www.doctolib.de/institut/berlin/ciz-berlin-berlin?pid=practice-158431"
]
waiting_secs = 1
slot = None
driver = webdriver.Chrome()
current_vaccine = 'moderna'
ref_date = datetime.strptime(latest_date, '%Y-%m-%d')
def notify(title, message):
t = '-title {!r}'.format(title)
m = '-message {!r}'.format(message)
os.system('terminal-notifier {}'.format(' '.join([m, t])))
def has_warning_message():
try:
warning = driver.find_element_by_css_selector('.booking-message-warning span')
if 'Aufgrund der starken Nachfrage ist dieses Zentrum nicht mehr verfügbar' in warning.text:
return True
if 'Sie können für diesen Arzt keine Termine online vereinbaren.' in warning.text:
return True
if 'Keine Verfügbarkeiten' in warning.text:
return True
except NoSuchElementException:
pass
try:
warning = driver.find_element_by_css_selector('h1.lang-de')
if 'Service vorübergehend außer Betrieb' in warning.text:
return True
except NoSuchElementException:
pass
try:
elem = driver.find_element_by_css_selector('.dl-modal-body-normal')
# doctolib was out of sync, the slot didn't really exist
if "Bitte wählen Sie einen neuen Termin aus." in elem.text:
return True
if "Es ist während der Terminvereinbarung ein Fehler aufgetreten." in elem.text:
return True
except NoSuchElementException:
pass
return False
def can_progress_because_element_available(css_selector, multiple_elements=False, callback=None):
for _ in range(10):
if has_warning_message():
return False
try:
if multiple_elements:
elem = driver.find_elements_by_css_selector(css_selector)[0]
else:
elem = driver.find_element_by_css_selector(css_selector)
if callback is None:
elem.click()
return True
elif callback(elem):
elem.click()
return True
except (NoSuchElementException, IndexError):
sleep(waiting_secs)
except ElementClickInterceptedException:
continue
return False
def validate_time(elem):
txt = elem.text
txt = txt.replace('Nächster Termin am ', '').replace(' Mai ', '05.').replace(' Juni ', '06.').replace(' Juli ', '07.').replace('August ', '08.')
txt = txt.replace(' ', '')
if not len(txt) == 10:
txt = '0' + txt
if datetime.strptime(txt, '%d.%m.%Y') <= ref_date:
return True
print(f'Found slot, but after requested date: {txt}.')
return False
while slot is None:
# we alternate between moderna and biontech selection every round to make things easier
current_vaccine = 'biontech' if current_vaccine == 'moderna' else 'moderna'
for url in urls:
print(f'Checking slots for {url} ...')
driver.get(url)
sleep(waiting_secs)
try:
driver.find_element_by_id('didomi-notice-agree-button').click()
except NoSuchElementException:
pass
try:
driver.find_element_by_css_selector('.dl-select-block').click()
options = driver.find_elements_by_css_selector('.dl-select-block option')
is_moderna_only = False
for option in options:
if option.text == 'Wählen sie den Besuchsgrund':
continue
if 'astra' in option.text.lower():
is_moderna_only = True
elif current_vaccine in option.text.lower():
option.click()
break
elif is_moderna_only and 'moderna' in option.text.lower():
option.click()
except NoSuchElementException:
pass
if not can_progress_because_element_available('.availabilities-message span', callback=validate_time):
continue
if not can_progress_because_element_available('.availabilities-next-slot', multiple_elements=True):
continue
slot = url
break
notify('New slots available!', 'Get your slot now!')
print(f'Available slots in {slot}.')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment