If you're looking for a complete Python Selenium solution for solving the Wordle Game programmatically, here's one that uses the SeleniumBase framework. The solution comes with a YouTube video, as well as the Python code of the solution, and a GIF of what to expect:
The code uses special SeleniumBase ::shadow
selectors in order to pierce through multiple layers of Shadow-DOM. Here's the code below, which can be run after calling pip install seleniumbase
to get all the Python dependencies: (Updated 2/11/22 - after NYT acquired Wordle; Updated again on 2/13/22 to fix font issue on some Python environments; Updated again on 7/1/22 to use web-archived versions of Wordle because NYT removed the Shadow-DOM elements from the latest Wordle.)
""" Solve the Wordle game using SeleniumBase.
This test runs on archived versions of Wordle, containing Shadow-DOM. """
import ast
import random
import requests
from seleniumbase import version_info
from seleniumbase import BaseCase
class WordleTests(BaseCase):
word_list = []
def initialize_word_list(self):
txt_file = "https://seleniumbase.io/cdn/txt/wordle_words.txt"
word_string = requests.get(txt_file).text
self.word_list = ast.literal_eval(word_string)
def modify_word_list(self, word, letter_status):
new_word_list = []
correct_letters = []
present_letters = []
for i in range(len(word)):
if letter_status[i] == "correct":
correct_letters.append(word[i])
for w in self.word_list:
if w[i] == word[i]:
new_word_list.append(w)
self.word_list = new_word_list
new_word_list = []
for i in range(len(word)):
if letter_status[i] == "present":
present_letters.append(word[i])
for w in self.word_list:
if word[i] in w and word[i] != w[i]:
new_word_list.append(w)
self.word_list = new_word_list
new_word_list = []
for i in range(len(word)):
if (
letter_status[i] == "absent"
and word[i] not in correct_letters
and word[i] not in present_letters
):
for w in self.word_list:
if word[i] not in w:
new_word_list.append(w)
self.word_list = new_word_list
new_word_list = []
def test_wordle(self):
random.seed()
year = "2022"
month = random.randint(3, 5)
day = random.randint(1, 30)
date = str(year) + "0" + str(month) + str(day)
archive = "https://web.archive.org/web/"
url = "https://www.nytimes.com/games/wordle/index.html"
past_wordle = archive + date + "/" + url
print("\n" + past_wordle)
self.open(past_wordle)
self.click("game-app::shadow game-modal::shadow game-icon")
self.initialize_word_list()
keyboard_base = "game-app::shadow game-keyboard::shadow "
word = random.choice(self.word_list)
num_attempts = 0
success = False
for attempt in range(6):
num_attempts += 1
word = random.choice(self.word_list)
letters = []
for letter in word:
letters.append(letter)
button = 'button[data-key="%s"]' % letter
self.click(keyboard_base + button)
button = "button.one-and-a-half"
self.click(keyboard_base + button)
row = 'game-app::shadow game-row[letters="%s"]::shadow ' % word
tile = row + "game-tile:nth-of-type(%s)"
self.wait_for_element(tile % "5" + '::shadow [data-state*="e"]')
letter_status = []
for i in range(1, 6):
letter_eval = self.get_attribute(tile % str(i), "evaluation")
letter_status.append(letter_eval)
if letter_status.count("correct") == 5:
success = True
break
self.word_list.remove(word)
self.modify_word_list(word, letter_status)
self.save_screenshot_to_logs()
if success:
print('Word: "%s"\nAttempts: %s' % (word.upper(), num_attempts))
else:
print('Final guess: "%s" (Not the correct word!)' % word.upper())
self.fail("Unable to solve for the correct word in 6 attempts!")
self.sleep(3)
This solution requires minimum SeleniumBase version 2.4.4
(or newer) due to updated Shadow-DOM methods.
Note that SeleniumBase tests are run using pytest
. Also, the Wordle website appears slightly differently when opened using headless Chrome, so don't use Chrome's headless mode when running this example.
Have fun solving "Wordle" with SeleniumBase using Python and Selenium!
Here's a script that works on the latest version of Wordle, which removed the Shadow-DOM elements:
""" Solve the Wordle game using SeleniumBase.
The latest version of Wordle no longer uses Shadow-DOM. """
import ast
import random
import requests
from seleniumbase import BaseCase
class WordleTests(BaseCase):
word_list = []
def initialize_word_list(self):
txt_file = "https://seleniumbase.io/cdn/txt/wordle_words.txt"
word_string = requests.get(txt_file).text
self.word_list = ast.literal_eval(word_string)
def modify_word_list(self, word, letter_status):
new_word_list = []
correct_letters = []
present_letters = []
for i in range(len(word)):
if letter_status[i] == "correct":
correct_letters.append(word[i])
for w in self.word_list:
if w[i] == word[i]:
new_word_list.append(w)
self.word_list = new_word_list
new_word_list = []
for i in range(len(word)):
if letter_status[i] == "present":
present_letters.append(word[i])
for w in self.word_list:
if word[i] in w and word[i] != w[i]:
new_word_list.append(w)
self.word_list = new_word_list
new_word_list = []
for i in range(len(word)):
if (
letter_status[i] == "absent"
and word[i] not in correct_letters
and word[i] not in present_letters
):
for w in self.word_list:
if word[i] not in w:
new_word_list.append(w)
self.word_list = new_word_list
new_word_list = []
def test_wordle(self):
self.open("https://www.nytimes.com/games/wordle/index.html")
self.click('svg[data-testid="icon-close"]')
self.initialize_word_list()
word = random.choice(self.word_list)
num_attempts = 0
success = False
for attempt in range(6):
num_attempts += 1
word = random.choice(self.word_list)
letters = []
for letter in word:
letters.append(letter)
button = 'button[data-key="%s"]' % letter
self.click(button)
button = 'button[class*="oneAndAHalf"]'
self.click(button)
row = (
'div[class*="lbzlf"] div[class*="Row-module"]:nth-of-type(%s) '
% num_attempts
)
tile = row + 'div:nth-child(%s) div[class*="module_tile__3ayIZ"]'
self.wait_for_element(tile % "5" + '[data-state*="e"]')
letter_status = []
for i in range(1, 6):
letter_eval = self.get_attribute(tile % str(i), "data-state")
letter_status.append(letter_eval)
if letter_status.count("correct") == 5:
success = True
break
self.word_list.remove(word)
self.modify_word_list(word, letter_status)
self.save_screenshot_to_logs()
if success:
print('\nWord: "%s"\nAttempts: %s' % (word.upper(), num_attempts))
else:
print('Final guess: "%s" (Not the correct word!)' % word.upper())
self.fail("Unable to solve for the correct word in 6 attempts!")
self.sleep(3)
所有评论(0)