Skip to content

Instantly share code, notes, and snippets.

@Svision
Forked from yaojialyu/visa.py
Last active April 12, 2024 02:42
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save Svision/04202d93fb32d14f00ac746879820722 to your computer and use it in GitHub Desktop.
Save Svision/04202d93fb32d14f00ac746879820722 to your computer and use it in GitHub Desktop.
ais usvisa reschedule
import logging
import time
import json
import random
from datetime import datetime
import requests
from selenium import webdriver
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
USERNAME = '<username>'
PASSWORD = '<pwd>'
SCHEDULE = '<schedule number>'
COUNTRY_CODE = '<country code>' # en-ca for Canada-English
FACILITY_ID = '<facility id>' # 94 for Toronto (others please use F12 to check)
MY_SCHEDULE_DATE = "<your already scheduled date>" # 2022-05-16 WARNING: DON'T CHOOSE DATE LATER THAN ACTUAL SCHEDULED
MY_CONDITION = lambda month, day: True # MY_CONDITION = lambda month, day: int(month) == 11 and int(day) >= 5
SLEEP_TIME = 60 # recheck time interval
DATE_URL = f"https://ais.usvisa-info.com/{COUNTRY_CODE}/niv/schedule/{SCHEDULE}/appointment/days/{FACILITY_ID}.json?appointments[expedite]=false"
TIME_URL = f"https://ais.usvisa-info.com/{COUNTRY_CODE}/niv/schedule/{SCHEDULE}/appointment/times/{FACILITY_ID}.json?date=%%s&appointments[expedite]=false"
APPOINTMENT_URL = f"https://ais.usvisa-info.com/{COUNTRY_CODE}/niv/schedule/{SCHEDULE}/appointment"
EXIT = False
driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()))
logging.basicConfig(level=logging.INFO, filename="visa.log", filemode="a+", format="%(asctime)-15s %(levelname)-8s %(message)s")
def login():
# Bypass reCAPTCHA
driver.get(f"https://ais.usvisa-info.com/{COUNTRY_CODE}/niv")
time.sleep(1)
a = driver.find_element(By.XPATH, value='//a[@class="down-arrow bounce"]')
a.click()
time.sleep(1)
logging.info("start sign")
href = driver.find_element(By.XPATH, value='//*[@id="header"]/nav/div[2]/div[1]/ul/li[3]/a')
href.click()
time.sleep(1)
WebDriverWait(driver, 60).until(EC.presence_of_element_located((By.NAME, "commit")))
logging.info("click bounce")
a = driver.find_element(By.XPATH, value='//a[@class="down-arrow bounce"]')
a.click()
time.sleep(1)
do_login_action()
def do_login_action():
logging.info("input email")
user = driver.find_element(By.ID, value='user_email')
user.send_keys(USERNAME)
time.sleep(random.randint(1, 3))
logging.info("input pwd")
pw = driver.find_element(By.ID, value='user_password')
pw.send_keys(PASSWORD)
time.sleep(random.randint(1, 3))
logging.info("click privacy")
box = driver.find_element(By.CLASS_NAME, value='icheckbox')
box .click()
time.sleep(random.randint(1, 3))
logging.info("commit")
btn = driver.find_element(By.NAME, value='commit')
btn.click()
time.sleep(random.randint(1, 3))
try:
WebDriverWait(driver, 15).until(EC.presence_of_element_located((By.XPATH, "//a[contains(text(),'Continue')]")))
logging.info("Login successfully!")
except TimeoutError:
logging.warning("Login failed!")
login()
def get_date():
driver.get(DATE_URL)
if not is_logined():
login()
return get_date()
else:
content = driver.find_element(By.TAG_NAME, value='pre').text
date = json.loads(content)
return date
def get_time(date):
time_url = TIME_URL % date
driver.get(time_url)
content = driver.find_element(By.TAG_NAME, value='pre').text
data = json.loads(content)
time = data.get("available_times")[-1]
logging.info("Get time successfully!")
return time
# BUGGY
def reschedule(date):
global EXIT
logging.info("Start Reschedule")
time = get_time(date)
driver.get(APPOINTMENT_URL)
data = {
"utf8": driver.find_element(By.NAME, value='utf8').get_attribute('value'),
"authenticity_token": driver.find_element(By.NAME, value='authenticity_token').get_attribute('value'),
"confirmed_limit_message": driver.find_element(By.NAME, value='confirmed_limit_message').get_attribute('value'),
"use_consulate_appointment_capacity": driver.find_element(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,
}
headers = {
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36",
"Referer": APPOINTMENT_URL,
"Cookie": "_yatri_session=" + driver.get_cookie("_yatri_session")["value"]
}
r = requests.post(APPOINTMENT_URL, headers=headers, data=data)
if(r.text.find('Successfully Scheduled') != -1):
logging.info("Successfully Rescheduled")
EXIT = True
else:
logging.warning("ReScheduled Fail")
logging.warning("POST REQUEST:\n")
logging.warning(headers)
logging.warning(data)
logging.warning("")
def is_logined():
content = driver.page_source
if(content.find("error") != -1):
return False
return True
def print_date(dates):
for d in dates:
logging.info("%s \t business_day: %s" %(d.get('date'), d.get('business_day')))
logging.info("\n")
last_seen = None
def get_available_date(dates):
global last_seen
def is_earlier(date):
return datetime.strptime(MY_SCHEDULE_DATE, "%Y-%m-%d") > datetime.strptime(date, "%Y-%m-%d")
for d in dates:
date = d.get('date')
if is_earlier(date) and date != last_seen:
_, month, day = date.split('-')
if(MY_CONDITION(month, day)):
last_seen = date
return date
if __name__ == "__main__":
login()
retry_count = 0
while 1:
if retry_count > 6:
break
try:
logging.info(datetime.today())
logging.info("------------------")
dates = get_date()[:5]
print_date(dates)
date = get_available_date(dates)
if date:
reschedule(date)
if(EXIT):
break
time.sleep(SLEEP_TIME)
except:
retry_count += 1
time.sleep(60*5)
@vitru
Copy link

vitru commented Mar 16, 2022

Did you get the reschedule method to work? Looks like it's missing the g-recaptcha-response parameter. I was thinking of rewriting this method using selenium automation instead.
Also, do you notice requests being throttled and start getting empty array from DATE_URL? I ended up increasing SLEEP_TIME to 5 min - this gives me about 4 hours of consistent API calls and then again start getting empty values for a while.

@Svision
Copy link
Author

Svision commented Mar 16, 2022

Did you get the reschedule method to work? Looks like it's missing the g-recaptcha-response parameter. I was thinking of rewriting this method using selenium automation instead. Also, do you notice requests being throttled and start getting empty array from DATE_URL? I ended up increasing SLEEP_TIME to 5 min - this gives me about 4 hours of consistent API calls and then again start getting empty values for a while.

Yes, I noticed it will get empty for a while. I am logging the output in my version, and it seems 60 SLEEP_TIME gives about 3 hours of consistent API calls. I think increasing to 5mins will be too conservative to get available space. Regarding the reschedule, it is not working now. I am trying to capture the POST data it was sending while rescheduling and then modify the reschedule method accordingly. But I do not have the chance to capture it at this moment. Do you have any suggestions?

@ADHDvir
Copy link

ADHDvir commented Mar 22, 2022

When you are using the reschedule method, what response do you get?
I got <429 response> "a padding to disable MSIE and Chrome friendly error page" which is wierd because it's about too much requests and i only use POST once...
Also, for how long do you wait until you stop getting the empty arrays?

@ADHDvir
Copy link

ADHDvir commented Apr 3, 2022

@PharAcc The thing is that I get this error on the first POST...and i wait 61 seconds between each call. In the end I used selinium to schedule an appointment so I managed to avoid the problem...

@betoxhj
Copy link

betoxhj commented Apr 26, 2022

Hi @ADHDvir could you please share the solution you found for the scheduled , I'm still stuck at that point. thanks in advance

@dresansol
Copy link

Hello, I tested it with the Colombia country code, I had an error with the get_time method but I fixed, I have not yet been able to test the reschedule method, there aren't available days, but I have a question, Does this code contemplates the scheduling of the consular appointment and the appointment of the ASC? I

@duo-fu-git
Copy link

@ADHDvir Could you kindly share the selenium solution?

@dresansol
Copy link

You will always get the empty array, is a security configuration, but you can set on your code a sleep function and try later. I did that and I always try again after 1 hour.

@dresansol
Copy link

I do the same, I think is the only way for keep the checking stable.

@slhsxcmy
Copy link

Any luck with the throttling? I've built a similar app on my side and getting the same issue, empty array after 48 requests. Then light ban for 5 hours

Do you know the period that 48 requests limit? Like 48 request within 1 hour?

@slhsxcmy
Copy link

I tried 5 locations every 10 minutes, also getting empty array after 4 hours. I'm not sure what the criteria is

@sg957
Copy link

sg957 commented Jun 15, 2022

Yes after getting the first empty array, I sleep for 1 hour until the next non-empty array (then it's back to checking every 5 minutes). But it still takes 5 hours to reset

I have a solution for that
Write to me in private visavisanot at gmail.com

@validator-333
Copy link

Yes after getting the first empty array, I sleep for 1 hour until the next non-empty array (then it's back to checking every 5 minutes). But it still takes 5 hours to reset

I have a solution for that Write to me in private visavisanot at gmail.com

Is the e-mail address' inbox still being monitored?
If not, could you please reply to mine?

Thanks.

@estebanalzated
Copy link

Hello, I tested it with the Colombia country code, I had an error with the get_time method but I fixed, I have not yet been able to test the reschedule method, there aren't available days, but I have a question, Does this code contemplates the scheduling of the consular appointment and the appointment of the ASC? I

Hey dresansol, did you figure out how to reschedule the ASC appointment? I haven't been able to do so :(

@theadri2
Copy link

Guys, has anyone found out a way to deal with the throttling/ban?

@israteneda
Copy link

Hey dresansol, did you figure out how to reschedule the ASC appointment? I haven't been able to do so :(

Here there is a repo with ASC appointment: https://github.com/Narias1999/visabot
Also, there is a repo with the original gist, here: https://github.com/uxDaniel/visa_rescheduler

@dresansol
Copy link

dresansol commented Jun 30, 2022

The appointment, ASC and consular, should be scheduled with the UI because the post request doesn’t work. You have to write a js code for click on each list box and set the dates

@manolodf
Copy link

Yes after getting the first empty array, I sleep for 1 hour until the next non-empty array (then it's back to checking every 5 minutes). But it still takes 5 hours to reset

I have a solution for that Write to me in private visavisanot at gmail.com

I am also interested, emailed you.

@sg957
Copy link

sg957 commented Dec 27, 2022

I see that many people write here about the problem, so I will write here some points that will lead to a solution
In order to monitor the available dates, it is recommended to use accounts that have already had an interview meeting, even accounts that have already had an interview show available dates, if the account no longer shows available dates move to the next account, you need several accounts for this to monitor the dates,
The monitoring should be done in a separate window of the browser, and the central account for which you want to make an appointment in a separate window, if a queue is found, of course, continue the script in the window of the central account.
In addition, queues enter the system (except for very unusual cases) only during a round minute, for example 20:00 20:05 20:10 and so on... the mechanism that searches for available queues should only be activated during these minutes.
Someone needs to update the code here according to this data

@sarah60225
Copy link

Thanks for your code. It helps a lot.

@sg957
Copy link

sg957 commented Jan 8, 2023

Has anyone adjusted the code according to the data I wrote down?

@dresansol
Copy link

Are you sure this was the reason? I've been executing my code for some friends and coincidentally they have been denied, but they have never told them anything related to the rescheduling process

@zakoud
Copy link

zakoud commented Feb 3, 2023

Just wanted to come by and let you guys know that I had my visa cancelled last week by the US embassy, for running this script on my own, which apparently violates the Terms of use of the ais website.
Not sure how the heck they found out. I feel so miserable. Not worth it, mate. Good luck to y'all.

Was this canceled at the embassy before being approved or after it was approved some time after?

@sarathbp
Copy link

Hello Friends, I do not have any programming background. Could you please help me to run this script to get my appointment ?

its group of 3.

I am using a windows 11 laptop

@sprfct
Copy link

sprfct commented Feb 26, 2023

hey guys, anyone has an idea about their rate limiting policy? I got 5 hour-bans twice and I dont want to risk it again. What is the optimal frequency and break-time to overcome this? Thanks in advance

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment