Как создать новый экземпляр Selenium Webdiver для каждого потока в Parallel.ForEach? - PullRequest
0 голосов
/ 11 апреля 2019

Я хочу запустить параллельное выполнение искателя с помощью Selenium ChromeDriver.

Если я использую тот же экземпляр ChromeDriver в цикле ForEach, у меня возникают проблемы.

При попытке получить доступ к атрибутам документа HTML я получаю исключение:

OpenQA.Selenium.StaleElementReferenceException: stale element reference: element is not attached to the page document

возможно, потому что другой поток изменяет состояние экземпляра, прежде чем текущий поток сможет его прочитать.

Вот что у меня сейчас:

public class ChromeCrawler : IDisposable
{
    private readonly ChromeDriver _driver;

    public ChromeCrawler()
    {
        var chromeOptions = new ChromeOptions();
        chromeOptions.AddArguments("headless");
        _driver = new ChromeDriver(chromeOptions);
    }

    public string GetHTML(string url)
    {
        _driver.Navigate().GoToUrl(url);

        var html = _driver.FindElementsByTagName("html");
        var content = html.First().GetAttribute("innerHTML");    //<----- Here I get the exception

        return content;
    }
    ....
}

var crawler = new ChromeCrawler();

//Execution
Parallel.ForEach(pages_list, page_url =>
{
    var html = crawler.GetHTML(page_url );
    .....
});

Есть ли способ создать новый экземпляр ChromeCrawler для каждого потока Parallel.ForEach?

1 Ответ

0 голосов
/ 11 апреля 2019

Храните ваши драйверы в списке в отдельном классе, предназначенном для отслеживания всех драйверов, выполняющихся в настоящее время параллельно. В моем случае у меня есть класс BrowserController, который отслеживает текущие экземпляры драйверов и обрабатывает как создание, так и удаление драйверов. Для добавления нового драйвера используется такая функция:

    public Dictionary<string, RemoteWebDriver> Drivers;

    public RemoteWebDriver AddDriver(string testName, string url, ICapabilities capabilities)
    {
        var driver = new ThreadLocal<RemoteWebDriver>(() =>
        {
            return new RemoteWebDriver(new Uri(url), capabilities);
        }).Value;

        Drivers.Add(testName, driver);

        TestBase.StaticLogInfo($"Added driver for test: {testName}");
        return Drivers[testName];
    }
...