2009-03-14 15 views
6

Estaba respondiendo algunas preguntas de prueba para una entrevista, y la pregunta era acerca de cómo iba a hacer raspado de pantalla. Es decir, seleccionando contenido de una página web, suponiendo que no tienes una mejor manera estructurada de consultar la información directamente (por ejemplo, un servicio web).Raspado de pantalla: expresiones regulares o expresiones XQuery?

Mi solución fue utilizar una expresión XQuery. La expresión fue bastante larga porque el contenido que necesitaba era bastante profundo en la jerarquía de HTML. Tuve que buscar a través de los antepasados ​​de una manera justa antes de encontrar un elemento con un atributo id. Por ejemplo, raspando una página de Amazon.com para Dimensiones del producto se ve así:

//a[@id="productDetails"] 
/following-sibling::table 
//h2[contains(child::text(), "Product Details")] 
/following-sibling::div 
//li 
/b[contains(child::text(), "Product Dimensions:")] 
/following-sibling::text() 

Esa es una expresión bastante desagradable, pero es por eso Amazon proporciona una API de servicios web. De todos modos, es solo un ejemplo. La pregunta no era sobre Amazon, sino sobre el raspado de la pantalla.

Al entrevistador no le gustó mi solución. Pensó que era frágil, porque un cambio en el diseño de la página de Amazon podría requerir la reescritura de la expresión XQuery. La depuración de una expresión de XQuery que no coincide con nada en la página en la que se aplica es difícil.

No estoy en desacuerdo con sus declaraciones, pero no creo que su solución haya sido una mejora: pensó que es mejor usar una expresión regular , y buscar contenido y etiquetas cerca del peso de envío. Por ejemplo, usando Perl:

$html =~ m{<li>\s*<b>\s*Product Dimensions:\s*</b>\s*(.*?)</li>}s; 

Mi argumento en contra es que esto también es susceptible a Amazon cambiar su código HTML. Podrían deletrear etiquetas HTML en mayúsculas (<LI>), o agregar atributos CSS o cambiar <b> a <span> o cambiar la etiqueta "Dimensiones del producto:" a "Dimensiones:" o muchos otros tipos de cambios. Mi punto era que las expresiones regulares no resuelven las debilidades que llamó en mi solución XQuery.

Pero, además, las expresiones regulares pueden encontrar falsos positivos, a menos que agregue suficiente contexto a la expresión. También puede hacer coincidir involuntariamente contenido que esté dentro de un comentario, o una cadena de atributo, o una sección CDATA.

Mi pregunta es, ¿qué tecnología utilizas para raspar la pantalla? ¿Por qué elegiste esa solución? ¿Hay alguna razón convincente para usar uno? ¿O nunca usas el otro? ¿Hay una tercera opción además de las que mostré arriba?

PD: Supongamos por el argumento que no existe una API de servicio web u otra forma más directa de adquirir el contenido deseado.

Respuesta

3

Utilizaría una expresión regular, por las razones que dio el gerente, además de algunas (más portátil, más fácil para los programadores externos, etc.).

Su argumento contrario pierde el punto de que su solución era frágil con respecto a cambios locales, mientras que la suya es frágil con respecto a cambios globales. Cualquier cosa que rompa su voluntad probablemente rompa la tuya, pero no viceversa.

Finalmente, es mucho más fácil construir slop/flex en su solución (si, por ejemplo, tiene que lidiar con múltiples variaciones menores en la entrada).

4

Utilizaría una expresión regular, pero solo porque la mayoría de las páginas HTML no son XML válidas, por lo que nunca conseguiría que XQUERY funcionara.

No sé XQuery, pero eso parece una expresión XPATH para mí. Si es así, parece un poco caro con tantos operadores "//" en él.

+0

Esta es la razón principal para evitar el raspado web basado en XML. Ningún procesador XML es tan indulgente como un navegador. La página solo necesita romper una regla de buena formación para que XQuery sea completamente inútil. – harpo

1

De hecho, encuentro que las expresiones de búsqueda CSS son más fáciles de leer que cualquiera de las dos. Probablemente exista al menos una biblioteca en el idioma de su elección que analizará una página y le permitirá escribir directivas CSS para localizar elementos particulares. Si hay una clase o un enlace ID apropiado cerca, la expresión es bastante trivial. De lo contrario, tome los elementos que parezcan apropiados e itere a través de ellos para encontrar los que necesita.

En cuanto a frágil, bueno, todos son frágiles. El rozamiento de la pantalla depende por definición del autor de esa página y no cambia drásticamente su diseño. Vaya con una solución que sea legible y se pueda cambiar fácilmente más adelante.

1

¿Una solución no quebradiza para raspar la pantalla? Buena suerte para el entrevistador por eso: solo porque las expresiones regulares desechen un montón de contexto no significa que sean menos frágiles: solo que son frágiles de otras maneras. La fragilidad puede no ser un inconveniente: si algo cambia en la página web de origen, con frecuencia es mejor si su solución genera una alarma, en lugar de tratar de compensar de una manera inteligente (e impredecible). Como notaste. Estas cosas siempre dependen de sus suposiciones: en este caso, sobre lo que constituye un cambio probable.

Me gusta mucho el HTML agility pack: obtienes tolerancia de páginas web que no son compatibles con XHTML combinadas con el poder expresivo de XPath.

2

Prueba JTidy o BeautifulSoup funciona bien para mí. ciertamente // La expersión de XPATH es bastante costosa de eliminar.

1

Las expresiones regulares son realmente rápidas y funcionan con documentos que no son XML. Esos son realmente buenos puntos contra XQuery. Sin embargo, creo que el uso de algún convertidor de XHTML como XQuery ordenada y tal vez algo más simple, como sólo la última parte de la suya:

//b[contains(child::text(), "Product Dimensions:")]/following-sibling::text() 

es una muy buena alternativa.

Saludos,

Rafal Rusin

1

para trabajar en las páginas html, lo mejor es utilizar HTMLAgilityPack (y con algunos códigos LINQ) es. Es una excelente manera de analizar todos los elementos y/o hacer una búsqueda directa con XPath. En mi opinión, es más preciso que RegEx y más fácil de programar. Estaba un poco reacio a usarlo anteriormente, pero es muy fácil de agregar a su proyecto y creo que es el estándar de factor para trabajar con html. http://htmlagilitypack.codeplex.com/

¡Buena suerte!

+0

Gracias, sí, HTML Agility Pack fue sugerido en otra respuesta por Pontus Gagge. Me pregunto qué HTML Agility Pack usa internamente: XPath, expresiones regulares o algún otro análisis DOM personalizado u otra cosa. –

+1

Con HtmlAgilityPack, puede recorrer todo el DOM a través de DocumentNode.ChildNodes. Por ejemplo: para cada voTag en voMyHTML.DocumentNode.ChildNodes o se puede enfocar en un solo nodo con voMyHTML.DocumentNode.SelectSingleNode (vsXPath) o incluso se puede utilizar LINQ: voElements = (De voTag En voMyHTML.DocumentNode.ChildNodes Dónde voTag.GetAttributeValue ("clase") = "myClass" Seleccione voTag) –