C# Как продолжить выполнение кода JavaScript после перенаправления или обновления с помощью CefSharp

Мне нужно программно сделать 3 действия на сайте

  1. заполнение поискового ввода
  2. нажатие кнопки поиска

(после этого происходит запрос и страница возвращает мне результат поиска)

  1. нажав на первую ссылку

если я помещу действие 1 и 2 в кнопку 1:

private void Button1_Click(object sender, EventArgs e)
{
string jsScript1 = "document.getElementById('story').value=" + '\'' + textFind.Text + '\'' + ";" 
+ "document.querySelector('body > div.wrapper > div.header > div.header44 > div.search_panel > span > form > button').click();";
var task1 = chrome.EvaluateScriptAsync(jsScript1);
task1.Wait();
}

И действие 3 в кнопке 2:

private void Button2_Click(object sender, EventArgs e)
{
   string jsScript3 = "document.getElementsByTagName('a')[1].click();";
   var task3 = chrome.EvaluateScriptAsync(jsScript3);
   task3.Wait();
}

Все работает отлично. Но я хочу сделать все эти действия внутри одной кнопки.

Я нашел следующее решение:

private async void ButtonFind_Click(object sender, EventArgs e)
        {
//Action 1 & 2
string jsScript1 = "document.getElementById('story').value=" + '\'' + textFind.Text + '\'' + ";" 
+ "document.querySelector('body > div.wrapper > div.header > div.header44 > div.search_panel > span > form > button').click();";
await chrome.EvaluateScriptAsync(jsScript1);



            //Action3
            Thread.Sleep(1000); //it is necessary to set exactly 1 seconds
            string jsScript3 = "document.getElementsByTagName('a')[2].click();";
            await chrome.EvaluateScriptAsync(jsScript3);

        }

Я должен использовать Thread.Sleep(1000);, потому что в JavaScript перенаправление или нажатие кнопки поиска уничтожает все сценарии, запущенные в данный момент в браузере. Но я думаю, что использование Thread.Sleep или Task.Delay не очень хорошая идея. Как еще я могу изменить свой код без использования Thread.Sleep/Task.Delay?

3 метода стилизации элементов HTML
3 метода стилизации элементов HTML
Когда дело доходит до применения какого-либо стиля к нашему HTML, существует три подхода: встроенный, внутренний и внешний. Предпочтительным обычно...
Формы c голосовым вводом в React с помощью Speechly
Формы c голосовым вводом в React с помощью Speechly
Пытались ли вы когда-нибудь заполнить веб-форму в области электронной коммерции, которая требует много кликов и выбора? Вас попросят заполнить дату,...
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Будучи разработчиком веб-приложений, легко впасть в заблуждение, считая, что приложение без JavaScript не имеет права на жизнь. Нам становится удобно...
Flatpickr: простой модуль календаря для вашего приложения на React
Flatpickr: простой модуль календаря для вашего приложения на React
Если вы ищете пакет для быстрой интеграции календаря с выбором даты в ваше приложения, то библиотека Flatpickr отлично справится с этой задачей....
В чем разница между Promise и Observable?
В чем разница между Promise и Observable?
Разберитесь в этом вопросе, и вы значительно повысите уровень своей компетенции.
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Клиент для URL-адресов, cURL, позволяет взаимодействовать с множеством различных серверов по множеству различных протоколов с синтаксисом URL.
0
0
52
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Вы можете использовать что-то вроде следующего, чтобы дождаться загрузки страницы

// create a static class for the extension method 
public static Task<LoadUrlAsyncResponse> WaitForLoadAsync(this IWebBrowser browser)
{
    var tcs = new TaskCompletionSource<LoadUrlAsyncResponse>(TaskCreationOptions.RunContinuationsAsynchronously);

    EventHandler<LoadErrorEventArgs> loadErrorHandler = null;
    EventHandler<LoadingStateChangedEventArgs> loadingStateChangeHandler = null;

    loadErrorHandler = (sender, args) =>
    {
        //Actions that trigger a download will raise an aborted error.
        //Generally speaking Aborted is safe to ignore
        if (args.ErrorCode == CefErrorCode.Aborted)
        {
            return;
        }

        //If LoadError was called then we'll remove both our handlers
        //as we won't need to capture LoadingStateChanged, we know there
        //was an error
        browser.LoadError -= loadErrorHandler;
        browser.LoadingStateChanged -= loadingStateChangeHandler;

        tcs.TrySetResult(new LoadUrlAsyncResponse(args.ErrorCode, -1));
    };

    loadingStateChangeHandler = (sender, args) =>
    {
        //Wait for while page to finish loading not just the first frame
        if (!args.IsLoading)
        {
            browser.LoadError -= loadErrorHandler;
            browser.LoadingStateChanged -= loadingStateChangeHandler;
            var host = args.Browser.GetHost();

            var navEntry = host?.GetVisibleNavigationEntry();

            int statusCode = navEntry?.HttpStatusCode ?? -1;

            //By default 0 is some sort of error, we map that to -1
            //so that it's clearer that something failed.
            if (statusCode == 0)
            {
                statusCode = -1;
            }

            tcs.TrySetResult(new LoadUrlAsyncResponse(statusCode == -1 ? CefErrorCode.Failed : CefErrorCode.None, statusCode));
        }
    };

    browser.LoadingStateChanged += loadingStateChangeHandler;
    browser.LoadError += loadErrorHandler;

    return tcs.Task;
}

// usage example 
await Task.WhenAll(chrome.WaitForLoadAsync(), chrome.EvaluateScriptAsync(script));

В версии 101 я добавлю новый метод, встроенный в версию этого метода. Проблема github.com/cefsharp/CefSharp/issues/4073 будет отслеживать это

amaitland 27.04.2022 05:58

Пожалуйста, помогите мне с этим вопросом stackoverflow.com/questions/72066705/…

Csharp_cowboy 30.04.2022 10:07

Вы никогда не должны использовать Sleep таким образом. Веб может занять больше или меньше времени, и ваш код через какое-то время выйдет из строя. Вы всегда должны работать в асинхронном режиме. Если хотите, можете поставить тайм-аут на случай ошибки, но в обычном режиме всегда ждите, пока не получите то, что хотите.

Например, нажмите кнопку и установите таймер, чтобы дождаться появления ссылок. Затем перейдите к первой ссылке.

В других случаях, когда происходит реальная навигация и вы потеряли свой контекст JavaScript, вы можете использовать связанный объект для связи вашего приложения C# и браузера. Делая это, вы можете запрашивать из своего JavaScript, что вы делаете, и из JavaScript давать обратную связь вашему коду C#. Это способ сохранить состояние.

Типичный пример — когда вы заполняете некоторые формы и нажимаете «Продолжить», «Продолжить...», перемещаясь по нескольким страницам. Если вы хотите собрать всю информацию, вам нужен связанный объект. Я использую его с сериализацией json для управления более сложными данными.

Если вы собираетесь много работать с браузером, я рекомендую вам внедрить собственные скрипты на страницу, по которой вы перемещаетесь. В этой форме вы можете работать со своими классами на загруженной странице.

Другие вопросы по теме