The creation of a Quizbot

·

5 min read

First of all, this is my first devblog, and hoping that i will make a lot more, so hi to everyone who is reading this, anyways let's start.

How all started

So, i'll try to be short on this one but i'll try to explain the basic concepts here, there's a website called Quizlet, in this website you can use it to learn a lot of things from languagues to geography, etc.

How i did it?

So Quizlet has a lot of features that are used to help students learn in a better way, but there is one feauture that will come in handy for what i need, the terms, this contain all we need, for almost any test, contains the word and a description (Could vary a little depending what subject is about)
Here is an example Captura de pantalla 2021-07-22 122619.png In this case this is a quizlet to learn english words, and warble is the word and the other part is the definition, great,now you'll probably thinking
"Sure, but how does this help? and about what test are you talking about?"

Let me explain, another feature of quizlet are this tests they come in many forms and are like minigames, you can see the name of some of them in the picture below Captura de pantalla 2021-07-22 123239.png

There are more, but those are my main goals

The interesting part

Now, the Interesting part, let's start from the beggining, before anything else we need to grab the lists(By lists i mean the collection of terms in a quizlet) so we have to where compare, so i started to write in python, using the selenium module to web scrape all those terms using a for loop to get them in a dictionary, and then converted them in .csv so it doesn't disappear into the void, and with that the List Grabber was done. I made the csv, follow this format instead of the regular "," because that would cause problems with question who contains commas.
word¿definition

SolveWrite()

Now, is time, is time to make something that is actually useful, the first automation for the "Write" test, this is the first function i made the SolveWrite() function

def SolveWrite(url,nombreL):
    count = 0
    driver.get(url)
    palabra=""
    time.sleep(2)
    while count < maxcount:
        with open('Lists/'+nombreL+'.csv', 'r') as lista:
            csv_dict_reader = csv.DictReader(lista, delimiter='¿')
            definition = driver.find_element_by_class_name('WriteQuestionElements')
            for row in csv_dict_reader:
                if row['definition'] == definition.text:
                    palabra = row['word']

            inputElement = driver.find_element_by_class_name('AutoExpandTextarea-textarea')
            inputElement.send_keys(palabra)
            time.sleep(.5)
            inputElement.send_keys(Keys.ENTER)  
            time.sleep(.5)
        count += 1
    driver.close()

Basically what this does is getting an url, and also the .csv name, from an input variable, then goes to that url and while is going to the url also opens the .csv file that we already made,then, it "scans" the website and "read" the definition since in this test is supposed that you should know the definition of a word, here's an example of how the test looks like Captura de pantalla 2021-07-22 130714.png Then when the definition is "scanned" the program compares with the other definitions and if one word coincides with the definition that we are given, the program stores that variable, and goes an type it in there and presses enter, and it does that until there are no more things to answer

SolveSpell()

This one was pretty since the only thing i needed to do is rewrite the SolveWrite function, but make it the double amount since, that's how this test works, you have to type the word twice to count as learned, here is how it looks this test

Captura de pantalla 2021-07-22 131225.png

The final boss, SolveLearn()

This was a pain to implement, but it works is a little slow but, oh boy, it does his work.

First let me explain why this one was a pain, first of all multiple options

Captura de pantalla 2021-07-22 131837.png

solvemultiple()

This one was functionception since i had to make first this function called solvemultiple()

