具有URI的多线程C#Selenium WebDriver自动化,事先不知道
我需要同时执行一些webdrivers操作,但我不确定如何做到这一点 我想问的是:具有URI的多线程C#Selenium WebDriver自动化,事先不知道,c#,multithreading,selenium-webdriver,webautomation,C#,Multithreading,Selenium Webdriver,Webautomation,我需要同时执行一些webdrivers操作,但我不确定如何做到这一点 我想问的是: 实现这一目标的正确方法是什么 我收到异常的原因是什么(如下所示) 经过一些研究,我最终得出以下结论: 1。我看到人们这样做的方式(以及我在玩API之后在搜索之前使用的方式)是循环我的WebDriver手头上的窗口句柄,并在我想要处理的窗口句柄之间执行切换,完成后将其关闭 2。Selenium Grid对我来说似乎不是一个选项——我是错了还是它是用于并行处理的?因为我在一台计算机上运行所有的东西,所以它对我没有用
在尝试第1个选项时,我有以下场景(下面有一个代码示例,我跳过了不相关的内容/重复本身(我曾经添加了3个点): 我有一个html页面,有几个提交按钮,堆叠在一起 单击其中每一个将打开一个新的浏览器/选项卡(有趣的是,使用ChromeDriver会打开选项卡,而FirefoxDriver会为每个选项卡打开单独的窗口。) 作为旁注:我不能预先确定每次提交的URI(它们必须由javascript确定,在这一点上,让我们假设我想处理所有不知道客户端代码的事情) 现在,在遍历所有提交按钮并在相应元素上发出webElement.Click()之后,选项卡/窗口将打开。代码将创建要执行的任务列表,每个新选项卡/窗口一个 问题在于:由于所有任务都依赖于同一个webdriver实例切换到窗口句柄,似乎我需要添加资源共享锁/控制。我不确定我是否正确,因为我在搜索多线程web驱动程序示例时没有提到锁/资源访问控制 另一方面,如果我能够事先确定选项卡/windows URI,我将能够跳过达到这一点所需的所有自动化步骤,然后通过
Navigate().gotour()为每个线程创建一个webDriver实例
会很简单。但这看起来像是一个死锁!我看不到webDriver的API在不执行切换的情况下提供对新打开的选项卡/窗口的任何访问。我只想在不必重复导致我进入当前窗口的所有自动化步骤的情况下进行切换
在任何情况下,我都会遇到一个例外:
元素属于与当前帧不同的帧-切换到其包含帧以使用它
在
在ToDictionary()块中
显然,我在chrome的控制台上检查了我所有的选择器是否都返回了结果
foreach (WebElement resultSet in resultSets)
resultSet.Click();
foreach(string windowHandle in webDriver.WindowHandles.Skip(1))
{
dataCollectionTasks.Add(Task.Factory.StartNew<List<DataTable>>(obj =>
{
List<DataTable> collectedData = new List<DataTable>();
string window = obj as string;
if (window != null)
{
webDriver.SwitchTo().Window(windowHandle);
List<WebElement> dataSets = webDriver.FindElements(By.JQuerySelector(utils.GetAppSetting("selectors.ResultSetData"))).ToList();
DataTable data = null;
for (int i = 0; i < dataSets.Count; i += 2)
{
data = new DataTable();
data.Columns.Add("Col1", typeof(string));
data.Columns.Add("Col2", typeof(string));
data.Columns.Add("Col3", typeof(string));
///...
//data set header
if (i % 2 != 0)
{
IWebElement headerElement = dataSets[i].FindElement(OpenQA.Selenium.By.CssSelector(utils.GetAppSetting("selectors.ResultSetDataHeader")));
data.TableName = string.Join(" ", headerElement.Text.Split().Take(3));
}
//data set records
else
{
Dictionary<string, string> cells = dataSets[i]
.FindElements(OpenQA.Selenium.By.CssSelector(utils.GetAppSetting("selectors.ResultSetDataCell")))
.ToDictionary(
cell =>
{
IWebElement element = cell.FindElement(OpenQA.Selenium.By.CssSelector(utils.GetAppSetting("selectors.ResultSetDataHeaderColumn")));
return element == null ? string.Empty : element.Text;
},
cell =>
{
return cell == null ? string.Empty : cell.Text;
});
string col1Value, col2Value, col3Value; //...
cells.TryGetValue("Col1", out col1Value);
cells.TryGetValue("Col2", out col2Value);
cells.TryGetValue("Col3", out col3Value);
//...
data.Rows.Add(col1Value, col2Value, col3Value /*...*/);
}
}
collectedData.Add(data);
}
webDriver.SwitchTo().Window(mainWindow);
webDriver.Close();
return collectedData;
}, windowHandle));
} //foreach
Task.WaitAll(dataCollectionTasks.ToArray());
foreach (Task<List<DataTable>> dataCollectionTask in dataCollectionTasks)
{
results.AddRange(dataCollectionTask.Result);
}
return results;
foreach(结果集中的WebElement结果集)
resultSet.Click();
foreach(webDriver.WindowHandles.Skip(1)中的字符串windowHandle)
{
dataCollectionTasks.Add(Task.Factory.StartNew(obj=>
{
List collectedData=新列表();
字符串窗口=obj作为字符串;
如果(窗口!=null)
{
webDriver.SwitchTo().Window(windowHandle);
列表数据集=webDriver.FindElements(By.JQuerySelector(utils.GetAppSetting(“selectors.ResultSetData”)).ToList();
DataTable data=null;
对于(int i=0;i
{
IWebElement元素=cell.findelelement(OpenQA.Selenium.By.CssSelector(utils.GetAppSetting(“selectors.ResultSetDataHeaderColumn”));
返回元素==null?字符串。空:element.Text;
},
单元格=>
{
返回单元格==null?字符串。空:cell.Text;
});
字符串col1Value、col2Value、col3Value;//。。。
单元格。TryGetValue(“Col1”,out col1Value);
TryGetValue(“Col2”,out col2Value);
单元格。TryGetValue(“Col3”,out col3Value);
//...
data.Rows.Add(col1Value、col2Value、col3Value/*…*/);
}
}
收集数据。添加(数据);
}
webDriver.SwitchTo().Window(主窗口);
webDriver.Close();
返回收集的数据;
},窗柄);
}//foreach
Task.WaitAll(dataCollectionTasks.ToArray());
foreach(dataCollectionTasks中的TaskDataCollectionTask)
{
AddRange(dataCollectionTask.Result);
}
返回结果;
除非明确说明,否则大多数方法在调用实例成员时都不是线程安全的。在任务中使用webDriver
。Run
肯定是问题所在。您说“我还尝试创建了新的webDriver实例
foreach (WebElement resultSet in resultSets)
resultSet.Click();
foreach(string windowHandle in webDriver.WindowHandles.Skip(1))
{
dataCollectionTasks.Add(Task.Factory.StartNew<List<DataTable>>(obj =>
{
List<DataTable> collectedData = new List<DataTable>();
string window = obj as string;
if (window != null)
{
webDriver.SwitchTo().Window(windowHandle);
List<WebElement> dataSets = webDriver.FindElements(By.JQuerySelector(utils.GetAppSetting("selectors.ResultSetData"))).ToList();
DataTable data = null;
for (int i = 0; i < dataSets.Count; i += 2)
{
data = new DataTable();
data.Columns.Add("Col1", typeof(string));
data.Columns.Add("Col2", typeof(string));
data.Columns.Add("Col3", typeof(string));
///...
//data set header
if (i % 2 != 0)
{
IWebElement headerElement = dataSets[i].FindElement(OpenQA.Selenium.By.CssSelector(utils.GetAppSetting("selectors.ResultSetDataHeader")));
data.TableName = string.Join(" ", headerElement.Text.Split().Take(3));
}
//data set records
else
{
Dictionary<string, string> cells = dataSets[i]
.FindElements(OpenQA.Selenium.By.CssSelector(utils.GetAppSetting("selectors.ResultSetDataCell")))
.ToDictionary(
cell =>
{
IWebElement element = cell.FindElement(OpenQA.Selenium.By.CssSelector(utils.GetAppSetting("selectors.ResultSetDataHeaderColumn")));
return element == null ? string.Empty : element.Text;
},
cell =>
{
return cell == null ? string.Empty : cell.Text;
});
string col1Value, col2Value, col3Value; //...
cells.TryGetValue("Col1", out col1Value);
cells.TryGetValue("Col2", out col2Value);
cells.TryGetValue("Col3", out col3Value);
//...
data.Rows.Add(col1Value, col2Value, col3Value /*...*/);
}
}
collectedData.Add(data);
}
webDriver.SwitchTo().Window(mainWindow);
webDriver.Close();
return collectedData;
}, windowHandle));
} //foreach
Task.WaitAll(dataCollectionTasks.ToArray());
foreach (Task<List<DataTable>> dataCollectionTask in dataCollectionTasks)
{
results.AddRange(dataCollectionTask.Result);
}
return results;