C # Raspe los datos de la página wiki (raspado de pantalla)

c# html-agility-pack screen screen-scraping

Pregunta

Quiero raspar una página de Wiki. En concreto, este.

Mi aplicación permitirá a los usuarios ingresar el número de registro del vehículo (por ejemplo, SBS8988Z) y mostrará la información relacionada (que se encuentra en la propia página).

Por ejemplo, si el usuario ingresa SBS8988Z en un campo de texto en mi aplicación, debería buscar la línea en esa página wiki

SBS8988Z (SLBP 192/194*) - F&N NutriSoy Fresh Milk: Singapore's No. 1 Soya Milk! (2nd Gen)

y devuelva SBS8988Z (SLBP 192/194 *) - Leche fresca F&N NutriSoy: ¡la leche de soja número 1 de Singapur! (2ª generación).

Mi código hasta ahora es (copiado y editado de varios sitios web) ...

WebClient getdeployment = new WebClient();
string url = "http://sgwiki.com/wiki/Scania_K230UB_(Batch_1_Euro_V)";

getdeployment.Headers["User-Agent"] = "NextBusApp/GetBusData UserAgent";
string sgwikiresult = getdeployment.DownloadString(url); // <<< EXCEPTION
MessageBox.Show(sgwikiresult); //for debugging only!

HtmlAgilityPack.HtmlDocument sgwikihtml = new HtmlAgilityPack.HtmlDocument();
sgwikihtml.Load(new StreamReader(sgwikiresult));
HtmlNode root = sgwikihtml.DocumentNode;

List<string> anchorTags = new List<string>();   

foreach(HtmlNode deployment in root.SelectNodes("SBS8988Z"))
{
    string att = deployment.OuterHtml;
    anchorTags.Add(att);
}

Sin embargo, obtengo una ArgumentException no fue manejada - Caracteres ilegales en la ruta.

¿Qué está mal con el código? ¿Hay alguna forma más fácil de hacer esto? Estoy usando HtmlAgilityPack pero si hay una solución mejor, me complacería cumplir.

Respuesta aceptada

¿Qué hay de malo con el código? Para ser franco, todo. :PAG

La página no está formateada en la forma en que la estás leyendo. No puedes esperar conseguir los contenidos deseados de esa manera.

El contenido de la página (la parte en la que estamos interesados) se ve algo como esto:

<h2>
<span id="Deployments" class="mw-headline">Deployments</span>
</h2>
<p>
    <!-- ... -->
    <b>SBS8987B</b>
    (SLBP 192/194*)
    <br>
    <b>SBS8988Z</b>
    (SLBP 192/194*) - F&amp;N NutriSoy Fresh Milk: Singapore's No. 1 Soya Milk! (2nd Gen)
    <br>
    <b>SBS8989X</b>
    (SLBP SP)
    <br>
    <!-- ... -->
</p>

Básicamente, necesitamos encontrar los elementos b que contienen el número de registro que estamos buscando. Una vez que encontremos ese elemento, obtenga el texto y júntelo para formar el resultado. Aquí está en código:

static string GetVehicleInfo(string reg)
{
    var url = "http://sgwiki.com/wiki/Scania_K230UB_%28Batch_1_Euro_V%29";

    // HtmlWeb is a helper class to get pages from the web
    var web = new HtmlAgilityPack.HtmlWeb();

    // Create an HtmlDocument from the contents found at given url
    var doc = web.Load(url);

    // Create an XPath to find the `b` elements which contain the registration numbers
    var xpath = "//h2[span/@id='Deployments']" // find the `h2` element that has a span with the id, 'Deployments' (the header)
              + "/following-sibling::p[1]"     // move to the first `p` element (where the actual content is in) after the header
              + "/b";                          // select the `b` elements

    // Get the elements from the specified XPath
    var deployments = doc.DocumentNode.SelectNodes(xpath);

    // Create a LINQ query to find the  requested registration number and generate a result
    var query =
        from b in deployments                 // from the list of registration numbers
        where b.InnerText == reg              // find the registration we're looking for
        select reg + b.NextSibling.InnerText; // and create the result combining the registration number with the description (the text following the `b` element)

    // The query should yield exactly one result (or we have a problem) or none (null)
    var content = query.SingleOrDefault();

    // Decode the content (to convert stuff like "&amp;" to "&")
    var decoded = System.Net.WebUtility.HtmlDecode(content);

    return decoded;
}


Related

Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué
Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué