java web crawler:使用selenium + webdriver

时间:2018-01-30 09:03:04

标签: java selenium selenium-webdriver webdriver web-crawler

背景

点击链接后,目标页面的请求由js发起。

所以我计划使用selenium + webdriver来模拟点击并获取页面数据。(我首先使用chrome驱动程序进行调试)

父页面如下:

the parent page

很明显,我无法直接获取链接'页面上的网址。

以下步骤如下:

  1. 定义链接列表
  2. 遍历列表元素,单击链接并获取相应的页面
  3. 通过页面句柄跳转到子页面,获取目标数据并返回到父页面
  4. 继续遍历,直到循环结束
  5. 问题

    根据上述逻辑,错误发生在第二次。

    第一个问题:

    org.openqa.selenium.StaleElementReferenceException: stale element reference: element is not attached to the page document

    我的代码:

    int pageIndex = Integer.parseInt(driver.findElement(By.xpath("//*[@id=\"mainContent\"]/div[2]/div[2]/div[1]/table/tfoot/tr[2]/td/div/ul/li[1]/span/font[3]")).getText());
    int pageSize = Integer.parseInt(driver.findElement(By.xpath("//*[@id=\"mainContent\"]/div[2]/div[2]/div[1]/table/tfoot/tr[2]/td/div/ul/li[1]/span/font[2]")).getText());
    while (pageIndex <= pageSize) {
        pageIndex++;
        WebElement tbody = driver.findElement(By.ByXPath.xpath("//*[@id=\"mainContent\"]/div[2]/div[2]/div[1]/table/tbody"));
        List<WebElement> links = tbody.findElements(By.cssSelector("a[class=ng-binding]"));
        for (WebElement link : links) {
            WebDriver window;
            System.out.println("-------------- voucherNo: " + link.getText());
            scrollToElementAndClick(link);
            currentWindow = driver.getWindowHandle();
            //get all windows
            Set<String> handles = driver.getWindowHandles();
            for (String s : handles) {
                //current page is don't close
                if (s.equals(currentWindow) || s.equals(parentWindow))
                    continue;
                else {
                    window = driver.switchTo().window(s);
                    window.manage().window().maximize();
                    window.manage().timeouts().implicitlyWait(60, TimeUnit.SECONDS);
                    window.manage().timeouts().pageLoadTimeout(60, TimeUnit.SECONDS);
                    //get all tables
                    String pageSource = window.getPageSource();
                    String jsonArray = parseDTO(pageSource);
                    System.out.println(jsonArray);
                    //close the table window
                    window.close();
                }
                //swich to current window
                driver.switchTo().window(currentWindow);
            }
        }
        // click next page
        if (pageIndex <= pageSize) {
            WebElement nextPage = driver.findElement(By.xpath("//*[@id=\"mainContent\"]/div[2]/div[2]/div[1]/table/tfoot/tr[2]/td/div/ul/li[3]/a"));
            scrollToElementAndClick(nextPage);
            //set next page to current page
            driver = driver.switchTo().window(driver.getWindowHandle());
            driver.manage().window().maximize();
            driver.manage().timeouts().implicitlyWait(60, TimeUnit.SECONDS);
            driver.manage().timeouts().pageLoadTimeout(60, TimeUnit.SECONDS);
        }
    }
    

    我在stackoverflow中搜索了类似的问题,但解决方案不起作用。我去官方网站看错误陈述

    原因应该是当我切换到子页面时,父页面会刷新。尽管可以在UI上看到链接,但之前定义的链接列表与当前父页面并不对应(我理解这种方式,如果我误解了,请指出)。

    所以我修改了代码:

    while (pageIndex <= pageSize) {
        pageIndex++;
        WebElement tbody = driver.findElement(By.ByXPath.xpath("//*[@id=\"mainContent\"]/div[2]/div[2]/div[1]/table/tbody"));
        List<WebElement> links = tbody.findElements(By.cssSelector("a[class=ng-binding]"));
        int size = links.size();
    
        for (int i = 1; i <= size; i++) {
        String href = String.format("//*[@id=\"mainContent\"]/div[2]/div[2]/div[1]/table/tbody/tr[%s]/td[2]/a", i);
        WebElement link = driver.findElement(By.xpath(href));
        WebDriver window;
        System.out.println("-------------- voucherNo: " + link.getText());
        scrollToElementAndClick(link);
            currentWindow = driver.getWindowHandle();
            //get all windows
            Set<String> handles = driver.getWindowHandles();
            for (String s : handles) {
                //current page is don't close
                if (s.equals(currentWindow) || s.equals(parentWindow))
                    continue;
                else {
                    window = driver.switchTo().window(s);
                    window.manage().window().maximize();
                    window.manage().timeouts().implicitlyWait(60, TimeUnit.SECONDS);
                    window.manage().timeouts().pageLoadTimeout(60, TimeUnit.SECONDS);
                    //get all tables
                    String pageSource = window.getPageSource();
                    String jsonArray = parseDTO(pageSource);
                    System.out.println(jsonArray);
                    //close the table window
                    window.close();
                }
                //swich to current window
                driver.switchTo().window(currentWindow);
            }
        }
    
        // click next page
        if (pageIndex <= pageSize) {
            WebElement nextPage = driver.findElement(By.xpath("//*[@id=\"mainContent\"]/div[2]/div[2]/div[1]/table/tfoot/tr[2]/td/div/ul/li[3]/a"));
            scrollToElementAndClick(nextPage);
            //set next page to current page
            driver = driver.switchTo().window(driver.getWindowHandle());
            driver.manage().window().maximize();
            driver.manage().timeouts().implicitlyWait(60, TimeUnit.SECONDS);
            driver.manage().timeouts().pageLoadTimeout(60, TimeUnit.SECONDS);
        }
    }
    

    链接&#39; Xpath定期更改:

    //*[@id="mainContent"]/div[2]/div[2]/div[1]/table/tbody/tr[1]/td[2]/a
    //*[@id="mainContent"]/div[2]/div[2]/div[1]/table/tbody/tr[2]/td[2]/a
    //*[@id="mainContent"]/div[2]/div[2]/div[1]/table/tbody/tr[3]/td[2]/a
    //*[@id="mainContent"]/div[2]/div[2]/div[1]/table/tbody/tr[%s]/td[2]/a
    

    然后发生第二次排队:

      

    引起:org.openqa.selenium.NoSuchElementException:{&#34; errorMessage&#34;:&#34;无法找到带有xpath的元素

    嗯......我无法理解为什么我无法获得webElement。它就在页面上。

    加成

    好吧,我注意到在那个问题中,链接url可以从页面获取。该问题的接受答案使用字符串列表来存储链接href。并使用((JavascriptExecutor) driver).executeScript("window.open(arguments[0]),myhref);执行它们。但就我而言,我无法获得网址。我需要逐个点击链接。

0 个答案:

没有答案