Направете в Selenium, ако страницата се зарежда твърде дълго • Ако искате, ще ви кажа
Същността на проблема
В предишна статия обясних как Selenium изчаква страницата да приключи зареждането.
За да обобщим, преди да изпълни всяка команда, той проверява стойността на свойството document.readyState и поставя командата на пауза, докато това свойство не бъде настроено да завърши.
Понякога обаче тази стратегия се проваля. Има ситуации, при които на свойството document.readyState или отнема много време, за да достигне пълното състояние, или изобщо не достига това състояние.
Представете си, че страницата на приложението има голямо изображение, което се зарежда от много бавен сървър. Цялата страница отдавна е заредена, можете да работите с нея, но поради тази тъпа снимка, браузърът продължава да върти колелото за зареждане, а Selenium продължава да чака...
Ето пример от реалния свят, който демонстрира този проблем:
На моята машина завършването на този кодов фрагмент отнема между 20 и 40 секунди (без времето за стартиране на браузъра). Причината е просто, че на страницата се зарежда голямо изображение (
7 мегабайта). В същото време необходимият бутон за превключване към английската версия на сайта става достъпен след няколко секунди, но Selenium изчаква зареждането на цялата страница.
Има ли нещо, което може да се направи, за да се попречи на Selenium да чака толкова дълго?
Има два начина:
- задайте изчакване за изтегляне
- промяна на стратегията за завършване на изтеглянето
Време за изчакване на изтегляне
Задаването на таймаут за зареждане кара операцията get да хвърля TimeoutException, ако страницата не се е заредила в рамките на определеното време.В този случай, след възникване на изключение, зареждането на страницата не се прекъсва, но става възможно „ранното“ извършване на някои действия с нея. Трябва обаче да се помни, че на такава „недостатъчно натоварена“ страница елементите, необходими за по-нататъшни действия, може все още да не са се появили, така че са необходими допълнителни изчаквания, за да се появят елементите:
В тази версия кодът се изпълнява за около 4 секунди (без времето за стартиране на браузъра).
Бързо не значи правилно :)
Въпросът е, че елементът с идентификатора на менюто е както на първата страница, така и на втората. В момента, в който се натисне бутонът с идентификатор en (превключване към английската версия на сайта), на страницата присъства и елементът с менюто с идентификатор. И Selenium, вместо да чака втората страница да се зареди след щракването, веднага "намира" този елемент на първата страница.
Причината за това е, че както вече споменах, след възникване на TimeoutException зареждането на страницата не се прекъсва, а продължава да се зарежда, включително и в момента на изпълнение на командата click. Това обърква Selenium, той не разбира, че трябва да се появи друга страница, и вместо това търси елементи на текущата страница.
Е, тъй като се отървахме от Selenium и поехме отговорността да изчакаме страницата да се зареди, трябва да поемем отговорност и за „разтоварването“ на страницата. Тоест, преди да изчакате появата на елемент, който трябва да бъде на следващата страница, първо трябва да изчакате, докато елементът, който е на текущата страница, изчезне. Например бутонът, върху който сте щракнали, ще изчезне:
Сега този кодов фрагмент работи за около 10 секунди (без да се брои времето за стартиране на браузъра), което е правилно - около 5 секунди на страница.
недостатъкМетодът, описан по-горе, е, че трябва да обвиете в блок try-catch всички извиквания на команди, които могат да доведат до началото на зареждането на нова страница. И може да бъде най-общо казано всеки отбор. Тоест, TimeoutException трябва да се очаква буквално навсякъде. Ужасно е!
За щастие има и друг начин.
Стратегия за изчакване на натоварването
Ако все още си спомняте, преди да изпълни всяка команда, Selenium проверява стойността на свойството document.readyState и спира изпълнението на командата, докато това свойство не бъде настроено да завърши.
По време на обработката на страницата браузърът променя това свойство, отразявайки информацията за текущия етап на зареждане:
- зареждане означава, че страницата все още се зарежда,
- интерактивен означава, че основното съдържание на страницата е заредено и изобразено, потребителят вече може да взаимодейства с него, но допълнителни ресурси все още се зареждат,
- пълно означава, че всички допълнителни ресурси също са заредени.
Така че можете да промените настройките на Selenium, така че да не чака пълната стойност, а интерактивната стойност или дори да не чака нищо.
За да направите това, когато инициализирате драйвера, трябва да зададете подходящата стойност за възможност, наречена pageLoadStrategy.
- нормално (по подразбиране) - изчакайте, докато свойството document.readyState бъде настроено да завърши
- нетърпелив - изчакайте, докато свойството document.readyState е настроено на интерактивно
- няма - изобщо не чакайте
Разбира се, и в този случай трябва да поемете отговорността да изчакате „разтоварването“ на страниците.
Ето същия пример, този път без изчакване, но с различна стратегия за изчакване:
В този сценарий скриптътсъщо работи за около 10 секунди (без времето за стартиране на браузъра).
P.S. Мисля, че разбирате, че използвайки само имплицитни чакания, триковете, описани по-горе, няма да работят.