Programing

문서가 준비 될 때까지 셀레늄 대기

crosscheck 2020. 7. 11. 10:03
반응형

문서가 준비 될 때까지 셀레늄 대기


누구든지 페이지가 완전히로드 될 때까지 어떻게 셀레늄을 기다릴 수 있습니까? 나는 일반적인 것을 원한다. WebDriverWait를 구성하고 'find'와 같은 것을 호출하여 기다릴 수는 있지만 멀리 가지 않는다는 것을 알고있다. 페이지가 성공적으로로드되는지 테스트하고 다음 페이지로 이동하여 테스트하십시오.

.net에서 무언가를 찾았지만 Java에서 작동시키지 못했습니다 ...

IWait<IWebDriver> wait = new OpenQA.Selenium.Support.UI.WebDriverWait(driver, TimeSpan.FromSeconds(30.00));
wait.Until(driver1 => ((IJavaScriptExecutor)driver).ExecuteScript("return document.readyState").Equals("complete"));

어떤 생각이라도?


이 코드를 사용해보십시오 :

  driver.manage().timeouts().pageLoadTimeout(10, TimeUnit.SECONDS);

위의 코드는 페이지로드를 위해 최대 10 초 동안 대기합니다. 페이지 로딩이 시간을 초과하면을 던집니다 TimeoutException. 당신은 예외를 잡아서 당신의 필요를합니다. 예외가 발생한 후 페이지 로딩이 종료되는지 확실하지 않습니다. 아직이 코드를 시도하지 않았습니다. 그냥 시도하고 싶습니다.

이것은 암묵적인 대기입니다. 이 설정을 한 번 설정하면 웹 드라이버 인스턴스가 삭제 될 때까지 범위가 설정됩니다.

자세한 내용은 설명서를WebDriver.Timeouts 참조하십시오 .


제안 된 솔루션은 DOMreadyState 신호 만 기다립니다 complete. 그러나 Selenium은 기본적으로 driver.get()and element.click()메소드 를 통해 페이지로드에있는 것들 (그리고 조금 더)을 기다리려고 합니다. 그들은 이미 차단하고 있으며 페이지가 완전히로드 될 때까지 기다렸다가 정상적으로 작동해야합니다.

분명히 문제는 AJAX 요청과 실행 스크립트를 통한 리디렉션입니다. Selenium은이를 잡을 수 없으며 완료 될 때까지 기다리지 않습니다. 또한, 당신은 그들을 통해 확실하게 잡을 수 없습니다 readyState-그것은 조금 기다립니다, 유용 할 수 있지만, complete모든 AJAX 내용이 다운로드되기 오래 전에 신호를 보냅니다 .

어느 곳에서나 모든 사람에게 적용되는 일반적인 솔루션은 없기 때문에 어렵고 모든 사람이 조금 다른 것을 사용합니다.

일반적인 규칙은 WebDriver를 사용하여 자신의 역할을 수행 한 다음 암시 적 대기를 사용한 다음 페이지에서 주장하려는 요소에 대한 명시 적 대기를 사용하는 것이지만 수행 할 수있는 더 많은 기술이 있습니다. 테스트 한 페이지에서 귀하의 경우에 가장 적합한 것을 선택해야합니다.

자세한 내용은 이에 관한 두 가지 답변을 참조하십시오.


이것은 당신이 준 예제의 작동하는 Java 버전입니다.

void waitForLoad(WebDriver driver) {
    new WebDriverWait(driver, 30).until((ExpectedCondition<Boolean>) wd ->
            ((JavascriptExecutor) wd).executeScript("return document.readyState").equals("complete"));
}

c #의 예 :

public static void WaitForLoad(IWebDriver driver, int timeoutSec = 15)
{
  IJavaScriptExecutor js = (IJavaScriptExecutor)driver;
  WebDriverWait wait = new WebDriverWait(driver, new TimeSpan(0, 0, timeoutSec));
  wait.Until(wd => js.ExecuteScript("return document.readyState").ToString() == "complete");
}

다음은 파이썬에서 완전히 일반적인 솔루션을 시도한 것입니다.

먼저, 일반적인 "대기"기능 (원하는 경우 WebDriverWait을 사용하면 추악합니다) :

def wait_for(condition_function):
    start_time = time.time()
    while time.time() < start_time + 3:
        if condition_function():
            return True
        else:
            time.sleep(0.1)
    raise Exception('Timeout waiting for {}'.format(condition_function.__name__))

