Skip to content

Instantly share code, notes, and snippets.

@farkmarnum
Last active April 9, 2021 14:15
Show Gist options
  • Save farkmarnum/4ce9c24afd2d06172da945a9122dbeee to your computer and use it in GitHub Desktop.
Save farkmarnum/4ce9c24afd2d06172da945a9122dbeee to your computer and use it in GitHub Desktop.
Poll NYC Vaccine finder periodically

Vaccine appointment checker

This Python script will

  1. Check every 30 seconds for new vaccine appointments in NYC within <threshold> miles of <zipcode>.
  2. If it finds available appointments, it will open a browser window (chromedriver).
  3. Then, you can complete the signup process for the appointment.

Installation (Mac OS)

# Install chromedriver so we can control Chrome
brew install --cask chromedriver
xattr -d com.apple.quarantine `which chromedriver`

# Create Python3 virtual environment
python3 -m venv .v
. .v/bin/activate

# Install packages
pip install -r requirements.txt

Running

# If not already in the virtual environment:
. .v/bin/activate

python3 vaccine.py <zipcode> <threshold in miles>

# To leave virtual environment:
deactivate

This will continue running, checking every 30 seconds for appointments, until killed with Ctrl-C.

blinker==1.4
certifi==2020.12.5
cffi==1.14.5
cryptography==3.4.7
h11==0.12.0
h2==4.0.0
hpack==4.0.0
hyperframe==6.0.0
kaitaistruct==0.9
pyasn1==0.4.8
pycparser==2.20
pyOpenSSL==20.0.1
pyparsing==2.4.7
PySocks==1.7.1
selenium==3.141.0
selenium-wire==4.2.3
six==1.15.0
urllib3==1.26.4
wsproto==1.0.0
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import sys
import os
import time
import json
import random
from urllib import request, parse
from seleniumwire import webdriver
from selenium.webdriver.chrome.options import Options as ChromeOptions
if len(sys.argv) < 3:
print('Usage: python3 vaccine.py <zipcode> <threshold in miles>')
exit(1)
ZIPCODE = sys.argv[1]
THRESHOLD_IN_MILES = int(sys.argv[2])
INTERVAL = 30
DOB = '1990-01-01'
def run_prescreen():
url = 'https://am-i-eligible.covid19vaccine.health.ny.gov/api/submit'
data = {
'person': {
'acknowledge': 'true',
'address': {
'zip': ZIPCODE
},
'zip': ZIPCODE,
'dob': DOB,
'name': "",
'nyresident': "Y",
'nyworker': "Y",
},
}
req = request.Request(url, data=parse.urlencode(data).encode())
resp = request.urlopen(req)
body = resp.read().decode('utf-8')
applicationId = json.loads(body)['applicationId']
return applicationId
def get_distance(s): return float(s['address']['distanceInMiles'])
def get_address_string(s):
address = s['address']
address_parts = [
address['line1'],
address['city'],
address['state'],
str(address['zipcode']),
]
return ', '.join([s.strip() for s in address_parts])
def is_available(s):
return s['availableAppointments'] == 'AA'
def print_success_message(site):
print("\n".join([
"🚨 🚨 🚨 🚨 🚨",
f"Vaccines available {get_distance(site)} miles away!",
site['providerName'],
get_address_string(site),
'',
'Opening headless Chrome...',
'',
]))
def print_failure_message(site):
dist = get_distance(site)
emojis = ["πŸ˜•", "😞", "😠", "😩", "πŸ˜”", "πŸ˜₯", "😭"]
emoji = emojis[random.randint(0, len(emojis) - 1)]
print(f"{emoji} nearest vaccine appointments are {dist} miles away")
print(f"(Waiting {INTERVAL}s to try again.)")
print("")
def check_for_vaccines(applicationId):
url = 'https://am-i-eligible.covid19vaccine.health.ny.gov/api/get-providers'
data = {
'address': ZIPCODE,
'applicationId': applicationId,
'dob': DOB,
'miles': 100,
}
req = request.Request(url, data=parse.urlencode(data).encode())
resp = request.urlopen(req)
body = resp.read().decode('utf-8')
vaccine_sites = json.loads(body)
sites_with_appointments = filter(is_available, vaccine_sites)
sorted_by_distance = sorted(sites_with_appointments, key=get_distance)
nearest_site = sorted_by_distance[0]
if get_distance(nearest_site) < THRESHOLD_IN_MILES:
print_success_message(nearest_site)
return nearest_site['3rdPartyURL']
print_failure_message(nearest_site)
def open_page_with_referer(url):
def interceptor(request):
request.headers['Referer'] = 'https://am-i-eligible.covid19vaccine.health.ny.gov/'
chrome_options = ChromeOptions()
chrome_options.add_argument("--incognito")
chrome_options.add_experimental_option("detach", True)
# For older ChromeDriver under version 79.0.3945.16
chrome_options.add_experimental_option(
"excludeSwitches", ["enable-automation"])
chrome_options.add_experimental_option('useAutomationExtension', False)
# For ChromeDriver version 79.0.3945.16 or over
chrome_options.add_argument(
'--disable-blink-features=AutomationControlled')
driver = webdriver.Chrome(chrome_options=chrome_options)
driver.request_interceptor = interceptor
driver.get(url)
input("Press Enter when finished in the browser.")
def main():
applicationId = run_prescreen()
while True:
success_url = check_for_vaccines(applicationId)
if success_url:
open_page_with_referer(success_url)
break
time.sleep(INTERVAL)
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment