Getting appointments using python

Retrieving GNIB appointments using python
published: (updated: )
by Harshvardhan J. Pandit
is part of: GNIB Appointments
GNIB python script visa

recap: In the previous posts, I managed to get the available appointments using javascript in the browser and through a bash script.

source: hosted on Github here

webapp: hosted on Heroku here shows available timings for GNIB and Visa appointments

Following up with a python based script that uses the requests library for the GET request and then parses the response to print available appointment times.


requests is a great library, which should be used more often by everyone, and one of the default installations on any system. The only reason it is not in the standard library is because there is no real need for it to be. Besides, by being outside the standard collection, it can iterate at a different pace. It makes requests really simple to read and make.

Specifying parameters becomes easy as they are delcared as a collection.

params = (
    ('openpage', ''),  # BLANK
    ('dt', ''),  # PARSED, but is always blank
    ('cat', 'Study'),  # Category
    ('sbcat', 'All'),  # Sub-Category
    ('typ', 'Renewal'),  # Type

Similarly, headers are a dict which allows us to specify the key: value pairs to be sent as headers.

headers = {
    'User-agent': 'script/python',
    'Accept': '*/*',  # CORS
    'Accept-Language': 'en-US,en;q=0.5',
    'Accept-Encoding': 'gzip, deflate, br',
    'Origin': 'null',  # CORS
    'Connection': 'keep-alive',

Making the request is calling the URL with the parameters and headers passed to it.

response = requests.get(
    + 'Website/AMSREG/AMSRegWeb.nsf/(getAppsNear)',
    headers=headers, params=params)

Dealing with SSL/HTTPS

As the SSL/HTTPS is an issue with the GNIB endpoints, I've stumbled upon the following solution. The requests library doesn't contain the particular cipher (or how the encryption is encoded). The particular cipher in use can be gleamed by studying the output of curl --verbose and then finding the corresponding entry in this table. For this particular case, it happened to be DES-CBC3-SHA.

# Looked up using curl --verbose
requests.packages.urllib3.util.ssl_.DEFAULT_CIPHERS += ':DES-CBC3-SHA'
# disable SSL warning


The response status code tells us whether the request was sucessfull or not. For this, check the value of response.status_code, which should be 2xx.

Parsing JSON

This part is pretty much simple as covered in the previous post. Some additional checks for error conditions out of the way, the appointments can be printed from the response.

# sanity checks
data = response.json()
# error key is set
if data.get('error', None) is not None:
    raise Exception('ERROR: %s' % data['error'])

# If there are no appointments, then the empty key is set
if data.get('empty', None) is not None:
    print('No appointments available')

# There are appointments, and are in the key 'slots'
data = data.get('slots', None)
if data is None:
    raise Exception('Data is NULL')

# This should not happen, but a good idea to check it anyway
if len(data) == 0:
    print('No appointments available')

# print appointments
# Format is:
# {
#   'id': 'str',
#   'time': 'str'
# }
for appointment in data:

Future Work

  • Online website that runs the script frequently and allows checking appointment timings online
  • Chrome extension that shows appointments