uxDaniel / visa_rescheduler

US VISA (ais.usvisa-info.com) appointment re-scheduler - Colombian adaptation
276 stars 236 forks source link

Exception occurred: Message: no such element: Unable to locate element #80

Open turik97 opened 6 months ago

turik97 commented 6 months ago

Available dates: 2026-07-30, 2026-07-31, 2026-08-04, 2026-08-06, 2026-08-07, 2026-08-10, 2026-08-11, 2026-08-12, 2026-08-13, 2026-08-14, 2026-08-17, 2026-08-18, 2026-08-20, 2026-08-21, 2026-08-24, 2026-08-25, 2026-08-26, 2026-08-27, 2026-08-28, 2026-08-31, Got time successfully! 2026-07-30 08:45 Exception occurred: Message: no such element: Unable to locate element: {"method":"css selector","selector":"[name="utf8"]"} (Session info: chrome=122.0.6261.112); For documentation on this error, please visit: https://www.selenium.dev/documentation/webdriver/troubleshooting/errors#no-such-element-exception Stacktrace: GetHandleVerifier [0x00007FF74E4FAD02+56930] (No symbol) [0x00007FF74E46F602] (No symbol) [0x00007FF74E3242E5] (No symbol) [0x00007FF74E3698ED] (No symbol) [0x00007FF74E369A2C] (No symbol) [0x00007FF74E3AA967] (No symbol) [0x00007FF74E38BCDF] (No symbol) [0x00007FF74E3A81E2] (No symbol) [0x00007FF74E38BA43] (No symbol) [0x00007FF74E35D438] (No symbol) [0x00007FF74E35E4D1] GetHandleVerifier [0x00007FF74E876F8D+3711213] GetHandleVerifier [0x00007FF74E8D04CD+4077101] GetHandleVerifier [0x00007FF74E8C865F+4044735] GetHandleVerifier [0x00007FF74E599736+706710] (No symbol) [0x00007FF74E47B8DF] (No symbol) [0x00007FF74E476AC4] (No symbol) [0x00007FF74E476C1C] (No symbol) [0x00007FF74E4668D4] BaseThreadInitThunk [0x00007FFA0E52257D+29] RtlUserThreadStart [0x00007FFA1040AA58+40]

Des-cloud commented 5 months ago

Delete the line "utf8" in data

turik97 commented 5 months ago

Ok people, since I had problems with this script since the beginning (First it was selenium issue for which I had to rewrite the driver location, then the config file was not getting parsed correctly, now the mentioned crash above which was solved by commenting the utf8 line as was advised) I want to post working as of 28/03/2024 version of visa.py which is running right now and was able to catch a slot within the specified range. (please note that this script works without the config.ini and you need to include your data in the provided variables)

turik97 commented 5 months ago