def solvemultiple(nombreL):
    driver.implicitly_wait(5)
    with open('Lists/'+nombreL+'.csv', 'r') as lista:
            csv_dict_reader = csv.DictReader(lista, delimiter='¿')
            try:
                option1 = driver.find_element_by_xpath('//*[@id="AssistantModeTarget"]/div/div/div[2]/div/div/div/div/div[2]/div/div[2]/div/div[1]')
                option2 = driver.find_element_by_xpath('//*[@id="AssistantModeTarget"]/div/div/div[2]/div/div/div/div/div[2]/div/div[2]/div/div[2]')
                option3 = driver.find_element_by_xpath('//*[@id="AssistantModeTarget"]/div/div/div[2]/div/div/div/div/div[2]/div/div[2]/div/div[3]')
                option4 = driver.find_element_by_xpath('//*[@id="AssistantModeTarget"]/div/div/div[2]/div/div/div/div/div[2]/div/div[2]/div/div[4]')
            except NoSuchElementException:
                driver.implicitly_wait(10)
                option1 = driver.find_element_by_xpath('//*[@id="AssistantModeTarget"]/div/div/div[2]/div/div/article/div[2]/div/div[1]')
                option2 = driver.find_element_by_xpath('//*[@id="AssistantModeTarget"]/div/div/div[2]/div/div/article/div[2]/div/div[2]')
                option3 = driver.find_element_by_xpath('//*[@id="AssistantModeTarget"]/div/div/div[2]/div/div/article/div[2]/div/div[3]')
                option4 = driver.find_element_by_xpath('//*[@id="AssistantModeTarget"]/div/div/div[2]/div/div/article/div[2]/div/div[4]')
            try:
                definition = driver.find_element_by_xpath('//*[@id="AssistantModeTarget"]/div/div/div[2]/div/div/article/div[1]/div[2]/div/div/div')
            except NoSuchElementException:
                definition = driver.find_element_by_xpath('//*[@id="AssistantModeTarget"]/div/div/div[2]/div/div/div/div/div[2]/div/div[1]/div/div/div/div/div')
            time.sleep(1)
            for row in csv_dict_reader:
                if row['definition'] == definition.text:
                    palabra = row['word']
            print('Correcta:'+palabra)
            if  palabra in option1.text :
                option1.click()
            if  palabra in option2.text:
                option2.click()
            if  palabra in option3.text:
                option3.click()
            if  palabra in option4.text:
                option4.click()
            time.sleep(2)

This what it does, is that gets the texts of all the options, and also get the correct word from the .csv file, then it compares all options, and to know to what option is the one to click it compares the text, to the correct word, and then it click it

Then it was time, time to make the SolveLearn() function, but luckily we already beaten the hard part, the only thing is that the "Learn" test not only contains multiple options, it also contains the "write" test in it, so we also need to take care of that

def SolveLearn(url,nombreL):
    count = 0
    palabra = ""
    driver.get(url)
    time.sleep(3)
    try:
        Continuar = driver.find_element_by_class_name('OnboardingView-gotItButton')
    except NoSuchElementException:
        Continuar = driver.find_element_by_xpath('//*[@id="AssistantModeTarget"]/div/div/div[2]/div/div/article/button')
    Continuar.click()      
    while count < maxcount*2:
        try:
            try:
                solvemultiple(nombreL)
            except NoSuchElementException:
                solvewrite(nombreL)
        except NoSuchElementException:
            try:
                boton = driver.find_element_by_class_name('//*[@id="AssistantModeTarget"]/div/div/div[2]/div/div/div/div/div/button')
            except:
                boton = driver.find_element_by_class_name('//*[@id="AssistantModeTarget"]/div/div/div[2]/div/div/div/div/div/div[2]/div/button')
            boton.click()
    print('Solved!')
    driver.close()

So, for the "Write" part, we only need to compare when the write is need and when multiple is needed,i did that by checking if an unique element from the multiple options exist and the same for the write , then we just execute the one we need,and is almost done.

SignIn()

We already have a functional quizlet bot, but what would be the point, if we cannot save the progress?, so i made this function that signs you in, with your account, using the input variables

def SignIn(user, password):
    driver.get('https://quizlet.com/es')
    Signin_button = driver.find_element_by_xpath('//*[@id="TopNavigationReactTarget"]/header/div/div[2]/div[3]/button[1]')
    Signin_button.click()
    user_blank = driver.find_element_by_id('username')
    pass_blank = driver.find_element_by_id('password')
    user_blank.send_keys(user)
    pass_blank.send_keys(password)
    pass_blank.send_keys(Keys.ENTER)
    time.sleep(3)

Great, now this will be useful in a moment

Disguise the code(GUI)

I'm not gonna place the gui code block, because i think is unecessary, but i will say that when you press the button, it will execute de SignIn() function, using the variables you put in the entrys, and the link of the test you would like to solve, it also detects if is a learn,write or spell test, automatically

Captura de pantalla 2021-07-22 133615.png

Example

Disclaimer

Yes, i am a native spanish speaker, but i preferred to write this blog in english