DOM

本指南描述了如何访问 DOM 文档、查找元素、修改 DOM 结构,以及模拟用户输入等。

概述

IBrowser 中加载的每个网页都有一个主 IFrameIFrame 本身可能有子框架。 例如,当一个网页有多个 IFRAME 对象时,可使用 IFrame 类访问 DOM 和 JavaScript。

访问文档

每个 IFrame 都有一个 DOM IDocument。 要访问 IDocument,请使用 IFrame.Document 属性:

IDocument document = frame.Document;
Dim document As IDocument = frame.Document

查找元素

您可以通过不同的条件找到元素内部的 HTML 元素。 下面的代码示例演示了如何在文档元素中查找所有 DIV 元素:

IElement documentElement = document.DocumentElement;
IEnumerable<IElement> elements = documentElement?.GetElementsByTagName("div"); 
Dim documentElement As IElement = document.DocumentElement
Dim elements As IEnumerable(Of IElement) = documentElement?.GetElementsByTagName("div")

如果您只需要查找第一个 HTML 元素,请使用以下方法:

documentElement.GetElementByTagName("div");
documentElement.GetElementByTagName("div")

以下是通过不同条件搜索 HTML 元素的示例:

documentElement.GetElementById("<id>");
documentElement.GetElementsByName("<attr-name>");
documentElement.GetElementsByTagName("<tag-name>");
documentElement.GetElementsByClassName("<attr-class>");
documentElement.GetElementById("<id>")
documentElement.GetElementsByName("<attr-name>")
documentElement.GetElementsByTagName("<tag-name>")
documentElement.GetElementsByClassName("<attr-class>")

XPath

DotNetBrowser DOM API 允许使用 INode.Evaluate(string expression) 评估 XPath 表达式。 您可以使用以下代码示例,在指定的 INode 范围内对 XPath 表达式进行评估:

IXPathResult result = node.Evaluate("count(//div)");
Dim result As IXPathResult = node.Evaluate("count(//div)")

评估结果存储在 IXPathResult 对象中。 确保结果包含预期的值类型,例如 Number, Boolean, String, Node, 并提取值本身:

if (result.Type == XPathResultType.Number) {
    double? number = result.Numeric;
}
If result.Type = XPathResultType.Number Then
    Dim number? As Double = result.Numeric
End If

查询选择器