`import time import json import random import requests import configparser from datetime import datetime

from selenium import webdriver from selenium.webdriver.chrome.service import Service from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support.ui import WebDriverWait as Wait from selenium.webdriver.common.by import By from webdriver_manager.chrome import ChromeDriverManager

from sendgrid import SendGridAPIClient from sendgrid.helpers.mail import Mail

from embassy import *

config = configparser.ConfigParser() config.read('config.ini')

Personal Info:

Account and current appointment info from https://ais.usvisa-info.com

USERNAME = 'YOUR@EMAIL.COM' PASSWORD = 'YOUR PASSWORD'

Find SCHEDULE_ID in re-schedule page link:

https://ais.usvisa-info.com/en-am/niv/schedule/{SCHEDULE_ID}/appointment

SCHEDULE_ID = '56637598'

Target Period:

PRIOD_START = '2024-03-26' PRIOD_END = '2024-07-30'

Embassy Section:

YOUR_EMBASSY = 'en-ca-van' EMBASSY = Embassies[YOUR_EMBASSY][0] FACILITY_ID = Embassies[YOUR_EMBASSY][1] REGEX_CONTINUE = Embassies[YOUR_EMBASSY][2]

RETRY_TIME_L_BOUND = 20 RETRY_TIME_U_BOUND = 30 WORK_LIMIT_TIME = 4 WORK_COOLDOWN_TIME = 0.5 BAN_COOLDOWN_TIME = 0.2

CHROMEDRIVER

LOCAL_USE = True HUB_ADDRESS = 'http://localhost:9515/wd/hub'

Notification

PUSHOVER_TOKEN = '' PUSHOVER_USER = '' SENDGRID_API_KEY = '' PERSONAL_SITE_USER = '' PERSONAL_SITE_PASS = '' PUSH_TARGET_EMAIL = 'notifyemail@gmail.com' PERSONAL_PUSHER_URL = 'https://yoursite.com/api/esender.php'

Time Section:

minute = 60 # 60 seconds hour = 60 * minute # 3600 seconds

Time between steps (interactions with forms)

STEP_TIME = 0.5

SIGN_IN_LINK = f"https://ais.usvisa-info.com/{EMBASSY}/niv/users/sign_in" APPOINTMENT_URL = f"https://ais.usvisa-info.com/{EMBASSY}/niv/schedule/{SCHEDULE_ID}/appointment" DATE_URL = f"https://ais.usvisa-info.com/{EMBASSY}/niv/schedule/{SCHEDULE_ID}/appointment/days/{FACILITY_ID}.json?appointments[expedite]=false" TIME_URL = f"https://ais.usvisa-info.com/{EMBASSY}/niv/schedule/{SCHEDULE_ID}/appointment/times/{FACILITY_ID}.json?date=%s&appointments[expedite]=false" SIGN_OUT_LINK = f"https://ais.usvisa-info.com/{EMBASSY}/niv/users/sign_out"

JS_SCRIPT = ("var req = new XMLHttpRequest();" f"req.open('GET', '%s', false);" "req.setRequestHeader('Accept', 'application/json, text/javascript, /; q=0.01');" "req.setRequestHeader('X-Requested-With', 'XMLHttpRequest');" f"req.setRequestHeader('Cookie', '_yatri_session=%s');" "req.send(null);" "return req.responseText;")

def send_notification(title, msg): print(f"Sending notification!") if SENDGRID_API_KEY: message = Mail(from_email=USERNAME, to_emails=USERNAME, subject=msg, html_content=msg) try: sg = SendGridAPIClient(SENDGRID_API_KEY) response = sg.send(message) print(response.status_code) print(response.body) print(response.headers) except Exception as e: print(e.message) if PUSHOVER_TOKEN: url = "https://api.pushover.net/1/messages.json" data = { "token": PUSHOVER_TOKEN, "user": PUSHOVER_USER, "message": msg } requests.post(url, data) if PERSONAL_SITE_USER: url = PERSONAL_PUSHER_URL data = { "title": "VISA - " + str(title), "user": PERSONAL_SITE_USER, "pass": PERSONAL_SITE_PASS, "email": PUSH_TARGET_EMAIL, "msg": msg, } requests.post(url, data)

def auto_action(label, find_by, el_type, action, value, sleep_time=0): print("\t"+ label +":", end="")

Find Element By

match find_by.lower():
    case 'id':
        item = driver.find_element(By.ID, el_type)
    case 'name':
        item = driver.find_element(By.NAME, el_type)
    case 'class':
        item = driver.find_element(By.CLASS_NAME, el_type)
    case 'xpath':
        item = driver.find_element(By.XPATH, el_type)
    case _:
        return 0
# Do Action:
match action.lower():
    case 'send':
        item.send_keys(value)
    case 'click':
        item.click()
    case _:
        return 0
print("\t\tCheck!")
if sleep_time:
    time.sleep(sleep_time)

def start_process():

Bypass reCAPTCHA

driver.get(SIGN_IN_LINK)
time.sleep(STEP_TIME)
Wait(driver, 60).until(EC.presence_of_element_located((By.NAME, "commit")))
auto_action("Click bounce", "xpath", '//a[@class="down-arrow bounce"]', "click", "", STEP_TIME)
auto_action("Email", "id", "user_email", "send", USERNAME, STEP_TIME)
auto_action("Password", "id", "user_password", "send", PASSWORD, STEP_TIME)
auto_action("Privacy", "class", "icheckbox", "click", "", STEP_TIME)
auto_action("Enter Panel", "name", "commit", "click", "", STEP_TIME)
Wait(driver, 60).until(EC.presence_of_element_located((By.XPATH, "//a[contains(text(), '" + REGEX_CONTINUE + "')]")))
print("\n\tlogin successful!\n")

def reschedule(date): time = get_time(date) driver.get(APPOINTMENT_URL) headers = { "User-Agent": driver.execute_script("return navigator.userAgent;"), "Referer": APPOINTMENT_URL, "Cookie": "_yatri_session=" + driver.get_cookie("_yatri_session")["value"] } data = {

"utf8": driver.find_element(by=By.NAME, value='utf8').get_attribute('value'),

    "authenticity_token": driver.find_element(by=By.NAME, value='authenticity_token').get_attribute('value'),
    "confirmed_limit_message": driver.find_element(by=By.NAME, value='confirmed_limit_message').get_attribute('value'),
    "use_consulate_appointment_capacity": driver.find_element(by=By.NAME, value='use_consulate_appointment_capacity').get_attribute('value'),
    "appointments[consulate_appointment][facility_id]": FACILITY_ID,
    "appointments[consulate_appointment][date]": date,
    "appointments[consulate_appointment][time]": time,
}
r = requests.post(APPOINTMENT_URL, headers=headers, data=data)
if(r.text.find('Successfully Scheduled') != -1):
    title = "SUCCESS"
    msg = f"Rescheduled Successfully! {date} {time}"
else:
    title = "FAIL"
    msg = f"Reschedule Failed!!! {date} {time}"
return [title, msg]

def get_date():

Requesting to get the whole available dates

session = driver.get_cookie("_yatri_session")["value"]
script = JS_SCRIPT % (str(DATE_URL), session)
content = driver.execute_script(script)
return json.loads(content)

def get_time(date): time_url = TIME_URL % date session = driver.get_cookie("_yatri_session")["value"] script = JS_SCRIPT % (str(time_url), session) content = driver.execute_script(script) data = json.loads(content) time = data.get("available_times")[-1] print(f"Got time successfully! {date} {time}") return time

def is_logged_in(): content = driver.page_source if(content.find("error") != -1): return False return True

def get_available_date(dates):

Evaluation of different available dates

def is_in_period(date, PSD, PED):
    new_date = datetime.strptime(date, "%Y-%m-%d")
    result = ( PED > new_date and new_date > PSD )
    # print(f'{new_date.date()} : {result}', end=", ")
    return result

PED = datetime.strptime(PRIOD_END, "%Y-%m-%d")
PSD = datetime.strptime(PRIOD_START, "%Y-%m-%d")
for d in dates:
    date = d.get('date')
    if is_in_period(date, PSD, PED):
        return date
print(f"\n\nNo available dates between ({PSD.date()}) and ({PED.date()})!")

def info_logger(file_path, log):

file_path: e.g. "log.txt"

with open(file_path, "a") as file:
    file.write(str(datetime.now().time()) + ":\n" + log + "\n")

if LOCAL_USE: options = webdriver.ChromeOptions() options.add_experimental_option('excludeSwitches', ['enable-logging']) driver = webdriver.Chrome(options=options) else: driver = webdriver.Remote(command_executor=HUB_ADDRESS, options=webdriver.ChromeOptions())

if name == "main": first_loop = True while 1: LOG_FILENAME = "log" + str(datetime.now().date()) + ".txt" if first_loop: t0 = time.time() total_time = 0 Req_count = 0 start_process() first_loop = False Req_count += 1 try: msg = "-" * 60 + f"\nRequest count: {Req_count}, Log time: {datetime.today()}\n" print(msg) info_logger(LOG_FILE_NAME, msg) dates = get_date() if not dates:

Ban Situation

            msg = f"List is empty, Probabely banned!\n\tSleep for {BAN_COOLDOWN_TIME} hours!\n"
            print(msg)
            info_logger(LOG_FILE_NAME, msg)
            send_notification("BAN", msg)
            driver.get(SIGN_OUT_LINK)
            time.sleep(BAN_COOLDOWN_TIME * hour)
            first_loop = True
        else:
            # Print Available dates:
            msg = ""
            for d in dates:
                msg = msg + "%s" % (d.get('date')) + ", "
            msg = "Available dates:\n"+ msg
            print(msg)
            info_logger(LOG_FILE_NAME, msg)
            date = get_available_date(dates)
            if date:
                # A good date to schedule for
                END_MSG_TITLE, msg = reschedule(date)
                break
            RETRY_WAIT_TIME = random.randint(RETRY_TIME_L_BOUND, RETRY_TIME_U_BOUND)
            t1 = time.time()
            total_time = t1 - t0
            msg = "\nWorking Time:  ~ {:.2f} minutes".format(total_time/minute)
            print(msg)
            info_logger(LOG_FILE_NAME, msg)
            if total_time > WORK_LIMIT_TIME * hour:
                # Let program rest a little
                send_notification("REST", f"Break-time after {WORK_LIMIT_TIME} hours | Repeated {Req_count} times")
                driver.get(SIGN_OUT_LINK)
                time.sleep(WORK_COOLDOWN_TIME * hour)
                first_loop = True
            else:
                msg = "Retry Wait Time: "+ str(RETRY_WAIT_TIME)+ " seconds"
                print(msg)
                info_logger(LOG_FILE_NAME, msg)
                time.sleep(RETRY_WAIT_TIME)
    except Exception as e:
        # Log the exception and continue
        error_msg = f"Exception occurred: {str(e)}\n"
        print(error_msg)

print(msg) info_logger(LOG_FILE_NAME, msg) send_notification(END_MSG_TITLE, msg) driver.get(SIGN_OUT_LINK) driver.stop_client() driver.quit() `

