Webview2 多线程冻结/停止

Webview2 multithreading freezes/stops

提问人:Gerrit 提问时间:10/25/2023 最后编辑:Theodor ZouliasGerrit 更新时间:10/25/2023 访问量:102

问:

我一直在做一个有趣的副业。基本上,我用 模拟了两个隐身浏览器。他们转到 X Instagram 个人资料列表并开始喜欢追随者的故事。我希望两者同时执行异步 Javascript 代码。所以我使用多线程。每个浏览器都有一个线程。问题是,当两个实例启动时,一个实例继续运行 script-loop 。但似乎另一个实例运行此方法几秒钟并冻结/停止?这有点奇怪,我真的不知道发生了什么。我可能忽略了一些东西,但我真的想不通。Webview2Webview2Webview2Method4

private async void button1_Click(object sender, EventArgs e)
{
    TabPage tabPage = new TabPage();
    tabPage.Name = "tabPage" + (tabControl1.TabCount + 1);
    tabPage.Text = "tabPage" + (tabControl1.TabCount + 1);
    tabPage.Margin = tabControl1.TabPages[0].Margin;
    tabPage.Padding = tabControl1.TabPages[0].Padding;
    tabPage.Size = tabControl1.TabPages[0].Size;

    CustomBrowser customBrowser = new CustomBrowser(this);
    bool done = await customBrowser.InitBrowser();

    tabPage.Controls.Add(customBrowser.webView2);

    tabControl1.TabPages.Add(tabPage);

    string name = names[0];
    names.RemoveAt(0);

    Thread browserThread = new Thread(async () =>
    {
        Method4(customBrowser, name);
    });

    threads.Add(browserThread);
}

首先,我创建一个带有实例的新选项卡(类执行该实例的所有初始化)。之后,我创建并定义一个线程,并将其添加到一个列表中。Webview2CustomBrowserWebview2

private void button2_Click(object sender, EventArgs e)
{
    foreach (Thread browserThread in threads)
    {
        browserThread.Start();
    }
}

在我用两个浏览器创建了两个选项卡后,我使用上面的代码启动了所有线程。两个线程现在都将开始执行,即:Method4

private async void Method4(CustomBrowser customBrowser, string scrape)
{
    while (!customBrowser.BrowserStopped)
    {
        customBrowser.webView2.Invoke(new Action(async () =>
        {
            customBrowser.webView2.CoreWebView2.Navigate($"https://www.instagram.com/{scrape}/followers/");
        }));

        await Task.Delay(TimeSpan.FromSeconds(10));

        //Select follower box
        customBrowser.webView2.Invoke(new Action(async () =>
        {
            await customBrowser.webView2.ExecuteScriptAsync($"var box = document.querySelectorAll('div._aano');");
        }));  

        int index = 0;
        int lastIndex = 0;
        int increment = 500;
        while (index < 100)
        {
            customBrowser.webView2.Invoke(new Action(async () =>
            {
                await customBrowser.webView2.ExecuteScriptAsync($"box[0].scrollTop = {increment};");
                index = int.Parse(await customBrowser.webView2.ExecuteScriptAsync("document.querySelectorAll('div._aarf._aarg').length;")) - 1;
            }));

            // Get names from lastIndex to index
            if (index > lastIndex)
            {
                for (int i = lastIndex + 1; i <= index; i++)
                {
                    // Click profile picture
                    customBrowser.webView2.Invoke(new Action(async () =>
                    {
                        await customBrowser.webView2.ExecuteScriptAsync($"var profile = document.querySelectorAll('div._aarf._aarg')[{i}]; profile.scrollIntoView();");
                    }));
                    await Task.Delay(TimeSpan.FromMilliseconds(random.Next(1521, 3526)));
                    customBrowser.webView2.Invoke(new Action(async () =>
                    {
                        await customBrowser.webView2.ExecuteScriptAsync($"profile.click();");
                    }));
                    await Task.Delay(TimeSpan.FromMilliseconds(random.Next(3000, 4567)));
                    // Like story
                    customBrowser.webView2.Invoke(new Action(async () =>
                    {
                        string response = await customBrowser.webView2.ExecuteScriptAsync("var likeButton = document.querySelector('span.x1i64zmx'); if (likeButton.children[0].children[0].children[0].children[0].getAttribute('aria-label') === 'Vind ik leuk') { likeButton.children[0].click(); }");
                    }));
                    await Task.Delay(TimeSpan.FromMilliseconds(random.Next(1000, 2000)));
                    // Exit story
                    customBrowser.webView2.Invoke(new Action(async () =>
                    {
                        await customBrowser.webView2.ExecuteScriptAsync("document.querySelector('div.xjbqb8w.x1ypdohk.xw7yly9.xktsk01.x1yztbdb.x1d52u69.x10l6tqk.x13vifvy.xds687c').children[0].click();");
                    }));
                    await Task.Delay(TimeSpan.FromMilliseconds(random.Next(1521, 3526)));
                }
                lastIndex = index;
            }

            await Task.Delay(TimeSpan.FromSeconds(random.Next(1, 3)));
            increment += random.Next(500, 800);
        }

        customBrowser.BrowserStopped = true;
    }
}

这种方法基本上就像 100 个 Instagram 故事,仅此而已。所以这基本上就是所有的代码。一个线程和一个浏览器成功执行并继续执行此操作。但是第二个线程似乎只在前几行(导航和打开关注者列表)工作,然后停止工作。这怎么可能?我只想模拟两个独立的隐身浏览器并在它们上运行脚本。就像我打开两个Chrome浏览器一样。Method4Method4

C# 多线程 WinForms 异步 WebView2

评论

1赞 Jimi 10/25/2023
首先,删除任何线程和所有调用。您可以尝试使用 List<Task>,添加您的(s),更改为 List,然后Method4private async Task Method4()await Task.WhenAll([Your List of Tasks])
0赞 Jimi 10/25/2023
我不确定 WebView2 的实例是否可以以这种方式并发工作,因为我已经这样测试过它。但它可以在 GUI 中同时工作
0赞 Gerrit 10/25/2023
@Jimi 感谢您的回复。我把所有东西都改成了任务。我删除了调用,但现在出现错误:“System.InvalidOperationException:'CoreWebView2只能从UI线程访问。我想这就是我首先添加它们的原因。在实现我想要的方面,你有什么建议?Webview2 甚至可能吗?
1赞 Gerrit 10/25/2023
@TheodorZoulias 感谢您的专业知识,非常感谢。但这个有趣项目的全部意义在于通过多线程、多个浏览器、多个循环等实现 webview2。所以我认为我会召唤多种形式。
1赞 Jimi 10/25/2023
顺便说一句,您正在将这些控件添加到 TabPages。这是因为您需要查看脚本执行后会发生什么吗?在任何情况下,WebView2 控件的操作都已是异步的 (可等待的方法和事件回调) ,只需设置 Source,其他所有内容都异步执行。或者你真的想把它作为一个无头浏览器使用,它不需要显示界面,只需在后台执行一些操作?-- 再次查看您的代码,似乎根本不需要任何任务或线程

答: 暂无答案