C# System.Windows.Forms.WebBrowser等待页面完全加载

C# System.Windows.Forms.WebBrowser等待页面完全加载,c#,web-scraping,dynamics-crm,webbrowser-control,C#,Web Scraping,Dynamics Crm,Webbrowser Control,我用等待和异步尝试了很多不同的解决方案。似乎什么都不管用。我无法找到真正完全等待页面完全加载的解决方案。所有的代码都在等待一段时间,但直到页面被加载,并且我在下一个进程中遇到错误 如何将示例代码设置为等待模式,直到在第页上找到Document.GetElementById(“quickFind\u text\u 0”)元素 这是我的密码: private void button7_Click(object sender, EventArgs e) { webBr

我用
等待
异步
尝试了很多不同的解决方案。似乎什么都不管用。我无法找到真正完全等待页面完全加载的解决方案。所有的代码都在等待一段时间,但直到页面被加载,并且我在下一个进程中遇到错误

如何将示例代码设置为等待模式,直到在第页上找到
Document.GetElementById(“quickFind\u text\u 0”)
元素

这是我的密码:

    private void button7_Click(object sender, EventArgs e)
    {

        webBrowser1.Navigate("https://company.crm4.dynamics.com/main.aspx?app=d365default&pagetype=entitylist&etn=opportunity");

        webBrowser1.Document.GetElementById("shell-container").Document.GetElementById("quickFind_text_0").SetAttribute("value", "Airbus");

        webBrowser1.Document.GetElementById("shell-container").Document.GetElementById("quickFind_text_0").InnerText = "Airbus";

        //Thread.Sleep(2000);

        HtmlElement fbLink = webBrowser1.Document.GetElementById("shell-container").Document.GetElementById("mainContent").Document.GetElementById("quickFind_button_0"); ;
        fbLink.InvokeMember("click");
    }
using System;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace v.0._0._01
{

    public static class WebBrowserExtensions
    {
        public static Task<Uri> DocumentCompletedAsync(this WebBrowser wb)
        {
            var tcs = new TaskCompletionSource<Uri>();
            WebBrowserDocumentCompletedEventHandler handler = null;
            handler = (_, e) =>
            {
                wb.DocumentCompleted -= handler;
                tcs.TrySetResult(e.Url);
            };
            wb.DocumentCompleted += handler;
            return tcs.Task;
        }
    }

    public partial class Browser : Form
    {

        public Browser()
        {
            InitializeComponent();
        }

        private async void button7_Click(object sender, EventArgs e)
        {

            webBrowser1.Navigate("https://company.crm4.dynamics.com/main.aspx?app=d365default&pagetype=entitylist&etn=opportunity");
            await webBrowser1.DocumentCompletedAsync(); // async magic
            HtmlElement fbLink = webBrowser1.Document.GetElementById("shell-container").Document.GetElementById("mainContent").Document.GetElementById("quickFind_button_0"); ;
            fbLink.InvokeMember("click");

        }

    }

}
请注意,我必须“两次”这样做,否则它将不起作用:

    webBrowser1.Document.GetElementById("shell-container").Document.GetElementById("quickFind_text_0").SetAttribute("value", "Airbus");

    webBrowser1.Document.GetElementById("shell-container").Document.GetElementById("quickFind_text_0").InnerText = "Airbus";
在VBA中,此操作有效:

    While .Busy
        DoEvents

    Wend
    While .ReadyState <> 4
        DoEvents
    Wend
While.Busy
多芬特
温德
While.ReadyState 4
多芬特
温德
在C#中也可以这样做吗


编辑:

我的完整代码如下。由于某些原因,async/await不起作用

System.NullReferenceException HResult=0x80004003消息=对象 引用未设置为对象的实例。来源=v.0.0.01
StackTrace:at v._0._0._01.Browser.d_7.MoveNext() 在C:\Users\PC\source\repos\v.0.0.01\v.0.0.01\Browser.cs中:第69行

这是我的密码:

    private void button7_Click(object sender, EventArgs e)
    {

        webBrowser1.Navigate("https://company.crm4.dynamics.com/main.aspx?app=d365default&pagetype=entitylist&etn=opportunity");

        webBrowser1.Document.GetElementById("shell-container").Document.GetElementById("quickFind_text_0").SetAttribute("value", "Airbus");

        webBrowser1.Document.GetElementById("shell-container").Document.GetElementById("quickFind_text_0").InnerText = "Airbus";

        //Thread.Sleep(2000);

        HtmlElement fbLink = webBrowser1.Document.GetElementById("shell-container").Document.GetElementById("mainContent").Document.GetElementById("quickFind_button_0"); ;
        fbLink.InvokeMember("click");
    }
