DOM

Este guia descreve como acessar um documento DOM, encontrar elementos, modificar uma estrutura DOM, simular a entrada do usuário, etc.

Visão geral

Cada página Web carregada num IBrowser tem um IFrame principal. O IFrame pode ter frames secundários. Por exemplo, quando uma página Web tem vários objetos IFRAME, utilize a classe IFrame para acessar o DOM e o JavaScript.

Acessar um documento

Cada IFrame tem um DOM IDocument. Para acessar o IDoc, utilize a propriedade IFrame.Document:

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

Encontrando elementos

Você pode encontrar elementos HTML dentro de um elemento através de diferentes condições. O exemplo de código abaixo demonstra como encontrar todos os elementos DIV dentro do elemento document:

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")

Se você precisa encontrar apenas o primeiro elemento HTML, utilize a seguinte abordagem:

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

Aqui estão os exemplos de pesquisa de elementos HTML por diferentes condições:

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

A API DOM do DotNetBrowser permite avaliar expressões XPath utilizando INode.Evaluate(string expression). Você pode avaliar uma expressão XPath no âmbito de um INode especificado utilizando o seguinte exemplo de código:

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

O resultado da avaliação é armazenado no objeto IXPathResult . Certifique-se de que o resultado contém o tipo de valor esperado, por exemplo, Number, Boolean, String, Node, e extraia o próprio valor:

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

Query selector

Para encontrar os elementos que correspondem a um seletor especificado, por exemplo, #root, utilize o seguinte código:

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

Elemento focalizado

Para encontrar o elemento atualmente em foco na página Web, utilize a propriedade IDocument.FocusedElement :

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

Nó no ponto

Para encontrar o INode num ponto específico, por exemplo, 100x150, na página Web, utilize a seguinte abordagem:

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

Trabalhar com elementos

Limites do elemento

É possível obter os limites do IElement com a posição relativa ao canto superior esquerdo da janela de visualização do atual IDocument da seguinte forma:

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

Este método devolve um Retângulo vazio quando o elemento tem um atributo hidden ou o estilo CSS do elemento contém a declaração display: none;.

Atributos do elemento

A classe IElement fornece métodos que lhe permitem obter, adicionar, remover ou modificar os atributos de elementos HTML. O exemplo de código abaixo demonstra como obter todos os atributos do elemento e imprimir os seus nomes e valores:

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

O exemplo de código abaixo demonstra como adicionar/modificar um atributo de elemento:

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

Criando de Elementos

A API DOM permite modificar a estrutura DOM do documento. O exemplo seguinte demonstra como criar e inserir o elemento <p> com algum texto:

// Cria um novo elemento de parágrafo.
IElement paragraph = document.CreateElement("p");
// Criar um nó de texto com o texto fornecido.
INode text = document.CreateTextNode("Text");
// Inserir o nó de texto no elemento de parágrafo.
if (paragraph.Children.Append(text)) {
    // Insere o elemento de parágrafo no elemento necessário.
    bool success = element.Children.Append(paragraph);
}
' Cria um novo elemento de parágrafo.
Dim paragraph As IElement = document.CreateElement("p")
' Criar um nó de texto com o texto fornecido.
Dim text As INode = document.CreateTextNode("Text")
' Inserir o nó de texto no elemento de parágrafo.
If paragraph.Children.Append(text) Then
    ' Inserir o elemento de parágrafo no elemento requerido.
    Dim success As Boolean = element.Children.Append(paragraph)
End If

Eventos DOM

Cada INode implementa a interface IEventTarget que fornece métodos para registrar eventos DOM. Você pode registrar um ouvinte DOM para receber eventos DOM, tais como click, mousedown, mouseup, keydown, load, error, entre outros.

A seguinte amostra de código demonstra como registrar um ouvinte do evento click para um elemento de documento HTML:

document.DocumentElement.Events.Click += (sender, e) => {
    // O evento de clique do mouse foi recebido.
};
AddHandler document.DocumentElement.Events.Click, Sub(sender, e)
    ' O evento de clique do mouse foi recebido.
End Sub

O DotNetBrowser também permite-lhe ouvir os tipos de eventos DOM personalizados. O seguinte exemplo de código demonstra como ouvir eventos DOM MyEvent:

// Cria um tipo de evento DOM personalizado.
EventType eventType = new EventType("MyEvent");
element.Events[eventType] += (sender, e) => {
    // Foi recebido um evento personalizado.
};
' Criar um tipo de evento DOM personalizado.
Dim eventType As New EventType("MyEvent")
AddHandler element.Events(eventType).EventReceived, Sub(sender, e)
    ' O evento personalizado foi recebido.
End Sub

Automatização

A API DOM do DotNetBrowser fornece tudo o que é necessário para automatizar o preenchimento de formulários Web. Esta seção descreve como atualizar o texto nos campos de texto, selecionar uma caixa de verificação ou um botão de rádio, selecionar uma ou várias opções numa lista pendente, simular um clique, etc.

Para trabalhar com controles de formulários Web, utilize a interface IFormControlElement. Esta interface permite-lhe verificar se o controle está ativado e modificar o seu valor. Todos os controles de formulário, como INPUT, SELECT, TEXTAREA, entre outros, herdam esta interface.

