使用异步 linq 过滤 Puppeter Sharp 的 ElementHandle[]
Filtering Puppeter Sharp's ElementHandle[] with async linq
我一直在用 Puppeter Sharp 重写我的 Selenium 应用程序以了解有关该框架的更多信息。我的应用程序运行在我无权修改其源代码的网站上,我只是收集了一些信息。
基于此,我使用 Selenium 编写了一个函数,可以在 IEnumerable<IWebElement>
中过滤所需的元素,这样:
var element = Driver.FindElements(By.Id("User"))
.First(x =>
x.Text.ToLower().Trim() == "AAA" &&
x.FindElement(By.Id("contact")).Text.ToLower().Trim() == "BBB")
.FindElement(By.XPath("../input"));
但是我无法使用 Puppeteer Sharp 编写代码来做同样的事情。我写的最准确的方法是:
var users = await Page.QuerySelectorAllAsync("#User");
var baseElement = users.First(async x =>
(await x.JsonValueAsync<string>()).ToLower().Trim() == "AAA" &&
(await (await x.QuerySelectorAsync("#contact")).JsonValueAsync<string>()).ToLower().Trim() == "BBB");
var element = await baseElement.XPathAsync("../input");
上面的代码还是return我报错了:
Cannot convert async lambda expression to delegate type 'Func'.
是的,这是有道理的,但我无法找到另一种使用 linq 的方法,以使其至少清晰易读。
编辑:
Html 示例如下:我需要 return 基于攻击名称和类型的无线电输入。我知道我可以写一个很棒的、丑陋的和难以辨认的 xpath 来为我查询它,但我试图做一个更易读和更流畅的方法来更容易维护。
<div id="player">
<div class="attklist">
<h2>Choose an Attack</h2>
<ul>
<li class="batsel" style="cursor: pointer;">
<input type="radio" value="1" name="selected" checked="checked" id="atkopt1">
<label for="atkopt1">Strength
<br><span class="tbtn tbtn-normal">normal</span>
</label>
</li>
<li style="cursor: pointer;">
<input type="radio" value="2" name="selected" id="atkopt2">
<label for="atkopt2">Strength
<br><span class="tbtn tbtn-fighting">fighting</span>
</label>
</li>
<li style="cursor: pointer;">
<input type="radio" value="3" name="selected" id="atkopt3">
<label for="atkopt3">Spectre Slash
<br><span class="tbtn tbtn-ghost">ghost</span>
</label>
</li>
<li style="cursor: pointer;">
<input type="radio" value="4" name="selected" id="atkopt4">
<label for="atkopt4">Fire Puch
<br><span class="tbtn tbtn-fire">fire</span>
</label>
</li>
</ul>
</div>
</div>
从技术上讲,这是 Linq 方法中缺少的功能。编写 Async Linq 函数并不是那么简单。
另一方面,我发现直接在 javascript 中实施起来要简单得多。为什么?因为您可以在浏览器中测试脚本,然后将其移至 C# 代码。
例如,此方法将查找所有 li
元素,查找具有文本 fire
跨度的 li
然后单击输入。
await page.EvaluateFunctionAsync(@"() => {
Array.from(document.querySelectorAll('li'))
.find(l => l.querySelector('span').innerText === 'fire').querySelector('INPUT').click();
}");
我一直在用 Puppeter Sharp 重写我的 Selenium 应用程序以了解有关该框架的更多信息。我的应用程序运行在我无权修改其源代码的网站上,我只是收集了一些信息。
基于此,我使用 Selenium 编写了一个函数,可以在 IEnumerable<IWebElement>
中过滤所需的元素,这样:
var element = Driver.FindElements(By.Id("User"))
.First(x =>
x.Text.ToLower().Trim() == "AAA" &&
x.FindElement(By.Id("contact")).Text.ToLower().Trim() == "BBB")
.FindElement(By.XPath("../input"));
但是我无法使用 Puppeteer Sharp 编写代码来做同样的事情。我写的最准确的方法是:
var users = await Page.QuerySelectorAllAsync("#User");
var baseElement = users.First(async x =>
(await x.JsonValueAsync<string>()).ToLower().Trim() == "AAA" &&
(await (await x.QuerySelectorAsync("#contact")).JsonValueAsync<string>()).ToLower().Trim() == "BBB");
var element = await baseElement.XPathAsync("../input");
上面的代码还是return我报错了:
Cannot convert async lambda expression to delegate type 'Func'.
是的,这是有道理的,但我无法找到另一种使用 linq 的方法,以使其至少清晰易读。
编辑:
Html 示例如下:我需要 return 基于攻击名称和类型的无线电输入。我知道我可以写一个很棒的、丑陋的和难以辨认的 xpath 来为我查询它,但我试图做一个更易读和更流畅的方法来更容易维护。
<div id="player">
<div class="attklist">
<h2>Choose an Attack</h2>
<ul>
<li class="batsel" style="cursor: pointer;">
<input type="radio" value="1" name="selected" checked="checked" id="atkopt1">
<label for="atkopt1">Strength
<br><span class="tbtn tbtn-normal">normal</span>
</label>
</li>
<li style="cursor: pointer;">
<input type="radio" value="2" name="selected" id="atkopt2">
<label for="atkopt2">Strength
<br><span class="tbtn tbtn-fighting">fighting</span>
</label>
</li>
<li style="cursor: pointer;">
<input type="radio" value="3" name="selected" id="atkopt3">
<label for="atkopt3">Spectre Slash
<br><span class="tbtn tbtn-ghost">ghost</span>
</label>
</li>
<li style="cursor: pointer;">
<input type="radio" value="4" name="selected" id="atkopt4">
<label for="atkopt4">Fire Puch
<br><span class="tbtn tbtn-fire">fire</span>
</label>
</li>
</ul>
</div>
</div>
从技术上讲,这是 Linq 方法中缺少的功能。编写 Async Linq 函数并不是那么简单。
另一方面,我发现直接在 javascript 中实施起来要简单得多。为什么?因为您可以在浏览器中测试脚本,然后将其移至 C# 代码。
例如,此方法将查找所有 li
元素,查找具有文本 fire
跨度的 li
然后单击输入。
await page.EvaluateFunctionAsync(@"() => {
Array.from(document.querySelectorAll('li'))
.find(l => l.querySelector('span').innerText === 'fire').querySelector('INPUT').click();
}");