├── capcha.png ├── appointmentImage.png ├── README.md └── vfsbot.py /capcha.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdudas/vfs-bot/HEAD/capcha.png -------------------------------------------------------------------------------- /appointmentImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdudas/vfs-bot/HEAD/appointmentImage.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vfs-bot 2 | ## Automate constantly checking for an appointment on VFS Global UKVI 3 | 4 | Hi! This is pretty hacky and not at all robust but this is the script I wrote so that my computer was able to text me when appointments became available on the VFS website. Before using it, you'll need to setup the following: 5 | - Selenium webdriver: https://www.selenium.dev (used to automate chrome) 6 | - Twilio free trial: https://www.twilio.com/ (api to build sms applications) 7 | - 2Capcha: https://2captcha.com/ (pay 50c per 1000 correctly solved capchas to login every time your session expires) 8 | 9 | The script you need to run is vfsbot.py. The rest should be explained in the comments!! 10 | 11 | The script may be buggy with regards to timeouts and such - let me know if it isn't working and i can try to figure it out! 12 | 13 | Good luck! 14 | -------------------------------------------------------------------------------- /vfsbot.py: -------------------------------------------------------------------------------- 1 | from selenium import webdriver 2 | import urllib 3 | from selenium.webdriver.common.by import By 4 | from selenium.webdriver.support.ui import WebDriverWait 5 | from selenium.webdriver.support import expected_conditions as EC 6 | import time 7 | from twilio.rest import Client 8 | from PIL import Image 9 | from selenium.webdriver.common.action_chains import ActionChains 10 | from selenium.webdriver.common.keys import Keys 11 | from datetime import datetime 12 | from twocaptcha import TwoCaptcha 13 | 14 | ## VFS login email 15 | email_str = 'VFS EMAIL USERNAME' 16 | 17 | ## VFS password 18 | pwd_str = 'VFS PORTAL PASSWORD' 19 | 20 | ## From Visa application - starts with GWF 21 | gwf_nbr = 'GWF NUMBER' 22 | 23 | ''' 24 | I used the Twilio python API to be able to text myself with appointment alerts! 25 | Twilio id, auth token, and twilio assigned phone number from Twilio free profile 26 | For help, check out https://www.twilio.com/docs/libraries/python. 27 | ''' 28 | account_sid = 'TWILIO SID' 29 | auth_token = 'TWILIO AUTH TOKEN' 30 | twilio_client = Client(account_sid, auth_token) 31 | twilio_phone = 'TWILIO PHONE NUMBER' 32 | ## Replace this here with the phone number you'd like to recieve SMS at 33 | my_phone = 'MY PHONE NUMBER' 34 | 35 | ''' 36 | 2Capcha is used to outsource solving the capchas - pay 50 cents / 1000 capchas solved. 37 | Load 50 cents for an account and insert your api key below. 38 | For help, check out https://github.com/athre0z/twocaptcha-api. 39 | ''' 40 | two_capcha_key = 'TWO CAPCHA API KEY' 41 | 42 | no_appts = 'there are no appointments available at your chosen Visa Application Centre' 43 | 44 | 45 | def log_msg(log, message): 46 | now = datetime.now() 47 | date_time = now.strftime("%m/%d/%Y, %H:%M:%S") 48 | log.write(date_time + " :: " + message + "\n") 49 | 50 | def login(browser, solver, log): 51 | ## Login Page 52 | browser.get(('https://myappointment.vfsglobal.co.uk/MyAppointment/?q=eDhlWnRkOWh4dVRlb2R3UEtiS0dSSUE0MnluVGN4aERMSk5MNHBWZEJNMjBCRVVyYTlZQ1IvL2JQYWRRQU1xczd1dWtvSVRFV0pidFh1NEpUK29FbFBOVStTQ1ZRT25QdTN2S1c3TU9DTllMdHpaclNSdDgxOUd0R1ZwTWJ0Vkc%3D')) 53 | browser.find_element_by_name('Email').send_keys(email_str) 54 | browser.find_element_by_name('Password').send_keys(pwd_str) 55 | ## Solves the CAPCHA 56 | capcha_img = browser.find_element_by_id('CaptchaImage') 57 | src = capcha_img.get_attribute('src') 58 | with open('capcha.png', 'wb') as file: 59 | file.write(capcha_img.screenshot_as_png) 60 | log_msg(log, "About to attempt to solve with 2Capcha.") 61 | capcha = solver.normal('capcha.png', minLength=5, maxLength=5) 62 | browser.find_element_by_name('CaptchaInputText').send_keys(capcha['code']) 63 | browser.find_element_by_class_name('btn-primary').click() 64 | log_msg(log, "Logged in with capcha " + capcha['code']) 65 | ## My applications page 66 | browser.find_element_by_name('Applicant.GwfNumber').send_keys(gwf_nbr) 67 | browser.find_element_by_name('Applicant.EmailAddress').send_keys(email_str) 68 | browser.find_element_by_name('submitbtn').click() 69 | 70 | def alert_for_appointment(browser, log): 71 | ## Returns a tuple, (Session expired, AppointmentAvailable) 72 | time.sleep(3) 73 | ## Switches over to the new tab with appointment availability. 74 | browser.switch_to_window(browser.window_handles[1]) 75 | browser.save_screenshot("appointmentImage.png") 76 | if (no_appts not in browser.page_source): 77 | if check_session_expired(browser, log): 78 | browser.close() 79 | browser.switch_to_window(browser.window_handles[0]) 80 | return (True, False) 81 | log_msg(log, "FOUND APPOINTMENTS!") 82 | browser.save_screenshot("appointmentImage.png") 83 | 84 | message = twilio_client.messages\ 85 | .create( 86 | body = 'THERE ARE APPOINTMENTS!! AHH!!', 87 | from_= twilio_phone, 88 | to= my_phone) 89 | return (check_session_expired(browser, log), True) 90 | else: 91 | log_msg(log, "No appointments available.") 92 | browser.close() 93 | browser.switch_to_window(browser.window_handles[0]) 94 | return (check_session_expired(browser, log), False) 95 | 96 | def check_appointment(browser, log): 97 | ## Returns a tuple, (Session expired, AppointmentAvailable) 98 | time.sleep(2) 99 | if check_session_expired(browser, log): 100 | return (True, False) 101 | browser.find_element_by_id('Documentupload').click() 102 | continue_btn = browser.find_element_by_id('btn_continue') 103 | ''' 104 | This is the action keys to right click on the continue button 105 | (to open the resulting page in a new tab). You'd need to change 106 | this action sequence if you're not on a Mac. 107 | ''' 108 | ActionChains(browser) \ 109 | .key_down(Keys.COMMAND) \ 110 | .click(continue_btn) \ 111 | .key_up(Keys.COMMAND) \ 112 | .perform() 113 | return alert_for_appointment(browser, log) 114 | 115 | def check_session_expired(browser, log): 116 | if 'Session timeout' in browser.page_source: 117 | log_msg(log, "Session expired.") 118 | return True 119 | return False 120 | 121 | def monitor_appointments(): 122 | ## Potentially change this path for wherever you have installed the chromedriver. 123 | browser = webdriver.Chrome(executable_path='/Users/sofia/dev/chromedriver') 124 | solver = TwoCaptcha(two_capcha_key) 125 | log = open('vfslog.txt', 'w+') 126 | appointments = False 127 | while True: 128 | login(browser, solver, log) 129 | while not appointments: 130 | (expired, appointments) = check_appointment(browser, log) 131 | if expired: 132 | break 133 | if appointments: 134 | return 135 | 136 | monitor_appointments() 137 | --------------------------------------------------------------------------------