Entrada

Para trabalhar com elementos INPUT, utilize a interface IInputElement. Ela fornece todos os métodos necessários para verificar o tipo de entrada e definir o seu valor.

Texto, e-mail e senha

Para substituir o valor predefinido de um campo de texto, e-mail ou senha por um novo valor, utilize a propriedade IInputElement.Value.

Por exemplo, o seu formulário Web contém os elementos <input> com os seguintes tipos:

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

Você pode definir o seu valor utilizando a seguinte abordagem:

((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 = "João"
DirectCast(documentElement.GetElementById("email"), IInputElement).Value = "me@company.com"
DirectCast(documentElement.GetElementById("password"), IInputElement).Value = "Jkdl12!"

Caixa de verificação, botão de rádio

Para selecionar um botão de rádio ou uma caixa de verificação, utilize a propriedade IInputElement.Checked . Por exemplo, o seu formulário Web contém os elementos <input> com os seguintes tipos:

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

É possível selecionar/desmarcar utilizando a seguinte abordagem:

((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

Arquivo

Os elementos <input> com type=file permitem o usuário escolher um ou mais arquivos do seu dispositivo de armazenamento. O DotNetBrowser permite selecionar programaticamente um arquivo e atualizar o valor dos elementos <input type=file>.

Por exemplo, o seu formulário Web contém um elemento <input> como:

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

É possível selecionar programaticamente o(s) arquivo(s) necessário(s) utilizando a seguinte abordagem:

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

Área de texto

Tem um elemento <textarea> como mostrado abaixo:

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

Utilize a seguinte abordagem para definir o texto:

((ITextAreaElement)documentElement.GetElementById("details")).Value = "Algum texto...";
Dim textElement = DirectCast(documentElement.GetElementById("details"), ITextAreaElement)
textElement.Value = "Algum texto..."

Selecionar & opção

Existe um controle SELECT como se segue:

<select id="fruits" multiple>
    <option>Maçã</option>
    <option>Laranja</option>
    <option>Abacaxi</option>
    <option>Banana</option>
</select>

Você pode utilizar a seguinte abordagem para selecionar um determinado item:

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

foreach (IOptionElement optionElement in optionElements)
{
    // Verifica se o item necessário foi encontrado.
    if (optionElement.InnerText.Contains("Laranja"))
    {
        // Selecionar o item necessário.
        optionElement.Selected = true;
    }
}
Dim document = browser.MainFrame.Document
Dim optionElements = DirectCast(document.GetElementById("fruits"), ISelectElement)
    .Options
    .ToList()

For Each optionElement As IOptionElement In optionElements
    ' Verifica se o item necessário foi encontrado.
    If optionElement.InnerText.Contains("Orange") Then
        ' Selecionar o item necessário.
        optionElement.Selected = True
    End If
Next

Com esta abordagem, é possível selecionar apenas uma opção necessária.

Simulação de clique

Para simular um clique do mouse em um elemento, utilize o seguinte método:

element.Click();
element.Click()

Quando Click() é utilizado com os elementos suportados, como um <input>, dispara o evento click do elemento. Este evento é transmitido para os elementos mais elevados na árvore do documento e ativa os seus eventos click .

Despacho de eventos

É possível enviar um IEvent para o IEventTarget especificado utilizando o método IEventTarget.DispatchEvent(IEvent) .

O exemplo de código abaixo demonstra como enviar um evento padrão click para o elemento especificado:

// Localização do cliente e da tela.
Point location = new Point(10, 10);
// Criar MouseEvent com as opções necessárias.
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);

// Gera um evento de clique no elemento de destino.
element.DispatchEvent(mouseClickEvent);
' Localização do cliente e da tela.
Dim location As New Point(10, 10)
' Criar MouseEvent com as opções necessárias.
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)

' Gerar um evento de clique no elemento de destino.
element.DispatchEvent(mouseClickEvent)

Utilizando esta abordagem, você pode criar e enviar vários eventos DOM. Estes eventos são normalmente designados por eventos sintéticos, ao contrário dos eventos disparados pelo próprio IBrowser.

Despachar o evento “change” (alteração)

No DotNetBrowser, os eventos DOM não são enviados automaticamente ao atualizar um valor, embora alguns sites possam exigi-los. Neste caso, é necessário enviar estes eventos explicitamente para que o site reconheça corretamente as atualizações. A utilização efetiva de DispatchEvent depende das estruturas JavaScript que está interagindo.

O caso mais comum é enviar o evento change depois de atualizar o campo de entrada para ativar o ouvinte de eventos onchange em JavaScript. Por exemplo:

IDoc document = Browser.MainFrame.Document;
IInputElement email = document.GetElementById("email") as IInputElement;
email.Value = "eu@exemplo.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 = "eu@exemplo.com"
email.DispatchEvent(document.CreateEvent(EventType.Change,
    (New EventParameters.Builder()).Build())))

Injetar um CSS personalizado

É possível especificar regras CSS personalizadas a serem aplicadas a todas as páginas carregadas na instância do IBrowser .

Você pode configurar CSS personalizadas definindo a propriedade IBrowser.InjectCssHandler. As regras CSS serão aplicadas à próxima página carregada no Browser.

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