다음으로 솔루션은 셀레늄이 최상위 <html>요소를 포함하여 페이지의 모든 요소에 대해 (내부) id 번호를 기록한다는 사실에 의존합니다 . 페이지를 새로 고치거나로드하면 새 ID를 가진 새로운 html 요소가 표시됩니다.

예를 들어, "my link"라는 텍스트가있는 링크를 클릭한다고 가정하면 다음과 같습니다.

old_page = browser.find_element_by_tag_name('html')

browser.find_element_by_link_text('my link').click()

def page_has_loaded():
    new_page = browser.find_element_by_tag_name('html')
    return new_page.id != old_page.id

wait_for(page_has_loaded)

더 파이썬적이고 재사용 가능한 일반 도우미를 위해 컨텍스트 관리자를 만들 수 있습니다.

from contextlib import contextmanager

@contextmanager
def wait_for_page_load(browser):
    old_page = browser.find_element_by_tag_name('html')

    yield

    def page_has_loaded():
        new_page = browser.find_element_by_tag_name('html')
        return new_page.id != old_page.id

    wait_for(page_has_loaded)

그리고 거의 모든 셀레늄 상호 작용에 사용할 수 있습니다.

with wait_for_page_load(browser):
    browser.find_element_by_link_text('my link').click()

방탄이라고 생각합니다! 어떻게 생각해?

블로그 게시물에 대한 자세한 정보는 여기


나는 비슷한 문제가 있었다. 문서가 준비 될 때까지 모든 Ajax 호출이 완료 될 때까지 기다려야했습니다. 두 번째 조건은 감지하기 어려운 것으로 판명되었습니다. 결국 나는 활성 Ajax 호출을 확인했고 작동했습니다.

자바 스크립트 :

return (document.readyState == 'complete' && jQuery.active == 0)

전체 C # 방법 :

private void WaitUntilDocumentIsReady(TimeSpan timeout)
{
    var javaScriptExecutor = WebDriver as IJavaScriptExecutor;
    var wait = new WebDriverWait(WebDriver, timeout);            

    // Check if document is ready
    Func<IWebDriver, bool> readyCondition = webDriver => javaScriptExecutor
        .ExecuteScript("return (document.readyState == 'complete' && jQuery.active == 0)");
    wait.Until(readyCondition);
}

WebDriverWait wait = new WebDriverWait(dr, 30);
wait.until(ExpectedConditions.jsReturnsValue("return document.readyState==\"complete\";"));

C # NUnit의 경우 WebDriver를 JSExecuter로 변환 한 다음 document.ready 상태가 완료되었는지 여부를 확인하기 위해 스크립트를 실행해야합니다. 아래 코드를 참조하십시오.

 public static void WaitForLoad(IWebDriver driver)
    {
        IJavaScriptExecutor js = (IJavaScriptExecutor)driver;
        int timeoutSec = 15;
        WebDriverWait wait = new WebDriverWait(driver, new TimeSpan(0, 0, timeoutSec));
        wait.Until(wd => js.ExecuteScript("return document.readyState").ToString() == "complete");
    }

조건이 충족되거나 시간 초과 될 때까지 기다립니다.


초기 페이지로드의 경우 브라우저 창을 "최대화"하면 실제로 페이지로드가 완료 될 때까지 기다립니다 (소스 포함).

바꾸다:

AppDriver.Navigate().GoToUrl(url);

와:

public void OpenURL(IWebDriver AppDriver, string Url)
            {
                try
                {
                    AppDriver.Navigate().GoToUrl(Url);
                    AppDriver.Manage().Window.Maximize();
                    AppDriver.SwitchTo().ActiveElement();
                }
                catch (Exception e)
                {
                    Console.WriteLine("ERR: {0}; {1}", e.TargetSite, e.Message);
                    throw;
                }
            }

사용보다 :

OpenURL(myDriver, myUrl);

그러면 페이지가로드되고 완료 될 때까지 기다렸다가 최대화하고 초점을 맞 춥니 다. 왜 그런지 모르겠지만 작동합니다.

다음 또는 "Navigate ()"이외의 다른 페이지 탐색 트리거를 클릭 한 후 페이지로드를 기다리려면 Ben Dyer의 답변 (이 스레드에서)이 작동합니다.


태피스트리 웹 프레임 워크를 살펴보십시오 . 거기에서 소스 코드다운로드 할 수 있습니다 .

아이디어는 본문의 html 속성으로 페이지가 준비되었음을 신호하는 것입니다. 복잡한 아이디어 사례를 무시하고이 아이디어를 사용할 수 있습니다.