miguela1245 commented 5 months ago

línea utf8

Hi, could you help me by explaining what exactly you mean by the utf8 line? Thanks

nystateomind commented 4 months ago

@turik97 could you please share your script as an attachment? I tried to use the code you pasted but formatting got messed up

EpiphoneLP commented 2 months ago

`import time import json import random import requests import configparser from datetime import datetime

from selenium import webdriver from selenium.webdriver.chrome.service import Service from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support.ui import WebDriverWait as Wait from selenium.webdriver.common.by import By from webdriver_manager.chrome import ChromeDriverManager

from sendgrid import SendGridAPIClient from sendgrid.helpers.mail import Mail

from embassy import *

config = configparser.ConfigParser() config.read('config.ini')

Personal Info:

Account and current appointment info from https://ais.usvisa-info.com

USERNAME = 'YOUR@EMAIL.COM' PASSWORD = 'YOUR PASSWORD'

Find SCHEDULE_ID in re-schedule page link:

https://ais.usvisa-info.com/en-am/niv/schedule/{SCHEDULE_ID}/appointment

SCHEDULE_ID = '56637598'

Target Period:

PRIOD_START = '2024-03-26' PRIOD_END = '2024-07-30'

Embassy Section:

YOUR_EMBASSY = 'en-ca-van' EMBASSY = Embassies[YOUR_EMBASSY][0] FACILITY_ID = Embassies[YOUR_EMBASSY][1] REGEX_CONTINUE = Embassies[YOUR_EMBASSY][2]

RETRY_TIME_L_BOUND = 20 RETRY_TIME_U_BOUND = 30 WORK_LIMIT_TIME = 4 WORK_COOLDOWN_TIME = 0.5 BAN_COOLDOWN_TIME = 0.2

CHROMEDRIVER

LOCAL_USE = True HUB_ADDRESS = 'http://localhost:9515/wd/hub'

Notification

PUSHOVER_TOKEN = '' PUSHOVER_USER = '' SENDGRID_API_KEY = '' PERSONAL_SITEUSER = '' PERSONAL_SITE_PASS = '_' PUSH_TARGET_EMAIL = 'notifyemail@gmail.com' PERSONAL_PUSHER_URL = 'https://yoursite.com/api/esender.php'

Time Section:

minute = 60 # 60 seconds hour = 60 * minute # 3600 seconds

Time between steps (interactions with forms)

STEP_TIME = 0.5

SIGN_IN_LINK = f"https://ais.usvisa-info.com/{EMBASSY}/niv/users/sign_in" APPOINTMENT_URL = f"https://ais.usvisa-info.com/{EMBASSY}/niv/schedule/{SCHEDULE_ID}/appointment" DATE_URL = f"https://ais.usvisa-info.com/{EMBASSY}/niv/schedule/{SCHEDULE_ID}/appointment/days/{FACILITY_ID}.json?appointments[expedite]=false" TIME_URL = f"https://ais.usvisa-info.com/{EMBASSY}/niv/schedule/{SCHEDULE_ID}/appointment/times/{FACILITY_ID}.json?date=%s&appointments[expedite]=false" SIGN_OUT_LINK = f"https://ais.usvisa-info.com/{EMBASSY}/niv/users/sign_out"

JSSCRIPT = ("var req = new XMLHttpRequest();" f"req.open('GET', '%s', false);" "req.setRequestHeader('Accept', 'application/json, text/javascript, /_; q=0.01');" "req.setRequestHeader('X-Requested-With', 'XMLHttpRequest');" f"req.setRequestHeader('Cookie', '_yatri_session=%s');" "req.send(null);" "return req.responseText;")

def send_notification(title, msg): print(f"Sending notification!") if SENDGRID_API_KEY: message = Mail(from_email=USERNAME, to_emails=USERNAME, subject=msg, html_content=msg) try: sg = SendGridAPIClient(SENDGRID_API_KEY) response = sg.send(message) print(response.status_code) print(response.body) print(response.headers) except Exception as e: print(e.message) if PUSHOVER_TOKEN: url = "https://api.pushover.net/1/messages.json" data = { "token": PUSHOVER_TOKEN, "user": PUSHOVER_USER, "message": msg } requests.post(url, data) if PERSONAL_SITE_USER: url = PERSONAL_PUSHER_URL data = { "title": "VISA - " + str(title), "user": PERSONAL_SITE_USER, "pass": PERSONAL_SITE_PASS, "email": PUSH_TARGET_EMAIL, "msg": msg, } requests.post(url, data)

def auto_action(label, find_by, el_type, action, value, sleep_time=0): print("\t"+ label +":", end="") # Find Element By match find_by.lower(): case 'id': item = driver.find_element(By.ID, el_type) case 'name': item = driver.find_element(By.NAME, el_type) case 'class': item = driver.find_element(By.CLASS_NAME, el_type) case 'xpath': item = driver.find_element(By.XPATH, eltype) case : return 0 # Do Action: match action.lower(): case 'send': item.sendkeys(value) case 'click': item.click() case : return 0 print("\t\tCheck!") if sleep_time: time.sleep(sleep_time)

def start_process(): # Bypass reCAPTCHA driver.get(SIGN_IN_LINK) time.sleep(STEP_TIME) Wait(driver, 60).until(EC.presence_of_element_located((By.NAME, "commit"))) auto_action("Click bounce", "xpath", '//a[@Class="down-arrow bounce"]', "click", "", STEP_TIME) auto_action("Email", "id", "user_email", "send", USERNAME, STEP_TIME) auto_action("Password", "id", "user_password", "send", PASSWORD, STEP_TIME) auto_action("Privacy", "class", "icheckbox", "click", "", STEP_TIME) auto_action("Enter Panel", "name", "commit", "click", "", STEP_TIME) Wait(driver, 60).until(EC.presence_of_element_located((By.XPATH, "//a[contains(text(), '" + REGEX_CONTINUE + "')]"))) print("\n\tlogin successful!\n")

def reschedule(date): time = get_time(date) driver.get(APPOINTMENT_URL) headers = { "User-Agent": driver.execute_script("return navigator.userAgent;"), "Referer": APPOINTMENT_URL, "Cookie": "_yatri_session=" + driver.get_cookie("_yatri_session")["value"] } data = { #"utf8": driver.find_element(by=By.NAME, value='utf8').get_attribute('value'), "authenticity_token": driver.find_element(by=By.NAME, value='authenticity_token').get_attribute('value'), "confirmed_limit_message": driver.find_element(by=By.NAME, value='confirmed_limit_message').get_attribute('value'), "use_consulate_appointment_capacity": driver.find_element(by=By.NAME, value='use_consulate_appointment_capacity').get_attribute('value'), "appointments[consulate_appointment][facility_id]": FACILITY_ID, "appointments[consulate_appointment][date]": date, "appointments[consulate_appointment][time]": time, } r = requests.post(APPOINTMENT_URL, headers=headers, data=data) if(r.text.find('Successfully Scheduled') != -1): title = "SUCCESS" msg = f"Rescheduled Successfully! {date} {time}" else: title = "FAIL" msg = f"Reschedule Failed!!! {date} {time}" return [title, msg]

def get_date(): # Requesting to get the whole available dates session = driver.get_cookie("_yatri_session")["value"] script = JS_SCRIPT % (str(DATE_URL), session) content = driver.execute_script(script) return json.loads(content)

def get_time(date): time_url = TIME_URL % date session = driver.get_cookie("_yatri_session")["value"] script = JS_SCRIPT % (str(time_url), session) content = driver.execute_script(script) data = json.loads(content) time = data.get("available_times")[-1] print(f"Got time successfully! {date} {time}") return time

def is_logged_in(): content = driver.page_source if(content.find("error") != -1): return False return True

def get_available_date(dates): # Evaluation of different available dates def is_in_period(date, PSD, PED): new_date = datetime.strptime(date, "%Y-%m-%d") result = ( PED > new_date and new_date > PSD ) # print(f'{new_date.date()} : {result}', end=", ") return result

PED = datetime.strptime(PRIOD_END, "%Y-%m-%d")
PSD = datetime.strptime(PRIOD_START, "%Y-%m-%d")
for d in dates:
    date = d.get('date')
    if is_in_period(date, PSD, PED):
        return date
print(f"\n\nNo available dates between ({PSD.date()}) and ({PED.date()})!")

def info_logger(file_path, log): # file_path: e.g. "log.txt" with open(file_path, "a") as file: file.write(str(datetime.now().time()) + ":\n" + log + "\n")

if LOCAL_USE: options = webdriver.ChromeOptions() options.add_experimental_option('excludeSwitches', ['enable-logging']) driver = webdriver.Chrome(options=options) else: driver = webdriver.Remote(command_executor=HUB_ADDRESS, options=webdriver.ChromeOptions())

if name == "main": first_loop = True while 1: LOG_FILENAME = "log" + str(datetime.now().date()) + ".txt" if first_loop: t0 = time.time() total_time = 0 Req_count = 0 start_process() first_loop = False Req_count += 1 try: msg = "-" 60 + f"\nRequest count: {Req_count}, Log time: {datetime.today()}\n" print(msg) info_logger(LOG_FILE_NAME, msg) dates = get_date() if not dates: # Ban Situation msg = f"List is empty, Probabely banned!\n\tSleep for {BAN_COOLDOWN_TIME} hours!\n" print(msg) info_logger(LOG_FILE_NAME, msg) send_notification("BAN", msg) driver.get(SIGN_OUT_LINK) time.sleep(BAN_COOLDOWN_TIME hour) first_loop = True else: # Print Available dates: msg = "" for d in dates: msg = msg + "%s" % (d.get('date')) + ", " msg = "Available dates:\n"+ msg print(msg) info_logger(LOG_FILE_NAME, msg) date = get_available_date(dates) if date: # A good date to schedule for END_MSG_TITLE, msg = reschedule(date) break RETRY_WAIT_TIME = random.randint(RETRY_TIME_L_BOUND, RETRY_TIME_U_BOUND) t1 = time.time() total_time = t1 - t0 msg = "\nWorking Time: ~ {:.2f} minutes".format(total_time/minute) print(msg) info_logger(LOG_FILE_NAME, msg) if total_time > WORK_LIMIT_TIME hour: # Let program rest a little send_notification("REST", f"Break-time after {WORK_LIMIT_TIME} hours | Repeated {Req_count} times") driver.get(SIGN_OUT_LINK) time.sleep(WORK_COOLDOWN_TIME hour) first_loop = True else: msg = "Retry Wait Time: "+ str(RETRY_WAIT_TIME)+ " seconds" print(msg) info_logger(LOG_FILE_NAME, msg) time.sleep(RETRY_WAIT_TIME) except Exception as e: # Log the exception and continue error_msg = f"Exception occurred: {str(e)}\n" print(error_msg)

print(msg) info_logger(LOG_FILE_NAME, msg) send_notification(END_MSG_TITLE, msg) driver.get(SIGN_OUT_LINK) driver.stop_client() driver.quit() `

