Obtenga datos usando HAP (HTML Agility Pack) de la página

.net .net-4.0 c# html-agility-pack

Pregunta

Una continuación de esta publicación , estoy tratando de analizar algunos datos de una página HTML. Aquí está el HTML (hay más información en la página, pero esta es la sección importante):

<table class="integrationteamstats">
<tbody>
<tr>
    <td class="right">
        <span class="mediumtextBlack">Queue:</span>
    </td>
    <td class="left">
        <span class="mediumtextBlack">0</span>
    </td>
    <td class="right">
        <span class="mediumtextBlack">Aban:</span>
    </td>
    <td class="left">
        <span class="mediumtextBlack">0%</span>
    </td>
    <td class="right">
        <span class="mediumtextBlack">Staffed:</span>
    </td>
    <td class="left">
        <span class="mediumtextBlack">0</span>
    </td>
</tr>
<tr>
    <td class="right">
        <span class="mediumtextBlack">Wait:</span>
    </td>
    <td class="left">
        <span class="mediumtextBlack">0:00</span>
    </td>
    <td class="right">
        <span class="mediumtextBlack">Total:</span>
    </td>
    <td class="left">
        <span class="mediumtextBlack">0</span>
    </td>
    <td class="right">
        <span class="mediumtextBlack">On ACD:</span>
    </td>
    <td class="left">
        <span class="mediumtextBlack">0</span>
    </td>
</tr>
</tbody>
</table>

Necesito obtener 2 piezas de información: los datos dentro de la td debajo de la cola y los datos dentro de la td debajo de Esperar (por lo tanto, el recuento de la cola y el tiempo de espera). Obviamente los números se van a actualizar con frecuencia.

He llegado al punto en el que el HTML se introduce en una variable HtmlDocument. Y he encontrado algo similar al uso de HtmlNodeCollection para recopilar nodos que cumplen con ciertos criterios. Aquí es básicamente donde estoy atascado:

HtmlNodeCollection tds = 
    new HtmlNodeCollection(this.html.DocumentNode.ParentNode);
tds = this.html.DocumentNode.SelectNodes("//td");

foreach (HtmlNode td in tds)
{
    /* I want to write:
     * If the last node's value was 'Queue', give me the value of this node.
     * and
     * If the last node's value was 'Wait Time', give me the value of this node.
     */
}

Y puedo pasar por esto con un foreach , pero no estoy seguro de cómo acceder al valor o cómo obtener el siguiente valor.

Respuesta aceptada

En general, no hay necesidad de seguir adelante con un foreach ya que obtener la información específica es bastante fácil (con un foreach tendría que administrar el estado de cada iteración del bucle y es realmente difícil de manejar).

Primero, quieres conseguir la mesa. Filtrar en el atributo de class es generalmente una mala idea, ya que puede tener varios elementos en un documento HTML que tienen la clase aplicada. Si tuvieras un atributo id , sería ideal.

Dicho esto, si esta es la única tabla con esta clase, entonces puede obtener el cuerpo del elemento de la table usando:

// Get the table.
HtmlNode tableBody = document.DocumentNode.SelectSingleNode(
    "//table[@class='integrationteamstats']/tbody");

A partir de ahí, desea obtener las filas individuales. Dado que estos son elementos directos del elemento tbody , puede obtener las filas por posición a través de la propiedad ChildNodes , así:

HtmlNode queueRow = tableBody.ChildNodes[0];
HtmlNode waitRow = tableBody.ChildNodes[1];

Entonces quieres el segundo elemento td en cada fila. Si bien hay una etiqueta span que envuelve el contenido, desea que todo el texto que se encuentra en el elemento td en su totalidad, puede usar la propiedad InnerText para obtener el valor:

string queueValue = queueRow.ChildNodes[1].InnerText;
string waitValue = waitRow.ChildNodes[1].InnerText;

Tenga en cuenta que aquí hay replicación, por lo que si encuentra que hay muchas filas que debe analizar de esta manera, es posible que desee dividir parte de la lógica en métodos auxiliares.


Respuesta popular

También podrías usar CsQuery para hacer esto. Ya que utiliza la sintaxis del selector CSS y los métodos jQuery, puede ser más fácil de usar que HAP para una navegación DOM más compleja. Por ejemplo:

// function to get the text from the cell AFTER the one containing 'text'

string getNextCellText(CQ dom, string text) {
    // find the target cell
    CQ target= dom.Select(".integrationteamstats td:contains(" + text + ")");

    // return the text contents of the next cell
    return target.Next().Text();
}

void Main() {
    var dom = CQ.Create(html);
    string queue = getNextCellText(dom,"Queue");
    string wait = getNextCellText(dom,"Wait:");

    .. do stuff
}


Related

Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow