martes, 1 de febrero de 2011

ASP.NET - Recuperar texto o imagenes contenidas en pagina web

developer_tools Ya hace algunos años habíamos hecho un post que enseñaba cómo recuperar el contenido completo de una página web. Y hasta allí quedamos en aquella ocasión.

Esta vez, queremos ir un poquito más allá, queremos recuperar secciones específicas de una página web.

Por ejemplo:
  • Cómo recupero el contenido de un div que tiene como id="cuerpo" ?
  • Cómo recupero todas las etiquetas a que tienen como class="menu" ?
  • Cómo recupero las imágenes que están dentro de un div de class="images" ?
Cómo extraigo los datos que están dentro de una tabla con id="Tabla1"
Cómo recupero cada uno de los elementos de una lista?
Muy interesante, no les parece?
Para hacer este trabajo tedioso, ya existe una maravillosa librería llamada Html Agility Pack, el cual lo pueden descargar desde http://htmlagilitypack.codeplex.com/
Pero, cómo es que esta librería hace el trabajo?
  • Se recupera el contenido html completo de la página web solicitada
  • Usamos el lenguaje de consulta XPATH para construir expresiones de consulta tomando como origen de datos el contenido html recuperado… XPATH trata el contenido html recuperado como si fuera una estructura con nodos, de esta manera puede navegar por él. Algo así:
html_nodes
Empecemos con el ejemplo:
Vamos a usar la página principal de CodeProject.com como objetivo, vamos a obtener sus distintos elementos como enlaces, imágenes, textos, etc..
1.- Creen un proyecto ASP.NET con C# y añádanle la referencia al ensamblado HtmlAgilityPack.dll
2.- Añadan una página aspx y pongan esta referencia en la parte superior:
using HtmlAgilityPack;

En el lado aspx pongan este código:

<form id="form1" runat="server">
<p>
<asp:Literal ID="Literal1" runat="server"></asp:Literal>
</p>

<p>
<asp:Literal ID="Literal2" runat="server"></asp:Literal>
</p>

<p>
<asp:Image ID="Image1" runat="server" />
<asp:Literal ID="Literal3" runat="server"></asp:Literal>
</p>
</form>

Continuemos. Como primer paso vamos a recuperar el contenido completo de la página web:

string url = @"http://www.codeproject.com/";
System.Net.WebClient wc = new System.Net.WebClient();
HtmlDocument doc = new HtmlDocument();

//recuperamos la página web completa
doc.Load(wc.OpenRead(url), System.Text.Encoding.GetEncoding("ISO-8859-1"));

El parámetro System.Text.Encoding.GetEncoding("ISO-8859-1") no es necesario si tu idioma no incluye acentos o caracteres adicionales especiales. Por ejemplo, el público que habla inglés no debería usarlo.

Ahora, vamos a recuperar el logo principal de la página. El código es el siguiente:

//Recuperamos el logo
HtmlNodeCollection logo = doc.DocumentNode.SelectNodes(@"//td[@class='header']/a");
Literal1.Text = logo[0].InnerHtml;

Sigamos. Ahora quiero recuperar las opciones del menú principal:

//Recuperamos el menu principal
HtmlNodeCollection ul = doc.DocumentNode.SelectNodes(@"//ul[@id='nav']");
Literal2.Text = ul[0].InnerHtml;

lima_weather Vamos a cambiar de url para recuperar elementos.








Esta vez nos desplazaremos hasta http://espanol.weather.com/weather/today-Lima-PEXX0011

En este sitio web muestran la temperatura diariamente de Lima Perú.

Entonces yo quiero obtenerlo de manera automatizada cada día tanto la imagen como la temperatura… para ello necesitamos el sgte código:

url = "http://espanol.weather.com/weather/today-Lima-PEXX0011";
doc.Load(wc.OpenRead(url), System.Text.Encoding.GetEncoding("ISO-8859-1"));

HtmlNodeCollection img = doc.DocumentNode.SelectNodes(@"//div[@id='current_box_icon']/img");
Image1.ImageUrl = img[0].Attributes["src"].Value;

HtmlNodeCollection current_box_temp = doc.DocumentNode.SelectNodes(@"//div[@id='current_box_temp']");
Literal3.Text = current_box_temp[0].InnerText;

Creo que ya vieron el poder de Html Agility Pack.

Este es el código completo:

protected void Page_Load(object sender, EventArgs e)
{
string url = @"http://www.codeproject.com/";
System.Net.WebClient wc = new System.Net.WebClient();
HtmlDocument doc = new HtmlDocument();

//recuperamos la página web completa
doc.Load(wc.OpenRead(url), System.Text.Encoding.GetEncoding("ISO-8859-1"));

//Recuperamos el logo
HtmlNodeCollection logo = doc.DocumentNode.SelectNodes(@"//td[@class='header']/a");
Literal1.Text = logo[0].InnerHtml;

//Recuperamos el menu principal
HtmlNodeCollection ul = doc.DocumentNode.SelectNodes(@"//ul[@id='nav']");
Literal2.Text = ul[0].InnerHtml;

url = "http://espanol.weather.com/weather/today-Lima-PEXX0011";
doc.Load(wc.OpenRead(url), System.Text.Encoding.GetEncoding("ISO-8859-1"));

HtmlNodeCollection img = doc.DocumentNode.SelectNodes(@"//div[@id='current_box_icon']/img");
Image1.ImageUrl = img[0].Attributes["src"].Value;

HtmlNodeCollection current_box_temp = doc.DocumentNode.SelectNodes(@"//div[@id='current_box_temp']");
Literal3.Text = current_box_temp[0].InnerText;
}


Se imaginan intentar recuperar los contenidos de otra manera? elaborando expresiones regulares, buscar como cadenas, etc, sería realmente trabajoso.

Tal vez estés preguntándote: y cuál es una forma fácil de detectar cuál es la ruta de elementos html que debo construir en mi expresión XPATH y con eso lograr capturar el contenido que requiero?

Pues, debes apoyarte de herramientas que te permitan navegar visualmente de manera sencilla por la estructura de la página web, para ello:

Chrome tiene la herramienta Developer Tools, la cual la puedes activar haciendo click derecho sobre la página web y eligiendo la opción “Inspeccionar elemento”. Internet Explorer también tiene sus herramientas de desarrollador. Firefox tiene Firebug y web Developer, entre otras.

Este post ha mostrado un extracto simplemente de lo que se puede hacer con Html Agility Pack. El resto de información lo pueden encontrar en http://htmlagilitypack.codeplex.com/

Espero que les sea de utilidad ;)

No hay comentarios.: