如何为Parallel.ForEach中的每个线程创建Selenium Webdiver的新实例?

时间:2019-04-11 09:02:55

标签: c# multithreading selenium selenium-chromedriver parallel.foreach

我想使用Selenium ChromeDriver并行执行搜寻器。

如果在ForEach循环中使用相同的ChromeDriver实例,则会遇到问题。

当尝试访问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 :(得分:0)

将驱动程序存储在单独类别的列表中,以跟踪当前并行执行的所有驱动程序。就我而言,我有一个名为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];
    }