Фильтрация Puppeter Sharp's ElementHandle[] с помощью async linq

Я переписывал свое приложение Selenium в Puppeter Sharp, чтобы узнать больше об этой платформе. Мое приложение работает на сайте, к которому у меня нет доступа, чтобы изменить его источник, я только собираю некоторую информацию.

Исходя из этого, я написал функцию с использованием 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");

Код выше все еще возвращает мне ошибку:

Невозможно преобразовать асинхронное лямбда-выражение в тип делегата "Func".

Да, это имеет смысл, но я не смог найти другой подход с linq, чтобы сделать его хотя бы разборчивым и небольшим.

Редактировать:

Пример HTML ниже: мне нужно вернуть радио вход, основанный на названии и типе атаки. Я понимаю, что могу написать отличный, уродливый и неразборчивый 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>

1 ответ

Решение

Технически говоря, это недостающая особенность методов Linq. Кодировать функции Async Linq не так просто.

С другой стороны, я считаю, что это гораздо проще реализовать прямо в javascript. Зачем? потому что вы можете проверить свой скрипт в браузере, а затем просто переместить его в код C#.

Например, этот метод найдет все li элементы, найти li с пролетом с текстом fire а затем нажмите на вход.

await page.EvaluateFunctionAsync(@"() => {
     Array.from(document.querySelectorAll('li'))
         .find(l => l.querySelector('span').innerText === 'fire').querySelector('INPUT').click();
}");
Другие вопросы по тегам