要查找与指定选择器(例如, #root)匹配的元素,请使用以下代码:

IEnumerable<IElement> elements = element.GetElementsByCssSelector("#root");
Dim elements As IEnumerable(Of IElement) = element.GetElementsByCssSelector("#root")

聚焦元素

要查找网页上当前聚焦的元素,请使用 IDocument.FocusedElement 属性:

IElement focusedElement = document.FocusedElement;
Dim focusedElement As IElement = document.FocusedElement

特定点的节点

要在网页上找到特定点的 INode ,例如 100x150,请使用以下方法:

PointInspection inspection = frame.Inspect(new Point(100, 150));
INode node = inspection.Node;
Dim inspection As PointInspection = frame.Inspect(New Point(100, 150))
Dim node As INode = inspection.Node

处理元素

元素边界

您可以通过以下方式获取相对于当前 IDocument 视口左上角位置的 IElement 边界:

Rectangle rect = element.BoundingClientRect;
Dim rect As Rectangle = element.BoundingClientRect

当元素具有 hidden 属性或元素的 CSS 样式包含 display: none; 语句时,该方法返回一个空的 Rectangle

元素属性

IElement 类提供了一些方法,使您能够获取、添加、删除或修改 HTML 元素的属性。 下面的代码示例演示了如何获取元素的所有属性并打印它们的名称和值:

foreach (KeyValuePair<string, string> attr in element.Attributes)
{
    Console.WriteLine($"{attr.Key}: {attr.Value}");
}
For Each attr As KeyValuePair(Of String, String) In element.Attributes
    Console.WriteLine($"{attr.Key}: {attr.Value}")
Next

下面的代码示例演示了如何添加/修改元素属性:

element.Attributes["attrName"] = "attrValue";
element.Attributes("attrName") = "attrValue"

创建元素

DOM API 允许修改文档 DOM 结构。 以下示例演示了如何创建和插入带有一些文本的 <p> 元素:

// 创建一个新的段落元素。
IElement paragraph = document.CreateElement("p");
// 用给定的文本创建一个文本节点。
INode text = document.CreateTextNode("Text");
// 将文本节点插入段落元素。
if (paragraph.Children.Append(text)) {
    // 将段落元素插入到所需的元素中。
    bool success = element.Children.Append(paragraph);
}
' 创建一个新的段落元素。
Dim paragraph As IElement = document.CreateElement("p")
' 用给定的文本创建一个文本节点。
Dim text As INode = document.CreateTextNode("Text")
' 将文本节点插入段落元素。
If paragraph.Children.Append(text) Then
    ' 将段落元素插入到所需的元素中。
    Dim success As Boolean = element.Children.Append(paragraph)
End If

DOM 事件

每个 INode 都实现了 IEventTarget 接口,该接口提供了注册 DOM 事件的方法。 您可以注册 DOM 监听器以接收 DOM 事件,如 click, mousedown, mouseup, keydown, load, error 等。

以下代码示例演示了如何为 HTML 文档元素注册 click 事件监听器:

document.DocumentElement.Events.Click += (sender, e) => {
    // 鼠标点击事件已被接收。
};
AddHandler document.DocumentElement.Events.Click, Sub(sender, e)
    ' 已收到鼠标点击事件。
End Sub

DotNetBrowser 还允许您监听自定义 DOM 事件类型。 下面的代码示例演示了如何监听 MyEvent DOM 事件:

// 创建一个自定义 DOM 事件类型。
EventType eventType = new EventType("MyEvent");
element.Events[eventType] += (sender, e) => {
    // 已收到自定义事件。
};
' 创建一个自定义 DOM 事件类型。
Dim eventType As New EventType("MyEvent")
AddHandler element.Events(eventType).EventReceived, Sub(sender, e)
    ' 已收到自定义事件。
End Sub

自动化

DotNetBrowser DOM API 提供了自动填写网络表单所需的一切。 本节介绍如何更新文本字段中的文本、选择复选框或单选按钮、在下拉列表中选择一个或多个选项、模拟单击等。

要使用网络表单控件,请使用 IFormControlElement 接口。 通过该界面可以检查控件是否启用,并修改其值。 所有表单控件,如 INPUTSELECTTEXTAREA 等,都继承了该接口。

Input (输入)

要使用 INPUT 元素,请使用 IInputElement 接口。 它提供了检查输入类型和设置其值所需的所有方法。

文本、电子邮件和密码

要用新值替换文本、电子邮件或密码字段的默认值,请使用 IInputElement.Value 属性。

例如,您的 Web 表单包含具有以下类型的 <input> 元素:

<input type="text" id="firstname" placeholder="First Name">
<input type="email" id="email" placeholder="Email Address">
<input type="password" id="password" placeholder="Password">

您可以使用以下方法设置它们的值:

((IInputElement)documentElement.GetElementById("firstname")).Value = "John";
((IInputElement)documentElement.GetElementById("email")).Value = "me@company.com";
((IInputElement)documentElement.GetElementById("password")).Value = "Jkdl12!";
DirectCast(documentElement.GetElementById("firstname"), IInputElement).Value = "John"
DirectCast(documentElement.GetElementById("email"), IInputElement).Value = "me@company.com"
DirectCast(documentElement.GetElementById("password"), IInputElement).Value = "Jkdl12!"

复选框、单选按钮

要选择单选按钮或复选框,请使用 IInputElement.Checked 属性。 例如,您的网络表单包含具有以下类型的 <input> 元素:

<input type="checkbox" id="checkbox" value="Remember me">
<input type="radio" id="radio" checked>

您可以使用以下方法选择/取消选择它们:

((IInputElement)documentElement.GetElementById("checkbox")).Checked = true;

((IInputElement)documentElement.GetElementById("radio")).Checked = false;
DirectCast(documentElement.GetElementById("checkbox"), IInputElement).Checked = True

DirectCast(documentElement.GetElementById("radio"), IInputElement).Checked = False

文件

type=file 的 <input> 元素允许用户从他们的设备存储中选择一个或多个文件。 DotNetBrowser 允许以编程方式选择文件并更新 <input type=file> 元素的值。

例如,您的网络表单包含一个 <input> 元素:

<input type="file" id="avatar" accept="image/png, image/jpeg" multiple>

您可以使用以下方法以编程方式选择所需的文件:

((IInputElement)documentElement.GetElementById("avatar")).Files = new[]{
    "file1.png", 
    "file2.jpeg"};
DirectCast(documentElement.GetElementById("avatar"), IInputElement).Files =
{
    "file1.png",
    "file2.jpeg"
}

文本区域

您有一个 <textarea> 元素,如下所示:

<textarea id="details"></textarea>

使用以下方法设置文本:

((ITextAreaElement)documentElement.GetElementById("details")).Value = "Some text...";
Dim textElement = DirectCast(documentElement.GetElementById("details"), ITextAreaElement)
textElement.Value = "Some text..."

选择和选项

下面是一个 SELECT 控件:

<select id="fruits" multiple>
    <option>Apple</option>
    <option>Orange</option>
    <option>Pineapple</option>
    <option>Banana</option>
</select>

您可以使用以下方法来选择某个项目:

var document = browser.MainFrame.Document;
var optionElements = ((ISelectElement)document.GetElementById("fruits"))
    .Options
    .ToList();

foreach (IOptionElement optionElement in optionElements)
{
    // 检查是否找到了必要的项目。
    if (optionElement.InnerText.Contains("Orange"))
    {
        // 选择必要的项目。
        optionElement.Selected = true;
    }
}
Dim document = browser.MainFrame.Document
Dim optionElements = DirectCast(document.GetElementById("fruits"), ISelectElement)
    .Options
    .ToList()

For Each optionElement As IOptionElement In optionElements
    ' 检查是否找到了必要的项目。
    If optionElement.InnerText.Contains("Orange") Then
        ' 选择必要的项目。
        optionElement.Selected = True
    End If
Next

使用此方法,您只能选择一个必需选项。

模拟点击

要模拟鼠标单击元素,请使用以下方法:

element.Click();
element.Click()

Click() 与支持的元素(如 )一起使用时,它会触发该元素的click事件。 该事件向上冒泡到文档树中较高的元素并触发它们的 click 事件。

调度事件

您可以使用IEventTarget.DispatchEvent(IEvent) 方法在指定的 IEventTarget 处调度 IEvent

下面的代码示例演示了如何在指定的元素上派发标准的 click 事件:

// 客户端和屏幕位置。
Point location = new Point(10, 10);
// 使用所需选项创建 MouseEvent。
MouseEventParameters eventParameters = new MouseEventParameters
{
    Button = 0,
    ClientLocation = location,
    ScreenLocation = location,
    UiEventModifierParameters = new UiEventModifierParameters()
    {
        EventParameters = new EventParameters.Builder()
        {
            Bubbles = true,
            Cancelable = true
        }.Build()
    }
};
IMouseEvent mouseClickEvent = document.CreateMouseEvent(EventType.Click,
    eventParameters);

// 在目标元素上生成点击事件。
element.DispatchEvent(mouseClickEvent);
' 客户端和屏幕位置。
Dim location As New Point(10, 10)
' 使用所需选项创建 MouseEvent。
Dim eventParameters As New MouseEventParameters With {
    .Button = 0,
    .ClientLocation = location,
    .ScreenLocation = location,
    .UiEventModifierParameters = New UiEventModifierParameters() With 
    {
        .EventParameters = New EventParameters.Builder() With 
        {
            .Bubbles = True, 
            .Cancelable = True
        }.Build()
    }
}
Dim mouseClickEvent As IMouseEvent = document.CreateMouseEvent(EventType.Click, 
    eventParameters)

' 在目标元素上生成点击事件。
element.DispatchEvent(mouseClickEvent)

使用这种方法,您可以创建和派发各种 DOM 事件。 这类事件通常被称为 合成事件,与由 IBrowser 本身触发的事件相对。

派发 “change” 事件

在 DotNetBrowser 中,更新值时不会自动派发 DOM 事件,但有些网站可能需要这些事件。 在这种情况下,你需要明确分派这些事件,以便网站能够正确地识别更新。 DispatchEvent 的实际用法取决于您与之交互的 JavaScript 框架。

最常见的情况是在更新输入字段后分派 change 事件以触发 JavaScript 中的 onchange 事件监听器。 例如:

IDocument document = Browser.MainFrame.Document;
IInputElement email = document.GetElementById("email") as IInputElement;
email.Value = "me@example.com";
email.DispatchEvent(document.CreateEvent(EventType.Change, 
    new EventParameters.Builder().Build()));
Dim document As IDocument = Browser.MainFrame.Document
Dim email = TryCast(document.GetElementById("email"), IInputElement)
email.Value = "me@example.com"
email.DispatchEvent(document.CreateEvent(EventType.Change,
    (New EventParameters.Builder()).Build()))

注入自定义 CSS

你可以指定自定义 CSS 规则,这些规则将应用于在 IBrowser 实例中加载的每个页面。

您可以通过设置 IBrowser.InjectCssHandler 属性来配置自定义 CSS。 CSS 规则将应用于浏览器中加载的下一个页面。

string hideOverflowCss = "HTML, BODY {overflow:hidden;}";
browser.InjectCssHandler = 
    new Handler<InjectCssParameters, InjectCssResponse>(p =>
    {
        return InjectCssResponse.Inject(hideOverflowCss);
    });
Dim hideOverflowCss = "HTML, BODY {overflow:hidden;}"
browser.InjectCssHandler = 
    New Handler(Of InjectCssParameters, InjectCssResponse)(Function(p)
        Return InjectCssResponse.Inject(hideOverflowCss)
    End Function)
Go Top