llenar - ¿Por qué mi consulta XPath(raspado de tablas HTML) solo funciona en Firebug, pero no en la aplicación que estoy desarrollando?
llenar tabla en html (2)
Solo encontré el mismo problema. Casi escribí una función recursiva para buscar cada etiqueta de tbody, si existe, y recorrer el dom de esa manera, luego recordé que conozco Regex. :)
Antes de analizar, obtenga el html como una cadena. Inserte las etiquetas <tbody>
y </tbody>
faltan con expresiones regulares, luego vuelva a cargarlas en su objeto DOMDocument.
Jens Erat da una buena explicación, pero aquí está
Solución 4: asegúrese de que la fuente HTML siempre tenga las etiquetas <tbody>
con expresiones regulares
JavaScript
var html = ''<html><table><tr><td>foo</td><td>bar</td></tr></table></html>'';
html.replace(/(<table([^>]+)?>([^<>]+)?)(?!<tbody([^>]+)?>)/g,"$1<tbody>").replace(/(<(?!(//tbody))([^>]+)?>)(<//table([^>]+)?>)/g,"$1</tbody>$4");
PHP
$html = $dom->saveHTML();
$html = preg_replace(array(''/(<table([^>]+)?>([^<>]+)?)(?!<tbody([^>]+)?>)/'',''/(<(?!(//tbody))([^>]+)?>)(<//table([^>]+)?>)/''),array(''$1<tbody>'',''$1</tbody>$4''),$html);
$dom->loadHTML($html);
Solo la expresión regular:
matches `<table>` tag with whatever else junk inside the tag and between this and the next tag if the next tag is NOT `<tbody>` also with stuff inside the tag
/(<table([^>]+)?>([^<>]+)?)(?!<tbody([^>]+)?>)/
replace with
$1<tbody>
the $1 referencing the captured `<table>` tag with contents.
Do the same for the closing tag like this:
/(<(?!(//tbody))([^>]+)?>)(<//table([^>]+)?>)/
replace with
$1</tbody>$4
De esta forma, la dom SIEMPRE tendrá las etiquetas <tbody>
donde sea necesario.
Esto tiene la intención de proporcionar una Q & A canónica a todas las preguntas similares (pero demasiado específicas para ser un candidato objetivo cercano) apareciendo una o dos veces por semana.
Estoy desarrollando una aplicación que necesita analizar un sitio web con tablas. Como derivar la expresión XPath para raspar páginas web es un trabajo aburrido y propenso a errores, me gustaría usar la función Extractor XPath de Firebug (o herramientas similares en otros navegadores) para esto.
La entrada de ejemplo se ve así:
<!-- snip -->
<table id="example">
<tr>
<th>Example Cell</th>
<th>Another one</th>
</tr>
<tr>
<td>foobar</td>
<td>42</td>
</tr>
</table>
<!-- snip -->
Quiero extraer la primera celda de datos ("foobar"). Firebug propone la expresión XPath
//table[@id="example"]/tbody/tr[2]/td[1]
que funciona bien en cualquier plugin de XPath tester, pero no en mi propia aplicación (no se encontraron resultados) . Si //table[@id]
la consulta a //table[@id]
, funciona de nuevo.
¿Qué está mal?
El problema: DOM requiere <tbody/>
Etiquetas
Firebug, Chrome''s Developer Tool, las funciones de XPath en JavaScript y otras funcionan en el DOM , no en el código fuente HTML básico.
El DOM para HTML requiere que todas las filas de la tabla que no <thead/>
contenidas en un encabezado de tabla del pie de página ( <thead/>
, <tfoot/>
) estén incluidas en las etiquetas del cuerpo de la tabla <tbody/>
. Por lo tanto, los navegadores agregan esta etiqueta si falta al analizar (X) HTML. Por ejemplo, la documentación DOM de Microsoft dice
El elemento
tbody
está expuesto para todas las tablas, incluso si la tabla no define explícitamente un elementotbody
.
Hay una explicación detallada en otra respuesta sobre .
Por otro lado, HTML no requiere necesariamente que esa etiqueta sea utilizada :
La etiqueta de inicio de
TBODY
siempre se requiere, excepto cuando la tabla contiene solo un cuerpo de tabla y no hay secciones de cabecera o pie de tabla.
La mayoría de los procesadores XPath trabajan en XML sin procesar
Excluyendo JavaScript, la mayoría de los procesadores XPath trabajan en XML sin formato, no en DOM, por lo tanto no agregan etiquetas <tbody/>
. También las bibliotecas de analizadores HTML como tag-soup y htmltidy solo emiten XHTML, no "DOM-HTML".
Este es un problema común publicado en para PHP, Ruby, Python, Java, C #, Google Docs (hojas de cálculo) y muchos otros. El selenio se ejecuta dentro del navegador y funciona en el DOM, por lo que no se ve afectado.
Reproducción del problema
Compara la fuente mostrada por Firebug (o las Herramientas de desarrollo de Chrome) con la que obtienes haciendo clic con el botón derecho y seleccionando "Mostrar origen de página" (o como se llame en tus navegadores), o usando curl http://your.example.org
en la línea de comando. Últimamente, probablemente no contenga elementos <tbody/>
(raramente se usan), Firebug siempre los mostrará.
Solución 1: Eliminar /tbody
Axis Step
Comprueba si la tabla a la que estás atascado realmente no contiene un elemento <tbody/>
(ver el último párrafo). Si lo hace, probablemente haya tenido otro tipo de problema.
Ahora elimine el paso del eje /tbody
, por lo que su consulta se verá como
//table[@id="example"]/tr[2]/td[1]
Solución 2: Saltar <tbody/>
Etiquetas
Esta es una solución bastante sucia y es probable que falle en las tablas anidadas (puede saltar a las tablas internas). Solo recomendaría esto en casos muy raros.
Reemplace el paso del eje /tbody
por un paso de descendiente o auto:
//table[@id="example"]//tr[2]/td[1]
Solución 3: Permitir tanto la entrada con y sin <tbody/>
Etiquetas
Si no está seguro de antemano su tabla o use la consulta tanto en "fuente HTML" como en contexto DOM; y no quiero / no puedo usar el hack de la solución 2, proporcionar una consulta alternativa (para XPath 1.0) o usar un paso de eje "opcional" (XPath 2.0 y superior).
- XPath 1.0 :
//table[@id="example"]/tr[2]/td[1] | //table[@id="example"]/tbody/tr[2]/td[1]
- XPath 2.0 :
//table[@id="example"]/(tbody, .)/tr[2]/td[1]