<html>
<head>
</head>
<body data-page-initialized="false">
    <p>Write you page here</p>

    <script>
    $(document).ready(function () {
        $(document.body).attr('data-page-initialized', 'true');
    });
    </script>  
</body>
</html>

그리고 태피스트리 프레임 워크에 따라 Selenium 웹 드라이버의 확장을 만듭니다.

public static void WaitForPageToLoad(this IWebDriver driver, int timeout = 15000)
{
    //wait a bit for the page to start loading
    Thread.Sleep(100);

    //// In a limited number of cases, a "page" is an container error page or raw HTML content
    // that does not include the body element and data-page-initialized element. In those cases,
    // there will never be page initialization in the Tapestry sense and we return immediately.
    if (!driver.ElementIsDisplayed("/html/body[@data-page-initialized]"))
    {                
        return;
    }

    Stopwatch stopwatch = Stopwatch.StartNew();

    int sleepTime = 20;

    while(true)
    {
        if (driver.ElementIsDisplayed("/html/body[@data-page-initialized='true']"))
        {
            return;
        }

        if (stopwatch.ElapsedMilliseconds > 30000)
        {
            throw new Exception("Page did not finish initializing after 30 seconds.");
        }

        Thread.Sleep(sleepTime);
        sleepTime *= 2; // geometric row of sleep time
    }          
}

Alister Scott이 작성한 확장 ElementIsDisplayed를 사용하십시오 .

public static bool ElementIsDisplayed(this IWebDriver driver, string xpath)
{
    try
    {
        return driver.FindElement(By.XPath(xpath)).Displayed;
    }
    catch(NoSuchElementException)
    {
        return false;
    }
}

그리고 마지막으로 테스트를 만듭니다.

driver.Url = this.GetAbsoluteUrl("/Account/Login");            
driver.WaitForPageToLoad();

Ben Dryer의 답변이 내 컴퓨터에서 컴파일되지 않았습니다 ( "The method until(Predicate<WebDriver>) is ambiguous for the type WebDriverWait").

작동하는 Java 8 버전 :

Predicate<WebDriver> pageLoaded = wd -> ((JavascriptExecutor) wd).executeScript(
        "return document.readyState").equals("complete");
new FluentWait<WebDriver>(driver).until(pageLoaded);

자바 7 버전 :

Predicate<WebDriver> pageLoaded = new Predicate<WebDriver>() {

        @Override
        public boolean apply(WebDriver input) {
            return ((JavascriptExecutor) input).executeScript("return document.readyState").equals("complete");
        }

};
new FluentWait<WebDriver>(driver).until(pageLoaded);

나는이 코드를 시도하고 그것은 나를 위해 작동합니다. 다른 페이지로 이동할 때마다이 함수를 호출합니다

public static void waitForPageToBeReady() 
{
    JavascriptExecutor js = (JavascriptExecutor)driver;

    //This loop will rotate for 100 times to check If page Is ready after every 1 second.
    //You can replace your if you wants to Increase or decrease wait time.
    for (int i=0; i<400; i++)
    { 
        try 
        {
            Thread.sleep(1000);
        }catch (InterruptedException e) {} 
        //To check page ready state.

        if (js.executeScript("return document.readyState").toString().equals("complete"))
        { 
            break; 
        }   
      }
 }

Nodejs에서는 약속을 통해 얻을 수 있습니다 ...

이 코드를 작성하면 다음에 도달 할 때 페이지가 완전히로드되었는지 확인할 수 있습니다.

driver.get('www.sidanmor.com').then(()=> {
    // here the page is fully loaded!!!
    // do your stuff...
}).catch(console.log.bind(console));

이 코드를 작성하면 탐색하고 셀레늄이 3 초 동안 대기합니다.

driver.get('www.sidanmor.com');
driver.sleep(3000);
// you can't be sure that the page is fully loaded!!!
// do your stuff... hope it will be OK...

Selenium 문서에서 :

this.get (url) → Thenable

주어진 URL로 이동하도록 명령을 예약합니다.

문서의 로드완료 되면 해결 될 가능성을 리턴합니다 .

셀레늄 문서 (Nodejs)


이 코드가 여전히 경쟁 조건에 있기 때문에 document.ready 이벤트 대기는이 문제에 대한 전체 수정이 아닙니다. 때로는 클릭 이벤트가 처리되기 전에이 코드가 시작되어 브라우저가 시작되지 않았기 때문에 직접 반환됩니다. 아직 새 페이지를로드 중입니다.

