Created
January 12, 2024 03:36
-
-
Save emrekasg/7250efcccb263ece9007044ad6dba40a to your computer and use it in GitHub Desktop.
USA Visa Appointment slot picker
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const { Builder, Key, By, until } = require('selenium-webdriver'); | |
const chrome = require('selenium-webdriver/chrome'); | |
console.log('Starting Chrome WebDriver'); | |
let options = new chrome.Options(); | |
// Modular function to create a WebDriver instance | |
async function createDriver() { | |
return new Builder() | |
.forBrowser('chrome') | |
.setChromeOptions(options) | |
.build(); | |
} | |
// Function to scroll to the bottom of a page | |
async function scrollToBottom(driver) { | |
await driver.executeScript("window.scrollTo(0, document.body.scrollHeight)"); | |
} | |
// Function to perform login | |
async function performLogin(driver) { | |
await driver.get('https://ais.usvisa-info.com/tr-tr/niv/users/sign_in'); | |
await scrollToBottom(driver); | |
await driver.findElement({ id: 'user_email' }).sendKeys(''); | |
await driver.findElement({ id: 'user_password' }).sendKeys('Emre1234!!'); | |
let checkbox = await driver.findElement({ className: 'icheckbox' }); | |
await checkbox.click(); | |
await driver.findElement({ name: 'commit' }).click(); | |
} | |
// Function to navigate to the appointment page | |
async function navigateToAppointmentPage(driver) { | |
await driver.sleep(4000); | |
await driver.get(""); // the appointment url you want to check | |
} | |
// Function to select a consulate | |
async function selectConsulate(driver, consulate) { | |
let select = await driver.findElement({ id: 'appointments_consulate_appointment_facility_id' }); | |
let options = await select.findElements({ tagName: 'option' }); | |
for (let option of options) { | |
let text = await option.getText(); | |
if (consulate === text) { | |
await option.click(); | |
return true; | |
} | |
} | |
throw new Error('Consulate not found'); | |
} | |
// Function to select a date from the date picker | |
async function selectDateFromDatePicker(driver, wantedMonths) { | |
await driver.findElement({ id: 'appointments_consulate_appointment_date' }).click(); | |
let foundSlot = false; | |
let noAvailableDate = false; | |
while (!foundSlot) { | |
let firstMonthText = await getMonthText(driver, 'ui-datepicker-group-first'); | |
let secondMonthText = await getMonthText(driver, 'ui-datepicker-group-last'); | |
let firstYearText = await getYearText(driver, 'ui-datepicker-group-first'); | |
let secondYearText = await getYearText(driver, 'ui-datepicker-group-last'); | |
console.log(`First month displayed: ${firstMonthText}`); | |
if (firstYearText !== '2024') { | |
console.log('Year is not 2024, skipping'); | |
return false; | |
} | |
if (wantedMonths.includes(firstMonthText) && firstYearText === '2024') { | |
foundSlot = await selectAvailableDate(driver, 'ui-datepicker-group-first'); | |
} else if (wantedMonths.includes(secondMonthText) && secondYearText === '2024') { | |
foundSlot = await selectAvailableDate(driver, 'ui-datepicker-group-last'); | |
} | |
if (!foundSlot) { | |
// Navigate to the next month | |
await driver.findElement({ className: 'ui-datepicker-next' }).click(); | |
await driver.sleep(2000); | |
} | |
} | |
return true; | |
} | |
// Function to get the month text from a date picker group | |
async function getMonthText(driver, className) { | |
let monthGroup = await driver.findElement({ className: className }); | |
let monthTitle = await monthGroup.findElement({ className: 'ui-datepicker-title' }); | |
let monthSpan = await monthTitle.findElement({ className: 'ui-datepicker-month' }); | |
return await monthSpan.getText(); | |
} | |
async function getYearText(driver, className) { | |
let monthGroup = await driver.findElement({ className: className }); | |
let monthTitle = await monthGroup.findElement({ className: 'ui-datepicker-title' }); | |
let monthSpan = await monthTitle.findElement({ className: 'ui-datepicker-year' }); | |
return await monthSpan.getText(); | |
} | |
// Function to select an available date from a specific date picker group | |
async function selectAvailableDate(driver, className) { | |
let datePickerGroup = await driver.findElement({ className: className }); | |
let datePickerTable = await datePickerGroup.findElement({ className: 'ui-datepicker-calendar' }); | |
let datePickerRows = await datePickerTable.findElements({ tagName: 'tr' }); | |
for (let row of datePickerRows) { | |
let dates = await row.findElements({ tagName: 'td' }); | |
for (let date of dates) { | |
let classAttr = await date.getAttribute('class'); | |
if (!classAttr.includes('ui-state-disabled')) { | |
console.log('Available date found'); | |
await date.click(); | |
return true; // Date selected successfully | |
} else { | |
console.log('Date is not available, date: ' + await date.getText()); | |
} | |
} | |
} | |
return false; // No available date found in this group | |
} | |
async function selectAvailableTime(driver) { | |
let appointmentTimes = await driver.findElement({ id: "appointments_consulate_appointment_time" }); | |
let appointmentTimesOptions = await appointmentTimes.findElements({ tagName: 'option' }); | |
for (let appointmentTimeOption of appointmentTimesOptions) { | |
let value = await appointmentTimeOption.getAttribute('value'); | |
if (value !== '') { | |
await appointmentTimeOption.click(); | |
return true; | |
} | |
} | |
return false; | |
} | |
async function automateTasks() { | |
let driver = await createDriver(); | |
let foundEmptySlot = false; | |
while (!foundEmptySlot) { | |
try { | |
await performLogin(driver); | |
await scrollToBottom(driver); | |
for (let i = 0; i < 100000; i++) { | |
await navigateToAppointmentPage(driver); | |
// check if we logged in | |
let currentUrl = await driver.getCurrentUrl(); | |
if (currentUrl !== '') { // the url you want to check | |
console.log('Not logged in, logging in again'); | |
await performLogin(driver); | |
await scrollToBottom(driver); | |
await navigateToAppointmentPage(driver); | |
} | |
let consulates = ['Istanbul', 'Ankara']; | |
for (let consulate of consulates) { | |
console.log(`Checking for consulate: ${consulate}`); | |
await selectConsulate(driver, consulate); | |
await driver.sleep(1000); | |
const wantedMonths = ["January", "February", "March", "April", "May", "December"]; | |
// run esc command to close the date picker | |
await driver.actions().sendKeys(Key.ESCAPE).perform(); | |
await driver.sleep(1000); | |
await driver.actions().sendKeys(Key.ESCAPE).perform(); | |
const success = await selectDateFromDatePicker(driver, wantedMonths); | |
if (!success) { | |
console.log('No available date found, skipping'); | |
continue; | |
} else { | |
console.log('Available date found'); | |
const foundTime = await selectAvailableTime(driver); | |
if (foundTime) { | |
console.log('Available time found'); | |
foundEmptySlot = true; | |
break; | |
}else{ | |
console.log('No available time found, skipping'); | |
continue; | |
} | |
break; | |
} | |
} | |
if (foundEmptySlot) { | |
break; | |
} | |
await driver.sleep(30000); | |
} | |
} catch (error) { | |
console.error('Error occurred:', error); | |
await driver.sleep(30000); // Wait for 30 seconds before retrying | |
continue; | |
} | |
} | |
// closes the browser after finding an empty slot | |
await driver.quit(); | |
} | |
automateTasks(); | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
oha