├── requirements.txt ├── chromedriver ├── README.md ├── .gitignore └── southwest_checkin.py /requirements.txt: -------------------------------------------------------------------------------- 1 | selenium>=2.0,<=3.0 2 | pyvirtualdisplay>=0.2.1 3 | -------------------------------------------------------------------------------- /chromedriver: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daveharmon/Southwest-Checkin/HEAD/chromedriver -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Southwest-Checkin 2 | An easy python script to continuously retry checking into your Southwest flight using ChromeDriver and Selenium. Effectively checking you in at the moment it becomes available! 3 | 4 | ### Example 5 | python southwest_checkin.py -c TESTER -f Testy -l McTest -t 'Jul 02 2017 07:00AM' 6 | 7 | ### Requirements 8 | install the selenium python library with pip via `pip install -r requirements.txt` 9 | Also requires chromedriver to be in the PATH environment variable. The MAC OSX chrome driver is in this repo, other versions are available [here](https://sites.google.com/a/chromium.org/chromedriver/downloads) 10 | 11 | If you're running in Linux, you'll also need to install a few other dependencies: 12 | `sudo apt-get install chromium-browser xvfb libgconf-2-4` 13 | 14 | ### Options 15 | * -c the confirmation number string 16 | * -f the first name for the confirmation 17 | * -l the last name for the confirmation 18 | * -t date and time of check in 19 | 20 | `-t` value must be in the following format: `%b %d %Y %I:%M%p` 21 | Example: `Jan 01 1970 10:10PM` 22 | 23 | Refer to the [Python documentation](https://docs.python.org/2/library/datetime.html#strftime-and-strptime-behavior) for a complete explanation of the date format. Also keep in mind, you may need to convert the date/time to your local time zone. 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | 27 | # PyInstaller 28 | # Usually these files are written by a python script from a template 29 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 30 | *.manifest 31 | *.spec 32 | 33 | # Installer logs 34 | pip-log.txt 35 | pip-delete-this-directory.txt 36 | 37 | # Unit test / coverage reports 38 | htmlcov/ 39 | .tox/ 40 | .coverage 41 | .coverage.* 42 | .cache 43 | nosetests.xml 44 | coverage.xml 45 | *,cover 46 | .hypothesis/ 47 | 48 | # Translations 49 | *.mo 50 | *.pot 51 | 52 | # Django stuff: 53 | *.log 54 | local_settings.py 55 | 56 | # Flask stuff: 57 | instance/ 58 | .webassets-cache 59 | 60 | # Scrapy stuff: 61 | .scrapy 62 | 63 | # Sphinx documentation 64 | docs/_build/ 65 | 66 | # PyBuilder 67 | target/ 68 | 69 | # IPython Notebook 70 | .ipynb_checkpoints 71 | 72 | # pyenv 73 | .python-version 74 | 75 | # celery beat schedule file 76 | celerybeat-schedule 77 | 78 | # dotenv 79 | .env 80 | 81 | # virtualenv 82 | venv/ 83 | ENV/ 84 | 85 | # Spyder project settings 86 | .spyderproject 87 | 88 | # Rope project settings 89 | .ropeproject 90 | -------------------------------------------------------------------------------- /southwest_checkin.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from selenium import webdriver 4 | from selenium.webdriver.support.ui import WebDriverWait 5 | from selenium.common.exceptions import NoSuchElementException, StaleElementReferenceException 6 | 7 | from optparse import OptionParser 8 | from datetime import datetime 9 | from datetime import timedelta 10 | from time import sleep 11 | 12 | import os 13 | 14 | sendmail_location = "/usr/sbin/sendmail" # sendmail location; this probably won't change 15 | 16 | parser = OptionParser() 17 | parser.add_option("-c", "--confirmation_num", action="store", dest="conf_num", 18 | help="confirmation number for flight", type="string") 19 | parser.add_option("-f", "--first_name", action="store", dest="first_name", 20 | help="first name for flight", type="string") 21 | parser.add_option("-l", "--last_name", action="store", dest="last_name", 22 | help="last name for flight", type="string") 23 | parser.add_option("-t", "--time", action="store", dest="time", 24 | help="time to start checkin attempts", type="string") 25 | parser.add_option("-H", "--headless", action="store_true", dest="headless", 26 | help="set to run headless and simulate a display") 27 | parser.add_option("-e", action="store_true", dest="email", 28 | help="set to send an email; use --email-from and --email-to as well") 29 | parser.add_option("--email-from", action="store", dest="email_from", 30 | help="email address to send from", type="string") 31 | parser.add_option("--email-to", action="store", dest="email_to", 32 | help="email address to send to", type="string") 33 | 34 | (options, args) = parser.parse_args() 35 | 36 | if options.headless: 37 | from pyvirtualdisplay import Display 38 | display = Display(visible=0, size=(800, 600)) 39 | display.start() 40 | 41 | # Create a new instance of the Chrome driver 42 | driver = webdriver.Chrome() 43 | 44 | # create a wait driver 45 | wait = WebDriverWait(driver,10) 46 | 47 | # go directly to the checkin page 48 | driver.get("https://mobile.southwest.com/check-in") 49 | 50 | # get text boxes for check in 51 | while True: 52 | try: 53 | confirmation_num = driver.find_element_by_name("recordLocator") 54 | first_name = driver.find_element_by_name("firstName") 55 | last_name = driver.find_element_by_name("lastName") 56 | break; 57 | except NoSuchElementException: 58 | print("loading checkin...") 59 | sleep(0.1) 60 | 61 | # insert data 62 | confirmation_num.send_keys(options.conf_num) 63 | first_name.send_keys(options.first_name) 64 | last_name.send_keys(options.last_name) 65 | 66 | # busy wait until it is the desired time 67 | des_time = datetime.strptime(options.time, '%b %d %Y %I:%M%p') 68 | des_time_minus_6s = des_time - timedelta(seconds=6) 69 | des_time_minus_30m = des_time - timedelta(minutes=30) 70 | cur_time = datetime.now() 71 | while des_time_minus_30m > cur_time: 72 | print("Waiting for checkin time " + str(des_time) + ". Time now is: " + str(cur_time) + ". Waiting 30min.") 73 | sleep(29*60) 74 | cur_time = datetime.now() 75 | while des_time_minus_6s > cur_time: 76 | print("Waiting for checkin time " + str(des_time) + ". Time now is: " + str(cur_time) + ". Waiting 5s.") 77 | sleep(5) 78 | cur_time = datetime.now() 79 | while des_time > cur_time: 80 | cur_time = datetime.now() 81 | 82 | # check in! 83 | print("checking in...") 84 | submit = driver.find_element_by_class_name("button--yellow"); 85 | submit.click() 86 | 87 | # wait while the loading spinner is up 88 | try: 89 | while driver.find_element_by_class_name("dimmer").is_displayed(): 90 | print("loading...") 91 | sleep(0.1) 92 | except NoSuchElementException: 93 | print("no spinner found, moving on - hope everything's okay...") 94 | 95 | while True: 96 | # while an error message exists, keep trying! 97 | try: 98 | while driver.find_element_by_class_name("popup-showing"): 99 | print("error displayed, trying again") 100 | sleep(0.1) 101 | driver.find_element_by_class_name("confirm-button").click() 102 | sleep(0.5) 103 | submit.click() 104 | except NoSuchElementException: 105 | print("no error displayed, moving on!") 106 | break; 107 | 108 | # confirm checkin 109 | print("confirming check in...") 110 | submit = driver.find_element_by_class_name("button--yellow"); 111 | submit.click() 112 | 113 | # wait while the loading spinner is up 114 | try: 115 | while driver.find_element_by_class_name("dimmer").is_displayed(): 116 | print("loading...") 117 | sleep(0.1) 118 | print("loading done") 119 | except NoSuchElementException: 120 | print("no spinner found, moving on - hope everything's okay...") 121 | 122 | print("checked in - getting boarding position") 123 | boardingPositionDiv = driver.find_element_by_class_name("boarding-group-and-position") 124 | (groupSpan, positionSpan) = boardingPositionDiv.find_elements_by_class_name("xxxlarge") 125 | group = groupSpan.text 126 | position = positionSpan.text 127 | print("Checked in! Boarding position "+group+" "+position+".") 128 | 129 | # Send mail, if enabled 130 | if options.email: 131 | p = os.popen("%s -t" % sendmail_location, "w") 132 | p.write("From: %s\n" % options.email_from) 133 | p.write("To: %s\n" % options.email_to) 134 | p.write("Subject: Southwest Checkin for %s\n" % options.conf_num) 135 | p.write("\n") # blank line separating headers from body 136 | p.write("You have been checked in for your flight with confirmation number %s, with boarding position %s." % (options.conf_num, group+" "+position)) 137 | status = p.close() 138 | --------------------------------------------------------------------------------