`import time import json import random import requests import configparser from datetime import datetime

from selenium import webdriver from selenium.webdriver.chrome.service import Service from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support.ui import WebDriverWait as Wait from selenium.webdriver.common.by import By from webdriver_manager.chrome import ChromeDriverManager

from sendgrid import SendGridAPIClient from sendgrid.helpers.mail import Mail

from embassy import *

config = configparser.ConfigParser() config.read('config.ini')

Personal Info:

Account and current appointment info from https://ais.usvisa-info.com

USERNAME = 'YOUR@EMAIL.COM' PASSWORD = 'YOUR PASSWORD'

Find SCHEDULE_ID in re-schedule page link:

https://ais.usvisa-info.com/en-am/niv/schedule/{SCHEDULE_ID}/appointment

SCHEDULE_ID = '56637598'

Target Period:

PRIOD_START = '2024-03-26' PRIOD_END = '2024-07-30'

Embassy Section:

YOUR_EMBASSY = 'en-ca-van' EMBASSY = Embassies[YOUR_EMBASSY][0] FACILITY_ID = Embassies[YOUR_EMBASSY][1] REGEX_CONTINUE = Embassies[YOUR_EMBASSY][2]

RETRY_TIME_L_BOUND = 20 RETRY_TIME_U_BOUND = 30 WORK_LIMIT_TIME = 4 WORK_COOLDOWN_TIME = 0.5 BAN_COOLDOWN_TIME = 0.2

CHROMEDRIVER

LOCAL_USE = True HUB_ADDRESS = 'http://localhost:9515/wd/hub'

Notification

PUSHOVER_TOKEN = '' PUSHOVER_USER = '' SENDGRID_API_KEY = '' PERSONAL_SITEUSER = '' PERSONAL_SITE_PASS = '_' PUSH_TARGET_EMAIL = 'notifyemail@gmail.com' PERSONAL_PUSHER_URL = 'https://yoursite.com/api/esender.php'

Time Section:

minute = 60 # 60 seconds hour = 60 * minute # 3600 seconds

Time between steps (interactions with forms)

STEP_TIME = 0.5

SIGN_IN_LINK = f"https://ais.usvisa-info.com/{EMBASSY}/niv/users/sign_in" APPOINTMENT_URL = f"https://ais.usvisa-info.com/{EMBASSY}/niv/schedule/{SCHEDULE_ID}/appointment" DATE_URL = f"https://ais.usvisa-info.com/{EMBASSY}/niv/schedule/{SCHEDULE_ID}/appointment/days/{FACILITY_ID}.json?appointments[expedite]=false" TIME_URL = f"https://ais.usvisa-info.com/{EMBASSY}/niv/schedule/{SCHEDULE_ID}/appointment/times/{FACILITY_ID}.json?date=%s&appointments[expedite]=false" SIGN_OUT_LINK = f"https://ais.usvisa-info.com/{EMBASSY}/niv/users/sign_out"

JSSCRIPT = ("var req = new XMLHttpRequest();" f"req.open('GET', '%s', false);" "req.setRequestHeader('Accept', 'application/json, text/javascript, /_; q=0.01');" "req.setRequestHeader('X-Requested-With', 'XMLHttpRequest');" f"req.setRequestHeader('Cookie', '_yatri_session=%s');" "req.send(null);" "return req.responseText;")

def send_notification(title, msg): print(f"Sending notification!") if SENDGRID_API_KEY: message = Mail(from_email=USERNAME, to_emails=USERNAME, subject=msg, html_content=msg) try: sg = SendGridAPIClient(SENDGRID_API_KEY) response = sg.send(message) print(response.status_code) print(response.body) print(response.headers) except Exception as e: print(e.message) if PUSHOVER_TOKEN: url = "https://api.pushover.net/1/messages.json" data = { "token": PUSHOVER_TOKEN, "user": PUSHOVER_USER, "message": msg } requests.post(url, data) if PERSONAL_SITE_USER: url = PERSONAL_PUSHER_URL data = { "title": "VISA - " + str(title), "user": PERSONAL_SITE_USER, "pass": PERSONAL_SITE_PASS, "email": PUSH_TARGET_EMAIL, "msg": msg, } requests.post(url, data)

def auto_action(label, find_by, el_type, action, value, sleep_time=0): print("\t"+ label +":", end="") # Find Element By match find_by.lower(): case 'id': item = driver.find_element(By.ID, el_type) case 'name': item = driver.find_element(By.NAME, el_type) case 'class': item = driver.find_element(By.CLASS_NAME, el_type) case 'xpath': item = driver.find_element(By.XPATH, eltype) case : return 0 # Do Action: match action.lower(): case 'send': item.sendkeys(value) case 'click': item.click() case : return 0 print("\t\tCheck!") if sleep_time: time.sleep(sleep_time)

def start_process(): # Bypass reCAPTCHA driver.get(SIGN_IN_LINK) time.sleep(STEP_TIME) Wait(driver, 60).until(EC.presence_of_element_located((By.NAME, "commit"))) auto_action("Click bounce", "xpath", '//a[@Class="down-arrow bounce"]', "click", "", STEP_TIME) auto_action("Email", "id", "user_email", "send", USERNAME, STEP_TIME) auto_action("Password", "id", "user_password", "send", PASSWORD, STEP_TIME) auto_action("Privacy", "class", "icheckbox", "click", "", STEP_TIME) auto_action("Enter Panel", "name", "commit", "click", "", STEP_TIME) Wait(driver, 60).until(EC.presence_of_element_located((By.XPATH, "//a[contains(text(), '" + REGEX_CONTINUE + "')]"))) print("\n\tlogin successful!\n")

def reschedule(date): time = get_time(date) driver.get(APPOINTMENT_URL) headers = { "User-Agent": driver.execute_script("return navigator.userAgent;"), "Referer": APPOINTMENT_URL, "Cookie": "_yatri_session=" + driver.get_cookie("_yatri_session")["value"] } data = { #"utf8": driver.find_element(by=By.NAME, value='utf8').get_attribute('value'), "authenticity_token": driver.find_element(by=By.NAME, value='authenticity_token').get_attribute('value'), "confirmed_limit_message": driver.find_element(by=By.NAME, value='confirmed_limit_message').get_attribute('value'), "use_consulate_appointment_capacity": driver.find_element(by=By.NAME, value='use_consulate_appointment_capacity').get_attribute('value'), "appointments[consulate_appointment][facility_id]": FACILITY_ID, "appointments[consulate_appointment][date]": date, "appointments[consulate_appointment][time]": time, } r = requests.post(APPOINTMENT_URL, headers=headers, data=data) if(r.text.find('Successfully Scheduled') != -1): title = "SUCCESS" msg = f"Rescheduled Successfully! {date} {time}" else: title = "FAIL" msg = f"Reschedule Failed!!! {date} {time}" return [title, msg]

def get_date(): # Requesting to get the whole available dates session = driver.get_cookie("_yatri_session")["value"] script = JS_SCRIPT % (str(DATE_URL), session) content = driver.execute_script(script) return json.loads(content)

def get_time(date): time_url = TIME_URL % date session = driver.get_cookie("_yatri_session")["value"] script = JS_SCRIPT % (str(time_url), session) content = driver.execute_script(script) data = json.loads(content) time = data.get("available_times")[-1] print(f"Got time successfully! {date} {time}") return time

def is_logged_in(): content = driver.page_source if(content.find("error") != -1): return False return True

def get_available_date(dates): # Evaluation of different available dates def is_in_period(date, PSD, PED): new_date = datetime.strptime(date, "%Y-%m-%d") result = ( PED > new_date and new_date > PSD ) # print(f'{new_date.date()} : {result}', end=", ") return result

PED = datetime.strptime(PRIOD_END, "%Y-%m-%d")
PSD = datetime.strptime(PRIOD_START, "%Y-%m-%d")
for d in dates:
    date = d.get('date')
    if is_in_period(date, PSD, PED):
        return date
print(f"\n\nNo available dates between ({PSD.date()}) and ({PED.date()})!")

def info_logger(file_path, log): # file_path: e.g. "log.txt" with open(file_path, "a") as file: file.write(str(datetime.now().time()) + ":\n" + log + "\n")

if LOCAL_USE: options = webdriver.ChromeOptions() options.add_experimental_option('excludeSwitches', ['enable-logging']) driver = webdriver.Chrome(options=options) else: driver = webdriver.Remote(command_executor=HUB_ADDRESS, options=webdriver.ChromeOptions())

if name == "main": first_loop = True while 1: LOG_FILENAME = "log" + str(datetime.now().date()) + ".txt" if first_loop: t0 = time.time() total_time = 0 Req_count = 0 start_process() first_loop = False Req_count += 1 try: msg = "-" 60 + f"\nRequest count: {Req_count}, Log time: {datetime.today()}\n" print(msg) info_logger(LOG_FILE_NAME, msg) dates = get_date() if not dates: # Ban Situation msg = f"List is empty, Probabely banned!\n\tSleep for {BAN_COOLDOWN_TIME} hours!\n" print(msg) info_logger(LOG_FILE_NAME, msg) send_notification("BAN", msg) driver.get(SIGN_OUT_LINK) time.sleep(BAN_COOLDOWN_TIME hour) first_loop = True else: # Print Available dates: msg = "" for d in dates: msg = msg + "%s" % (d.get('date')) + ", " msg = "Available dates:\n"+ msg print(msg) info_logger(LOG_FILE_NAME, msg) date = get_available_date(dates) if date: # A good date to schedule for END_MSG_TITLE, msg = reschedule(date) break RETRY_WAIT_TIME = random.randint(RETRY_TIME_L_BOUND, RETRY_TIME_U_BOUND) t1 = time.time() total_time = t1 - t0 msg = "\nWorking Time: ~ {:.2f} minutes".format(total_time/minute) print(msg) info_logger(LOG_FILE_NAME, msg) if total_time > WORK_LIMIT_TIME hour: # Let program rest a little send_notification("REST", f"Break-time after {WORK_LIMIT_TIME} hours | Repeated {Req_count} times") driver.get(SIGN_OUT_LINK) time.sleep(WORK_COOLDOWN_TIME hour) first_loop = True else: msg = "Retry Wait Time: "+ str(RETRY_WAIT_TIME)+ " seconds" print(msg) info_logger(LOG_FILE_NAME, msg) time.sleep(RETRY_WAIT_TIME) except Exception as e: # Log the exception and continue error_msg = f"Exception occurred: {str(e)}\n" print(error_msg)

print(msg) info_logger(LOG_FILE_NAME, msg) send_notification(END_MSG_TITLE, msg) driver.get(SIGN_OUT_LINK) driver.stop_client() driver.quit() `

could you please share your script as an attachment? formatting got messed up