C# 如何在使用 CefSharp 重定向或刷新后继续 运行 JavaScript 代码

C# How to continue running JavaScript code after a redirect or refresh by using CefSharp

我需要以编程方式在网站上执行 3 个操作

  1. 填写搜索输入
  2. 按下搜索按钮

(之后出现请求,页面returns我是搜索结果)

  1. 点击第一个link

如果我将操作 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();
}

按钮 2 中的操作 3:

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?

的情况下,我还能如何更改我的代码?

您可以使用如下方式等待页面加载

// 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));

您绝不能以这种方式使用 Sleep。 Web 可能需要更多或更少的时间,并且您的代码会在一段时间后失败。您必须始终在异步模式下工作。如果你愿意,你可以设置一个超时以防出错,但在正常模式下,总是等到你想要的。

例如,单击按钮并设置计时器以等待您的 link 出现。然后,导航到第一个 link.

在其他情况下,当真正的导航发生并且您丢失了 JavaScript 上下文时,您可以使用绑定对象来连接您的 C# 应用程序和浏览器。为此,您可以从 JavaScript 查询您在做什么,并从 JavaScript 向您的 C# 代码提供反馈。这是一种持久化状态的方法。

一个典型的示例是当您填写一些表格并单击“继续”、“继续...”时在多个页面中导航。如果你想收集所有信息,你需要绑定对象。我将它与 json 序列化一起使用来管理更复杂的数据。

如果您要经常使用浏览器,我建议您在您导航的页面中插入您自己的脚本。在此表单中,您可以在加载的页面中使用您自己的 类。