Update 12/30/2018: I don’t maintain this piece of code, so don’t simply copy-paste-run. This is just served as a way of inspiration

This article only applies to California DMV road test.

Last month my wife wanted to take the behind-the-wheel drive test at DMV. We made an appointment on April 21st but we want to take the test earlier, and we know sometimes people just reschedule for different reasons and sometimes DMV releases new available time slots. As I believe in DRY principle I don’t want to sit in front of a computer and refresh the page forever to get a lucky chance. And the simple job should be easily done by some quick-and-dirty script.

I googled for such script, didn’t find a perfect script which just meets my needs but I found a script on Github for field office visit appointment. So, based on that, I simply changed the script to adapt to the behind-the-wheel test procedure, added “start date” so that we don’t make too early appointment, keep refreshing until we can get a better time. And we did.

Script can be found at my gist page and here is the no-more-maintained code:

import mechanize
from bs4 import BeautifulSoup
from datetime import datetime
import random
import time
TGT_DATE = 'April 21, 2015' #i.e. 'September 30, 2014'
OFFICE_ID = '548' # officeid for RWC DMV. See HTML code for other office ids
form_url = 'https://www.dmv.ca.gov/wasapp/foa/findDriveTest.do'
def schedule(targetDate,name,officeId,telNumber,birthday,dlNumber,fromDate=None):
    tels = telNumber.split('-')
    births = birthday.split('-')
    names = name.split(' ')
    if not fromDate:
        fromDate = datetime.today()
        from_date = datetime.today().strftime("%B %d, %Y")
        from_date = datetime.strptime(fromDate,'%B %d, %Y')
    tgt_date = datetime.strptime(targetDate,'%B %d, %Y')
    # Browser
    br = mechanize.Browser()
    br.find_control(name="requestedTask").value = ["DT"]
    br['firstName'] = names[0]
    br['lastName'] = names[1]
    br['telArea'] = tels[0]
    br['telPrefix'] = tels[1]
    br['telSuffix'] = tels[2]
    br['dlNumber'] = dlNumber
    br['birthMonth'] = births[0]
    br['birthDay'] = births[1]
    br['birthYear'] = births[2]
    result = br.submit()
    result_html =  br.response().read()
    soup = BeautifulSoup(result_html)
    results = soup.findAll('p',class_="alert")
    logString = ""
    for result in results:
        if ('2015' in result.get_text()):
            appt_text = result.get_text()
            logString += "Earliest Appointment found is %s" %(appt_text)
            appt_date = datetime.strptime(appt_text,'%A, %B %d, %Y at %I:%M %p')
            if appt_date <= tgt_date and appt_date>=from_date:
                logString+= "\nCongratulations! You've found a date earlier than your target. Scheduling the appointment..."
                r = br.submit()
                logString+= "\nConfirming the appointment..."
                r = br.submit()
                s = BeautifulSoup(br.response().read())
                logString += "\nThe final step is to actually schedule it...Use it when necessary.\n"
                r = br.submit()
                s = BeautifulSoup(br.response().read())
                print s
                # logString += br #print out relevant info related to the appointment
                print logString
                with open("test.txt", "a") as myfile:
                return True
                logString += "\nSorry there is no appointment available between date %s and %s"%(from_date,targetDate)
                logString += "\n"
                print logString
                with open("test.txt", "a") as myfile:
                return False
while not schedule(TGT_DATE,'FIRST LAST',OFFICE_ID,'111-222-3333','01-30-1980','DL00001','April 13, 2015'):
    waitTime = random.randint(60,600)

DMV office’s ID can be found at DMV’s own website, if you need to schedule at another place, please go there and find it. Or you may want to enhance the code if you want try more than one DMV offices at the same time.

Now she happily passed the test so I can open-source the code, and I can’t test it any more because DMV won’t let someone who already passed the test to make such appointment.