RPA Challenge z Pythonem i Selenium

Znalazłem ostatnio fajne Robotic Process Automation (RPA) Challenge. Chyba nie jest już najświeższe ale mimo tego całkiem fajnie się się przy nim bawiłem. Pomysł na challenge jest prosty – mamy plik Excel’a z 10 liniami i 7 kolumnami, potrzebujemy wpisać linię po linii do formularza online zatweirdzając każdą przyciskiem. Ciekawy trick to, że formularz zmienia ułożenie pól po każdym submission.

Żeby mieć jakiś punkt odniesienia, poszukałem wyników innych osób. Znajdziecie je na LinkedIn lub Youtube. Czasy wykonania zadania były różne, naszybsze około 7-8 sekund, a średnio, większość która widziałem oscylowała koło 10-12 sekund. Ok, czas pobić rekordy 🙂

Pierwsza próba

Użyłem Pythona i Selenium obsługujące Chrome. Początkowo planowałem odczytać Excela za pomocą openpyxl, zlokalizować odpowiednie pola za pomocą głównie XPath, potem wypełnić je używając send_keys. Na koniec kliknąć przycisk submit również używając metody Selenium. Kod poniżej. Rezultat to 7.5 sek. Nie tak dobry jak bym chciał…

driver = webdriver.Chrome()
driver.get("http://www.rpachallenge.com/")

wb = openpyxl.load_workbook('challenge.xlsx')
ws = wb.active
col_names = [ws.cell(row=1,column=j).value.strip() for j in range(1,8)]

driver.execute_script("document.getElementById('start').click()")

for i in range(2,12):
    vals = [ws.cell(row=i,column=j).value for j in range(1,8)]

    submit_button = WebDriverWait(driver, 1).until(EC.presence_of_element_located((By.XPATH, "//*[@id='randomForm']/div[2]/input")))
    any_field = WebDriverWait(driver, 1).until(EC.presence_of_element_located((By.XPATH, "//div[contains(@class, 'js-inputContainer') and contains(@class, 'input-group')]")))
    all_fields = driver.find_elements_by_xpath("//div[contains(@class, 'js-inputContainer') and contains(@class, 'input-group')]")
    
    for field in all_fields:
        field_label = field.find_element_by_tag_name("label").text
        field_input = field.find_element_by_tag_name("input")
        
        for idx, col in enumerate(col_names):
            if field_label == col:
                field_input.send_keys(vals[idx])

    submit_button.click()

Ostatnia próba

Zmieniłem podejście, w dalszym ciągu oparłem się na Pythonie i Selenium, ale wykorzystałem metodę uruchomienia Javascriptu bezpośrednio w przeglądarce. W dwóch słowach, za pomocą tego podejścia lokalizuję i wypełniam wszystkie pola jedną komendą. Przycisk obsłużyłem również za pomocą JS. Tym razem wynik jest zadowalający, 0.17 sek. 40 razy szybciej niż poprzednim razem i ponad 60 razy szybciej niż używając popularnych narzędzi RPA (porównując do wyników z sieci) .
Kod poniżej.

driver = webdriver.Chrome()
driver.get("http://www.rpachallenge.com/")

wb = openpyxl.load_workbook('challenge.xlsx')
ws = wb.active
col_names = [ws.cell(row=1,column=j).value.strip() for j in range(1,8)]

driver.execute_script("document.getElementById('start').click()")

for i in range(2,12):
    vals = [ws.cell(row=i,column=j).value for j in range(1,8)]
    scripts = ["document.evaluate('//label[contains(text()," + '"' + col_names[idx]  + '"' + ")]', document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue.parentElement.getElementsByTagName('input')[0].setAttribute('value', '" + str(val) + "')" for idx, val in enumerate(vals)]
    script_to_be_executed = ";".join(scripts)
    driver.execute_script(script_to_be_executed)
    driver.execute_script("document.getElementsByClassName('btn btn-default')[0].click()")

Kod ma 12 linii (plus kilka do importu bibliotek), także jest naprawdę krótki. Używając popularnego narzędzia RPA do rozwiązania tego samego problemu mielibyśmy zdecydowanie więcej linii kodopodobnych.

Video

Rezultaty krótkim video poniżej.

Sprawdźcie również poprzedni artykuł, w którym porównuję 4 różne narzędzia do automatyzacji. Jeśli macie chwilkę, podejmijcie ten RPA challenge, jest całkiem fajny!

Update

Okazało się, że ktoś inny zrobił to jeszcze szybciej, i to właśnie jeden z powodów dlaczego bardzo lubię tego typu wyzwania 🙂 Przemyślałem sprawę po raz kolejny i udało mi się zmniejszyć czas procesowania do 0.034 sek., używając poniższego kodu.

execute = []

wb = openpyxl.load_workbook('challenge.xlsx')
ws = wb.active
col_names = [ws.cell(row=1,column=j).value.strip() for j in range(1,8)]

execute.append("document.getElementById('start').click()")
for i in range(2,12):
    vals = [ws.cell(row=i,column=j).value for j in range(1,8)]
    scripts = ["document.evaluate('//label[contains(text()," + '"' + col_names[idx]  + '"' + ")]', document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue.parentElement.getElementsByTagName('input')[0].setAttribute('value', '" + str(val) + "')" for idx, val in enumerate(vals)]
    scripts = ";".join(scripts)
    execute.append(scripts)
    execute.append("document.getElementsByClassName('btn btn-default')[0].click()")
    
execute = ";".join(execute)
driver.execute_script(execute)

Można powiedzieć, że powyższy kod tłumaczy Excela do serii linii w JS i uruchamia wszystkie jedną komendą. Zadziałało bardzo sprawnie w tym przypadku, jednak nie polecam takiego podejścia w przypadku prawdziwego projektu.

@sejm_watch - o czym ćwierkają wróbelki w Sejmie<< >>Czy musisz programować żeby być Developerem RPA?

1
Dodaj komentarz

avatar
1 Comment threads
0 Thread replies
0 Followers
 
Most reacted comment
Hottest comment thread
1 Comment authors
Jan Recent comment authors
  Subscribe  
najnowszy najstarszy oceniany
Powiadom o
Jan
Gość
Jan

Świetny wynik. Mi się udało to rozwiązać w 174 milisekundy przy użyciu samego AutoIt ale dopiero za 3 podejściem. Polecam Ci spróbować swoich sił w RPA Hackathon od Vincix Group jeśli lubisz takie wyzwania. Mi udało mi się dostać do TOP3 na drugim poziomie 🙂