Quiero obtener todos los enlaces de un documento HTML. Esto no es un problema, pero aparentemente pone todos los enlaces en orden alfabético antes de almacenarlos uno por uno. Quiero tener los enlaces en orden original (no en orden alfabético).
Entonces, ¿hay alguna posibilidad de obtener el primer enlace encontrado, almacenarlo, luego el segundo, ...? Ya intenté usar HtmlAgilityPack y los métodos de control del navegador web, pero ambos los ordenan alfabéticamente. El pedido original es importante para fines posteriores.
Escuché que podría ser posible con Regex, pero he encontrado suficientes respuestas, donde dicen que no se debe usar para el análisis de HTML. Entonces, ¿cómo puedo hacerlo?
Aquí está el código de control del navegador web, que intenté usar para obtener los enlaces y almacenarlos en una matriz:
private void btnGet_Click(object sender, EventArgs e)
{
HtmlWindow mainFrame = webFl.Document.Window.Frames["mainFrame"];
HtmlElementCollection links = mainFrame.Document.Links;
foreach (HtmlElement link in links)
{
string linkText = link.OuterHtml;
if (linkText.Contains("puzzle"))
{
arr[i] = linkText;
i++;
}
}
}
Gracias de antemano, Opak
Puede obtener el orden correcto recorriendo el árbol DOM usando API DOM de HTML . El siguiente código hace esto. Tenga en cuenta, yo uso dynamic
para acceder a la API DOM. Esto se debe a WebBrowser
's HtmlElement.FirstChild
/ HtmlElement.NextSibling
no funcionan para este fin, ya que regresan null
para los nodos de texto DOM.
private void btnGet_Click(object sender, EventArgs e)
{
Action<object> walkTheDom = null;
var links = new List<object>();
// element.FirstChild / NextSibling don't work as they stop at DOM text nodes
walkTheDom = (element) =>
{
dynamic domElement = element;
if (domElement.tagName == "A")
links.Add(domElement);
for (dynamic child = domElement.firstChild; child != null; child = child.nextSibling)
{
if (child.nodeType == 1) // Element node?
walkTheDom(child);
}
};
walkTheDom(this.webBrowser.Document.Body.DomElement);
string html = links.Aggregate(String.Empty, (a, b) => a + ((dynamic)b).outerHtml + Environment.NewLine);
MessageBox.Show(html);
}
[ACTUALIZACIÓN] Si realmente necesita obtener una lista de objetos HtmlElement
para etiquetas <A>
, en lugar de elementos nativos dynamic
, todavía es posible con un pequeño truco usando GetElementById
:
private void btnGet_Click(object sender, EventArgs e)
{
// element.FirstChild / NextSibling don't work because they stop on DOM text nodes
var links = new List<HtmlElement>();
var document = this.webBrowser.Document;
dynamic domDocument = document.DomDocument;
Action<dynamic> walkTheDom = null;
walkTheDom = (domElement) =>
{
if (domElement.tagName == "A")
{
// get HtmlElement for the found <A> tag
string savedId = domElement.id;
string uniqueId = domDocument.uniqueID;
domElement.id = uniqueId;
links.Add(document.GetElementById(uniqueId));
if (savedId != null)
domElement.id = savedId;
else
domElement.removeAttribute("id");
}
for (var child = domElement.firstChild; child != null; child = child.nextSibling)
{
if (child.nodeType == 1) // is an Element node?
walkTheDom(child);
}
};
// walk the DOM for <A> tags
walkTheDom(domDocument.body);
// show the found tags
string combinedHtml = links.Aggregate(String.Empty, (html, element) => html + element.OuterHtml + Environment.NewLine);
MessageBox.Show(combinedHtml);
}