WebView2 (2020/06) -> DOM 在哪里?

9 webview2

我将一种可工作的 Excel VBA 应用程序(该应用程序将 IE 自动化)作为我为我的妻子编写的网络抓取和下订单系统的一部分移动到了 C#/Windows Forms/WebView2,她花了几个小时被 90 年代风格的 Usborne Children Books Consultant Portal 折磨。项目。

目前看来,基础知识还不具备。

例如...

    1- if(browser.navigationComplete == true){

    That simple check isn't available. 
    How is one supposed to flow sequences of user actions without this?

    2- htmlagilitypack like tools?

    In VBA you can easily work with the DOM since there's types for pretty much everything. Where's that in WebView2?
Run Code Online (Sandbox Code Playgroud)

也许我理解错了,但看起来 webview2 只是一个浏览器,没有 VBA 二十多年来所拥有的自动化工具。请告诉我,我不必爬回中世纪的 Excel VBA 地牢。我已经看到了光明,这很好!

任何架构或实际测试的工作代码将不胜感激:)

感谢您从温哥华,

安托万

ama*_*and 5

对于那些感兴趣的人,我刚刚将WebView2.DevTools.Dom发布到NuGet.org。任何人都可以免费使用。

与当前可用的其他一些包不同,它是基于Chrome DevTools 协议的框架,用于 JavaScript 执行、DOM 访问/操作和自动化。需要.Net 4.6.2 or .Net Core 3.1 or greater

  • 通过Microsoft.Web.WebView2.DevToolsProtocolExtension直接连接到浏览器(不打开远程调试端口)。
  • QuerySelector 和 QuerySelectorAll 支持
  • 可用于自动化,支持模拟键盘和鼠标事件(如木偶操纵者)
  • 完全异步
  • 支持多帧
  • 约280xUnit次测试
  • 支持从返回复杂类型JavaScript

自述文件中的更多详细信息和示例

 await webView.EnsureCoreWebView2Async();
 
 // Create one instance per CoreWebView2
 // Reuse devToolsContext if possible, dispose (via DisposeAsync) before creating new instance
 // Make sure to call DisposeAsync when finished or await using as per this example
// Add using WebView2.DevTools.Dom; to access the CreateDevToolsContextAsync extension method
 await using var devToolsContext = await webView2Browser.CoreWebView2.CreateDevToolsContextAsync();

// Get element by Id
// https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector
var element = await devToolsContext.QuerySelectorAsync<HtmlElement>("#myElementId");

//Strongly typed element types
//Only a subset of element types have been added so far, use HtmlElement as a generic type for all others
var htmlDivElement = await devToolsContext.QuerySelectorAsync<HtmlDivElement>("#myDivElementId");
var htmlSpanElement = await devToolsContext.QuerySelectorAsync<HtmlSpanElement>("#mySpanElementId");
var htmlSelectElement = await devToolsContext.QuerySelectorAsync<HtmlSelectElement>("#mySelectElementId");
var htmlInputElement = await devToolsContext.QuerySelectorAsync<HtmlInputElement>("#myInputElementId");
var htmlFormElement = await devToolsContext.QuerySelectorAsync<HtmlFormElement>("#myFormElementId");
var htmlAnchorElement = await devToolsContext.QuerySelectorAsync<HtmlAnchorElement>("#myAnchorElementId");
var htmlImageElement = await devToolsContext.QuerySelectorAsync<HtmlImageElement>("#myImageElementId");
var htmlTextAreaElement = await devToolsContext.QuerySelectorAsync<HtmlImageElement>("#myTextAreaElementId");
var htmlButtonElement = await devToolsContext.QuerySelectorAsync<HtmlButtonElement>("#myButtonElementId");
var htmlParagraphElement = await devToolsContext.QuerySelectorAsync<HtmlParagraphElement>("#myParagraphElementId");
var htmlTableElement = await devToolsContext.QuerySelectorAsync<HtmlTableElement>("#myTableElementId");

// Get a custom attribute value
var customAttribute = await element.GetAttributeAsync<string>("data-customAttribute");

//Set innerText property for the element
await element.SetInnerTextAsync("Welcome!");

//Get innerText property for the element
var innerText = await element.GetInnerTextAsync();
//Can also be acessed via calling GetPropertyValueAsync
//Can use this method to get any property that isn't currently mapped
innerText = await element.GetInnerTextAsync();

//Get all child elements
var childElements = await element.QuerySelectorAllAsync("div");

//Change CSS style background colour
await element.EvaluateFunctionAsync("e => e.style.backgroundColor = 'yellow'");

//Type text in an input field
await element.TypeAsync("Welcome to my Website!");

//Scroll Element into View (if needed)
//Can optional specify a Rect to be scrolled into view, relative to the node's border box,
//in CSS pixels. When omitted, center of the node will be used
await element.ScrollIntoViewIfNeededAsync();

//Click The element
await element.ClickAsync();

// Simple way of chaining method calls together when you don't need a handle to the HtmlElement
var htmlButtonElementInnerText = await devToolsContext.QuerySelectorAsync<HtmlButtonElement>("#myButtonElementId")
    .AndThen(x => x.GetInnerTextAsync());

//Event Handler
//Expose a function to javascript, functions persist across navigations
//So only need to do this once
await devToolsContext.ExposeFunctionAsync("jsAlertButtonClick", () =>
{
    _ = devToolsContext.EvaluateExpressionAsync("window.alert('Hello! You invoked window.alert()');");
});

var jsAlertButton = await devToolsContext.QuerySelectorAsync("#jsAlertButton");

//Write up the click event listner to call our exposed function
_ = jsAlertButton.AddEventListenerAsync("click", "jsAlertButtonClick");

//Get a collection of HtmlElements
var divElements = await devToolsContext.QuerySelectorAllAsync<HtmlDivElement>("div");

foreach (var div in divElements)
{
    // Get a reference to the CSSStyleDeclaration
    var style = await div.GetStyleAsync();

    //Set the border to 1px solid red
    await style.SetPropertyAsync("border", "1px solid red", important: true);

    await div.SetAttributeAsync("data-customAttribute", "123");
    await div.SetInnerTextAsync("Updated Div innerText");
}

//Using standard array
var tableRows = await htmlTableElement.GetRowsAsync().ToArrayAsync();

foreach(var row in tableRows)
{
    var cells = await row.GetCellsAsync().ToArrayAsync();
    foreach(var cell in cells)
    {
        var newDiv = await devToolsContext.CreateHtmlElementAsync<HtmlDivElement>("div");
        await newDiv.SetInnerTextAsync("New Div Added!");
        await cell.AppendChildAsync(newDiv);
    }
}

//Get a reference to the HtmlCollection and use async enumerable
//Requires Net Core 3.1 or higher
var tableRowsHtmlCollection = await htmlTableElement.GetRowsAsync();

await foreach (var row in tableRowsHtmlCollection)
{
    var cells = await row.GetCellsAsync();
    await foreach (var cell in cells)
    {
        var newDiv = await devToolsContext.CreateHtmlElementAsync<HtmlDivElement>("div");
        await newDiv.SetInnerTextAsync("New Div Added!");
        await cell.AppendChildAsync(newDiv);
    }
}
Run Code Online (Sandbox Code Playgroud)


小智 3

1. browser.navigationComplete:您应该能够使用WebView2.NavigationCompleted事件。

2. htmlagilitypack:虽然 WebView2 不提供直接 DOM 访问,但您可以将html 作为字符串获取并使用htmlagilitypack LoadHtml函数。还有来自 Web功能的 htmlagilitypack,但我不确定这是否只是在幕后使用 WebBrowser。