2012-07-13 43 views
66

estoy usando BeautifulSoup para raspar una URL y que tenía el siguiente código¿podemos usar xpath con BeautifulSoup?

import urllib 
import urllib2 
from BeautifulSoup import BeautifulSoup 

url = "http://www.example.com/servlet/av/ResultTemplate=AVResult.html" 
req = urllib2.Request(url) 
response = urllib2.urlopen(req) 
the_page = response.read() 
soup = BeautifulSoup(the_page) 
soup.findAll('td',attrs={'class':'empformbody'}) 

Ahora en el código anterior podemos utilizar findAll para obtener etiquetas e información relacionada con ellos, pero quiero utilizar XPath. ¿Es posible usar xpath con BeautifulSoup? Si es posible, ¿alguien puede proporcionarme un código de ejemplo para que sea más útil?

Respuesta

108

No, BeautifulSoup, por sí solo, no admite expresiones XPath.

Una biblioteca alternativa, lxml, hace compatible con XPath 1.0. Tiene un BeautifulSoup compatible mode donde intentará analizar HTML roto de la misma manera que Soup. Sin embargo, el default lxml HTML parser hace tan buen trabajo de análisis de HTML roto, y creo que es más rápido.

Una vez que haya analizado el documento en un árbol lxml, puede usar el método .xpath() para buscar elementos.

import urllib2 
from lxml import etree 

url = "http://www.example.com/servlet/av/ResultTemplate=AVResult.html" 
response = urllib2.urlopen(url) 
htmlparser = etree.HTMLParser() 
tree = etree.parse(response, htmlparser) 
tree.xpath(xpathselector) 

De posible interés para usted es el CSS Selector support; la clase CSSSelector traduce declaraciones CSS en expresiones XPath, por lo que su búsqueda de td.empformbody que mucho más fácil:

from lxml.cssselect import CSSSelector 

td_empformbody = CSSSelector('td.empformbody') 
for elem in td_empformbody(tree): 
    # Do something with these table cells. 

Cerrando el círculo: sí BeautifulSoup hace tienen bastante decente CSS selector support:

for cell in soup.select('table#foobar td.empformbody'): 
    # Do something with these table cells. 
+0

Muchas gracias Pieters, tengo dos informaciones de tu código, 1. Una aclaración de que no podemos usar xpath con BS 2. Un buen ejemplo de cómo usar lxml. ¿Podemos ver en una documentación particular que "no podemos implementar xpath utilizando BS en forma escrita", porque debemos mostrar algunas pruebas a alguien que pida una aclaración, ¿verdad? –

+0

De todos modos, gracias por tu ayuda. –

+6

Es difícil demostrar una negativa; la [documentación de BeautifulSoup 4] (http://www.crummy.com/software/BeautifulSoup/bs4/doc/) tiene una función de búsqueda y no hay resultados para 'xpath'. –

1

He buscado a través de su docs y parece que no hay una opción xpath. Además, como puede ver here en una pregunta similar en SO, el OP está solicitando una traducción de xpath a BeautifulSoup, por lo que mi conclusión sería: no, no hay ningún análisis de xpath disponible.

+0

[ 'scrapy'] (http://scrapy.org/) es otra opción para obtener lxml trabajo BS ingenio – inspectorG4dget

+0

sí en realidad hasta ahora he usado scrapy que utiliza XPath para recuperar los datos dentro de muy tags.Its práctico y fácil de obtener datos, pero tengo la necesidad de hacer lo mismo con beautifulsoup así que estoy ansioso por obtenerlo. –

77

puedo confirmar que no hay soporte XPath en Beautiful Soup.

+46

Nota: Leonard Richardson es el autor de Beautiful Soup, como verá si hace clic en su perfil de usuario. – senshin

+13

Sería muy bueno poder usar XPATH dentro de BeautifulSoup – DarthOpto

+0

Entonces, ¿cuál es la alternativa? –

9

BeautifulSoup tiene una función llamada findNext del elemento actual dirigida hijos también, así que:

father.findNext('div',{'class':'class_value'}).findNext('div',{'id':'id_value'}).findAll('a') 

Por encima de código puede imitar la siguiente XPath:

div[class=class_value]/div[id=id_value] 
16

código de Martijn ya no funciona correctamente (es 4 + años antes de ahora ...), la línea etree.parse() se imprime en la consola y no asigna el valor a la variable tree. Hacer referencia a this, yo era capaz de averiguar esto funciona mediante solicitudes y lxml:

from lxml import html 
import requests 

page = requests.get('http://econpy.pythonanywhere.com/ex/001.html') 
tree = html.fromstring(page.content) 
#This will create a list of buyers: 
buyers = tree.xpath('//div[@title="buyer-name"]/text()') 
#This will create a list of prices 
prices = tree.xpath('//span[@class="item-price"]/text()') 

print 'Buyers: ', buyers 
print 'Prices: ', prices 
0

Este es un hilo bastante viejo, pero no hay una solución trabajo en todo momento, lo cual no puede haber estado en BeautifulSoup en el momento .

Aquí hay un ejemplo de lo que hice. Utilizo el módulo de "solicitudes" para leer un canal RSS y obtener su contenido de texto en una variable llamada "rss_text". Con eso, lo ejecuto a través de BeautifulSoup, busco xpath/rss/channel/title y recupero su contenido. No es exactamente XPath en todo su esplendor (comodines, múltiples rutas, etc.), pero si solo tienes una ruta básica que deseas localizar, esto funciona.

from bs4 import BeautifulSoup 
rss_obj = BeautifulSoup(rss_text, 'xml') 
cls.title = rss_obj.rss.channel.title.get_text()