-
-
Save yaojialyu/0c59c23d84585cc6e889e394d928a164 to your computer and use it in GitHub Desktop.
# -*- coding: utf8 -*- | |
import time | |
import json | |
import random | |
import platform | |
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 as Wait | |
from selenium.webdriver.common.by import By | |
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities | |
USERNAME = '<username>' | |
PASSWORD = '<pwd>' | |
SCHEDULE = '<schedule number>' | |
PUSH_TOKEN = '<my push token>' | |
PUSH_USER = '<my push user>' | |
MY_SCHEDULE_DATE = "<current date>" # 2020-12-02 | |
#MY_CONDITION = lambda month,day: int(month) == 11 or (int(month) == 12 and int(day) <=5) | |
MY_CONDITION = lambda month,day: int(month) == 11 and int(day) >= 5 | |
SLEEP_TIME = 5 # recheck time interval | |
DATE_URL = "https://ais.usvisa-info.com/en-ec/niv/schedule/%s/appointment/days/108.json?appointments[expedite]=false" % SCHEDULE | |
TIME_URL = "https://ais.usvisa-info.com/en-ec/niv/schedule/%s/appointment/times/108.json?date=%%s&appointments[expedite]=false" % SCHEDULE | |
APPOINTMENT_URL = "https://ais.usvisa-info.com/en-ec/niv/schedule/%s/appointment" % SCHEDULE | |
HUB_ADDRESS = 'http://localhost:4444/wd/hub' | |
EXIT = False | |
def send(msg): | |
url = "https://api.pushover.net/1/messages.json" | |
data = { | |
"token": PUSH_TOKEN, | |
"user": PUSH_USER, | |
"message": msg | |
} | |
requests.post(url, data) | |
def get_drive(): | |
local_use = platform.system() == 'Darwin' | |
if local_use: | |
dr = webdriver.Chrome(executable_path = './chromedriver') | |
else: | |
dr= webdriver.Remote(command_executor=HUB_ADDRESS, desired_capabilities=DesiredCapabilities.CHROME) | |
return dr | |
driver = get_drive() | |
def login(): | |
# Bypass reCAPTCHA | |
driver.get("https://ais.usvisa-info.com/en-ec/niv") | |
time.sleep(1) | |
a = driver.find_element_by_xpath('//a[@class="down-arrow bounce"]') | |
a.click() | |
time.sleep(1) | |
print("start sign") | |
href = driver.find_element_by_xpath('//*[@id="header"]/nav/div[2]/div[1]/ul/li[3]/a') | |
href.click() | |
time.sleep(1) | |
Wait(driver, 60).until(EC.presence_of_element_located((By.NAME, "commit"))) | |
print("click bounce") | |
a = driver.find_element_by_xpath('//a[@class="down-arrow bounce"]') | |
a.click() | |
time.sleep(1) | |
do_login_action() | |
def do_login_action(): | |
print("input email") | |
user = driver.find_element_by_id('user_email') | |
user.send_keys(USERNAME) | |
time.sleep(random.randint(1, 3)) | |
print("input pwd") | |
pw = driver.find_element_by_id('user_password') | |
pw.send_keys(PASSWORD) | |
time.sleep(random.randint(1, 3)) | |
print("click privacy") | |
box = driver.find_element_by_class_name('icheckbox') | |
box .click() | |
time.sleep(random.randint(1, 3)) | |
print("commit") | |
btn = driver.find_element_by_name('commit') | |
btn.click() | |
time.sleep(random.randint(1, 3)) | |
Wait(driver, 60).until(EC.presence_of_element_located((By.XPATH, "//a[contains(text(),'Continue')]"))) | |
print("Login successfully! ") | |
def get_date(): | |
driver.get(DATE_URL) | |
if not is_logined(): | |
login() | |
return get_date() | |
else: | |
content = driver.find_element_by_tag_name('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('pre').text | |
data = json.loads(content) | |
time = data.get("available_times")[-1] | |
print("Get time successfully!") | |
return time | |
def reschedule(date): | |
global EXIT | |
print("Start Reschedule") | |
time = get_time(date) | |
driver.get(APPOINTMENT_URL) | |
data = { | |
"utf8": driver.find_element_by_name('utf8').get_attribute('value'), | |
"authenticity_token": driver.find_element_by_name('authenticity_token').get_attribute('value'), | |
"confirmed_limit_message": driver.find_element_by_name('confirmed_limit_message').get_attribute('value'), | |
"use_consulate_appointment_capacity": driver.find_element_by_name('use_consulate_appointment_capacity').get_attribute('value'), | |
"appointments[consulate_appointment][facility_id]": "108", | |
"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): | |
print("Successfully Rescheduled") | |
send("Successfully Rescheduled") | |
EXIT = True | |
else: | |
print("ReScheduled Fail") | |
send("ReScheduled Fail") | |
def is_logined(): | |
content = driver.page_source | |
if(content.find("error") != -1): | |
return False | |
return True | |
def print_date(dates): | |
for d in dates: | |
print("%s \t business_day: %s" %(d.get('date'), d.get('business_day'))) | |
print() | |
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 | |
def push_notification(dates): | |
msg = "date: " | |
for d in dates: | |
msg = msg + d.get('date') + '; ' | |
send(msg) | |
if __name__ == "__main__": | |
login() | |
retry_count = 0 | |
while 1: | |
if retry_count > 6: | |
break | |
try: | |
print(datetime.today()) | |
print("------------------") | |
dates = get_date()[:5] | |
print_date(dates) | |
date = get_available_date(dates) | |
if date: | |
reschedule(date) | |
push_notification(dates) | |
if(EXIT): | |
break | |
time.sleep(SLEEP_TIME) | |
except: | |
retry_count += 1 | |
time.sleep(60*5) | |
if(not EXIT): | |
send("HELP! Crashed.") |
Hi @fredthedead ,
Thanks for your comment.
The reason fails to log in is that this page is using Google reCAPTCHA v3, you can see this sign on the right bottom. It may recognize some patterns if you try to log in frequently (I guess), and I met the situation you mentioned before.
The way I solved this problem is to simulate a "real" person's browsing activities. You can see inside login
function, there are some actions before the actual login operation and some sleep intervals after typing in username and password. If you already encountered this problem, it'd be better to retry later.
I tested and run my code just now and it logs in successfully.
Many thanks for your reply and suggestions 🙏. Will try again now that some time has passed
¿Still woks?
Sigue funcionando tu script?
After login i am getting {message:Facility is not valid,error:bad_request} error!
Btw, I am using Webdriver_Manager this way: from webdriver_manager.chrome import ChromeDriverManager
and the code is running on terminal mac os.
🙏🏻
^ I’m having the same issue here.
I’m not quite sure how this DATE_URL works
DATE_URL = "https://ais.usvisa-info.com/en-ca/niv/schedule/%s/appointment/days/108.json?appointments[expedite]=false" % SCHEDULE
What is this 108.json thingy doing at the end anyway? Should I change this?
UPDATE:
I find out what that 108 means now. It represent the facility_id, to find out which facility you want to attend. Use F12 or inspect on appointment page, and, in my case, you can see something like
<option data-collects-biometrics="false" selected="selected" value="94">Toronto</option>
The value number is the facility_id, replace 108
in the code with your <facility_id> should work.
Hey,
Did you guys got blocked after a few attempts for a couple of hours?
if not, did you change the sleep_time interval? did you do something else?
The script works for me on my mac. When I try to run it inside a linux VM on Azure, however, it fails to log in after clicking the signin button. Tried using varying sleep interval but did not help. Manual login inside VM through xrdp works though. I suspect reCAPTCHA detects that the input speed of username and password is too fast. Just my two cents, not sure how reCAPTCHA works and what else of the workflow differs from real human beings.
Also, saw people on the internet saying there's a limit of the number of reschedules an application can make before re-pay the appointment fee. Typically 3 (the initial one + 2 changes) from what I could find. Currently I have made 2 reschedules so trying to be cautious before making any changes. Would appreciate if anyone knows more about the limit.
Hey guys, I wrote this script 16 months ago and I haven't tested it for a long time, things may be changed now. So that I cannot provide more insights/solutions for what you mentioned above. Please refer to others' replies. Good luck to you all.
One question, is there some place that refers to this script? since these days the replies become more than ever before.
I just randomly came across this gist while searching ais on github lol.. Thanks for sharing :)
The reschedule(date) method doesn't seem to work. Did anyone write a functional version? Appreciated it.
I modified the original script and included logging: https://gist.github.com/Svision/04202d93fb32d14f00ac746879820722
@Svision I saw an implementation of @yaojialyu's gist here: https://github.com/uxDaniel/visa_rescheduler
Lo único malo es que el servidor lo bloquea a uno por entrar mucho :(
Yo Hice un boot también, busco la manera acceder a api importando request, logro solo iniciar sesión, de ahí no he pasado pasar. Alguna forma de guardar hacer request.Session() y que no se pierda el registro cuando le hago peticiones get a la página de appoiment?
Hi @yaojialyu , can you tell me what is number 108 for in the DATE_URL and TIME_URL please?
Hi guys, I see that the APIs does not work if we call them from the codebase. Have the US Gov made changes in the server to not accept APIs?
Lo único malo es que el servidor lo bloquea a uno por entrar mucho :( Yo Hice un boot también, busco la manera acceder a api importando request, logro solo iniciar sesión, de ahí no he pasado pasar. Alguna forma de guardar hacer request.Session() y que no se pierda el registro cuando le hago peticiones get a la página de appoiment?
Hablame y lo checamos, yo busco lo mismo
Lo único malo es que el servidor lo bloquea a uno por entrar mucho :( Yo Hice un boot también, busco la manera acceder a api importando request, logro solo iniciar sesión, de ahí no he pasado pasar. Alguna forma de guardar hacer request.Session() y que no se pierda el registro cuando le hago peticiones get a la página de appoiment?
Hablame y lo checamos, yo busco lo mismo
Ya lo solucioné hace más de un año. Pero si lo que quieres es adelantar las citas, hasta hace mes y medio se podía, la Embajada ha cambiado todo.
Hey
Is there a way to contact you by email or anything? I await your response as soon as possible.
@yaojialyu
I want to work with you on a project similar to visa appointments , i want your email
Hey,
Many thanks for sharing your code 🙏 I wrote something similar but ran into a problem with both my code and yours (which is why it's great to meet someone who might have solved it)
The problem is that after 'clicking' the sign-in button, the page refreshes without successfully logging in. This only happens in the webdriver/selenium session, in a regular browser, with manual login, everything works fine. This makes me think the webdriver is being detected and blocked somehow. I tried everything I could to bypass the block - from changing IPs to solving reCaptchas, modifying the user-agent, using undetected_chromedriver, and whatnot.
Have you run into this issue when running your script? Any recommendation on how to overcome it?
Again, many thanks for your help in advance