일부 검색 후 Obay에서 테스트 염소 게시물을 발견 했는데이 문제에 대한 해결책이 있습니다. 해당 솔루션의 C # 코드는 다음과 같습니다.

 IWebElement page = null;
 ...
 public void WaitForPageLoad()
 {
    if (page != null)
    {
       var waitForCurrentPageToStale = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
       waitForCurrentPageToStale.Until(ExpectedConditions.StalenessOf(page));
    }

    var waitForDocumentReady = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
    waitForDocumentReady.Until((wdriver) => (driver as IJavaScriptExecutor).ExecuteScript("return document.readyState").Equals("complete"));

    page = driver.FindElement(By.TagName("html"));

}

`driver.navigate.gotourl 바로 다음에이 메소드를 실행하여 가능한 빨리 페이지의 참조를 얻습니다. 재미있게 보내세요!


셀레늄이 클릭 또는 제출 또는 메소드 가져 오기에서 새 페이지를 열면 페이지가로드 될 때까지 기다릴 것이지만 문제는 페이지에 xhr 호출 (ajax)이있을 때 xhr 이로 드 될 때까지 기다리지 않을 것입니다. xhr을 모니터링하고 그들을 기다리는 새로운 방법을 만드는 것이 좋습니다.

public boolean waitForJSandJQueryToLoad() {
    WebDriverWait wait = new WebDriverWait(webDriver, 30);
    // wait for jQuery to load
    ExpectedCondition<Boolean> jQueryLoad = new ExpectedCondition<Boolean>() {
      @Override
      public Boolean apply(WebDriver driver) {
        try {
            Long r = (Long)((JavascriptExecutor)driver).executeScript("return $.active");
            return r == 0;
        } catch (Exception e) {
            LOG.info("no jquery present");
            return true;
        }
      }
    };

    // wait for Javascript to load
    ExpectedCondition<Boolean> jsLoad = new ExpectedCondition<Boolean>() {
      @Override
      public Boolean apply(WebDriver driver) {
        return ((JavascriptExecutor)driver).executeScript("return document.readyState")
        .toString().equals("complete");
      }
    };

  return wait.until(jQueryLoad) && wait.until(jsLoad);
}

if $.active == 0따라서 활성 xhrs 호출이 없습니다 (jQuery에서만 작동). 자바 스크립트 아약스 호출의 경우 프로젝트에서 변수를 생성하고 시뮬레이션해야합니다.


이것을 처리하기 위해 몇 가지 논리를 작성할 수 있습니다. 나는 반환 할 메소드를 작성 했으며이 WebElement메소드는 세 번 호출되거나 시간을 늘리고 null 검사를 추가 할 수 있습니다. WebElement여기에 예가 있습니다.

public static void main(String[] args) {
        WebDriver driver = new FirefoxDriver();
        driver.get("https://www.crowdanalytix.com/#home");
        WebElement webElement = getWebElement(driver, "homekkkkkkkkkkkk");
        int i = 1;
        while (webElement == null && i < 4) {
            webElement = getWebElement(driver, "homessssssssssss");
            System.out.println("calling");
            i++;
        }
        System.out.println(webElement.getTagName());
        System.out.println("End");
        driver.close();
    }

    public static WebElement getWebElement(WebDriver driver, String id) {
        WebElement myDynamicElement = null;
        try {
            myDynamicElement = (new WebDriverWait(driver, 10))
                    .until(ExpectedConditions.presenceOfElementLocated(By
                            .id(id)));
            return myDynamicElement;
        } catch (TimeoutException ex) {
            return null;
        }
    }

문서가 준비되었는지 확인하기 위해 자바 스크립트 코드를 실행했습니다. 클라이언트 쪽 렌더링이있는 사이트에 대한 셀레늄 테스트를 디버깅하는 데 많은 시간을 절약했습니다.

public static boolean waitUntilDOMIsReady(WebDriver driver) {
def maxSeconds = DEFAULT_WAIT_SECONDS * 10
for (count in 1..maxSeconds) {
    Thread.sleep(100)
    def ready = isDOMReady(driver);
    if (ready) {
        break;
    }
}

}

public static boolean isDOMReady(WebDriver driver){
    return driver.executeScript("return document.readyState");
}

public boolean waitForElement(String zoneName, String element, int index, int timeout) {
        WebDriverWait wait = new WebDriverWait(appiumDriver, timeout/1000);
        wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath(element)));
        return true;
    }

Rubanov가 C #을 위해 쓴 것처럼 Java를 위해 쓰고 다음과 같습니다.

    public void waitForPageLoaded() {
    ExpectedCondition<Boolean> expectation = new
            ExpectedCondition<Boolean>() {
                public Boolean apply(WebDriver driver) {
                    return (((JavascriptExecutor) driver).executeScript("return document.readyState").toString().equals("complete")&&((Boolean)((JavascriptExecutor)driver).executeScript("return jQuery.active == 0")));
                }
            };
    try {
        Thread.sleep(100);
        WebDriverWait waitForLoad = new WebDriverWait(driver, 30);
        waitForLoad.until(expectation);
    } catch (Throwable error) {
        Assert.fail("Timeout waiting for Page Load Request to complete.");
    }
}

Java에서는 다음과 같습니다.

  private static boolean isloadComplete(WebDriver driver)
    {
        return ((JavascriptExecutor) driver).executeScript("return document.readyState").equals("loaded")
                || ((JavascriptExecutor) driver).executeScript("return document.readyState").equals("complete");
    }

다음 코드가 작동해야합니다.

WebDriverWait wait = new WebDriverWait(driver, 10);
wait.until(ExpectedConditions.presenceOfAllElementsLocated(By.xpath("//*")));

If you have a slow page or network connection, chances are that none of the above will work. I have tried them all and the only thing that worked for me is to wait for the last visible element on that page. Take for example the Bing webpage. They have placed a CAMERA icon (search by image button) next to the main search button that is visible only after the complete page has loaded. If everyone did that, then all we have to do is use an explicit wait like in the examples above.


public void waitForPageToLoad()
  {
(new WebDriverWait(driver, DEFAULT_WAIT_TIME)).until(new ExpectedCondition<Boolean>() {
      public Boolean apply(WebDriver d) {
        return (((org.openqa.selenium.JavascriptExecutor) driver).executeScript("return document.readyState").equals("complete"));
      }
    });//Here DEFAULT_WAIT_TIME is a integer correspond to wait time in seconds

Here's something similar, in Ruby:

wait = Selenium::WebDriver::Wait.new(:timeout => 10)
wait.until { @driver.execute_script('return document.readyState').eql?('complete') }

You can have the thread sleep till the page is reloaded. This is not the best solution, because you need to have an estimate of how long does the page take to load.

driver.get(homeUrl); 
Thread.sleep(5000);
driver.findElement(By.xpath("Your_Xpath_here")).sendKeys(userName);
driver.findElement(By.xpath("Your_Xpath_here")).sendKeys(passWord);
driver.findElement(By.xpath("Your_Xpath_here")).click();

I Checked page load complete, work in Selenium 3.14.0

    public static void UntilPageLoadComplete(IWebDriver driver, long timeoutInSeconds)
    {
        Until(driver, (d) =>
        {
            Boolean isPageLoaded = (Boolean)((IJavaScriptExecutor)driver).ExecuteScript("return document.readyState").Equals("complete");
            if (!isPageLoaded) Console.WriteLine("Document is loading");
            return isPageLoaded;
        }, timeoutInSeconds);
    }

    public static void Until(IWebDriver driver, Func<IWebDriver, Boolean> waitCondition, long timeoutInSeconds)
    {
        WebDriverWait webDriverWait = new WebDriverWait(driver, TimeSpan.FromSeconds(timeoutInSeconds));
        webDriverWait.Timeout = TimeSpan.FromSeconds(timeoutInSeconds);
        try
        {
            webDriverWait.Until(waitCondition);
        }
        catch (Exception e)
        {
            Console.WriteLine(e);
        }
    }

For the people who need to wait for a specific element to show up. (used c#)

public static void WaitForElement(IWebDriver driver, By element)
{
    WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(20));
    wait.Until(ExpectedConditions.ElementIsVisible(element));
}

그런 다음 DOM에 class = "error-message"가있는 경우를 기다리려면 간단히 수행하십시오.

WaitForElement(driver, By.ClassName("error-message"));

id의 경우

WaitForElement(driver, By.Id("yourid"));


Angular를 사용하고 있습니까? 가능한 경우 웹 드라이버가 비동기 호출이 완료되었음을 인식하지 못할 수 있습니다.

Paul Hammants ngWebDriver를 보는 것이 좋습니다 . waitForAngularRequestsToFinish () 메소드가 유용 할 수 있습니다.

참고 URL : https://stackoverflow.com/questions/15122864/selenium-wait-until-document-is-ready

반응형