using System;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace v.0._0._01
{

    public static class WebBrowserExtensions
    {
        public static Task<Uri> DocumentCompletedAsync(this WebBrowser wb)
        {
            var tcs = new TaskCompletionSource<Uri>();
            WebBrowserDocumentCompletedEventHandler handler = null;
            handler = (_, e) =>
            {
                wb.DocumentCompleted -= handler;
                tcs.TrySetResult(e.Url);
            };
            wb.DocumentCompleted += handler;
            return tcs.Task;
        }
    }

    public partial class Browser : Form
    {

        public Browser()
        {
            InitializeComponent();
        }

        private async void button7_Click(object sender, EventArgs e)
        {

            webBrowser1.Navigate("https://company.crm4.dynamics.com/main.aspx?app=d365default&pagetype=entitylist&etn=opportunity");
            await webBrowser1.DocumentCompletedAsync(); // async magic
            HtmlElement fbLink = webBrowser1.Document.GetElementById("shell-container").Document.GetElementById("mainContent").Document.GetElementById("quickFind_button_0"); ;
            fbLink.InvokeMember("click");

        }

    }

}
使用系统;
使用System.Threading.Tasks;
使用System.Windows.Forms;
名称空间v.0.\u 0.\u 01
{
公共静态类WebBrowserExtensions
{
公共静态任务DocumentCompletedAsync(此WebBrowser wb)
{
var tcs=new TaskCompletionSource();
WebBrowserDocumentCompletedEventHandler=null;
处理程序=(u,e)=>
{
wb.DocumentCompleted-=处理程序;
tcs.TrySetResult(e.Url);
};
wb.DocumentCompleted+=处理程序;
返回tcs.Task;
}
}
公共部分类浏览器:表单
{
公共浏览器()
{
初始化组件();
}
私有异步无效按钮7_单击(对象发送方,事件参数e)
{
webBrowser1.导航(“https://company.crm4.dynamics.com/main.aspx?app=d365default&pagetype=entitylist&etn=opportunity");
等待webBrowser1.DocumentCompletedAsync();//异步魔法
HtmlElement fbLink=webBrowser1.Document.GetElementById(“外壳容器”).Document.GetElementById(“主要内容”).Document.GetElementById(“快速查找按钮0”);
fbLink.InvokeMember(“单击”);
}
}
}
以下是源代码:


现在我还注意到,
quickFind_text_0
quickFind_按钮_0
总是以相同的单词开头,但是数字在变化,比如
quickFind_text_1
quickFind_按钮_1
quickFind_text_2
。但是,通过手动单击所有内容,可以使用
quickFind\u text\u 0
quickFind\u按钮\u 0

以下是一种扩展方法,用于轻松等待
DocumentCompleted
事件:

public static class WebBrowserExtensions
{
    public static Task<Uri> DocumentCompletedAsync(this WebBrowser wb)
    {
        var tcs = new TaskCompletionSource<Uri>();
        WebBrowserDocumentCompletedEventHandler handler = null;
        handler = (_, e) =>
        {
            wb.DocumentCompleted -= handler;
            tcs.TrySetResult(e.Url);
        };
        wb.DocumentCompleted += handler;
        return tcs.Task;
    }
}
wait
后面的行将在页面完成加载后运行


更新:以下是另一种扩展方法,用于等待特定元素出现在页面中:

public static async Task<HtmlElement> WaitForElementAsync(this WebBrowser wb,
    string elementId, int timeout = 30000, int interval = 500)
{
    var stopwatch = Stopwatch.StartNew();
    while (true)
    {
        try
        {
            var element = wb.Document.GetElementById(elementId);
            if (element != null) return element;
        }
        catch { }
        if (stopwatch.ElapsedMilliseconds > timeout) throw new TimeoutException();
        await Task.Delay(interval);
    }
}

这是一个
System.Windows.Forms.WebBrowser
?加载页面时,它将引发一个事件;把你的刮码放进去。@DourHighArch是的。它是
System.Windows.Forms.WebBrowser
。我将尝试这将等待页面加载,我如何才能添加更多的等待?例如,我需要对textbox执行文本输入,然后等待,我有
//Thread.Sleep(2000)当前。然后点击按钮。我想我需要等待,直到在页面上找到某个元素,如果30秒未找到,则结束进程。可能是重复链接
.Document.GetElementById(…)
时出现问题。不知怎么的,这似乎不对。谢谢你!我不知道问题出在哪里,但我认为这不会等待,因为我在下一个命令中遇到错误。如果我单独运行所有命令,但使用不同的按钮,等待进程自己完成,那么一切正常。页面是否包含
frame
s或
iframe
s?这可以解释为什么在第一个
DocumentCompleted
事件中页面没有完全加载。我在回答中包含了另一个扩展方法,您可能会发现它很有用(
WaitForElementAsync
)。