2012-07-13 16 views
66

Sto usando BeautifulSoup per raschiare un URL e ho avuto il seguente codicepossiamo usare 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'}) 

Ora nel codice qui sopra possiamo utilizzare findAll per ottenere i tag e le informazioni relative a loro, ma voglio usare XPath. È possibile usare xpath con BeautifulSoup? Se possibile, qualcuno può fornirmi un codice di esempio in modo che sia più utile?

risposta

108

No, BeautifulSoup, di per sé, non supporta le espressioni XPath.

Una libreria alternativa, lxml, fa supporta XPath 1.0. Ha un BeautifulSoup compatible mode dove tenterà di analizzare l'HTML spezzato come fa Soup. Tuttavia, lo default lxml HTML parser fa altrettanto bene l'analisi dell'HT rotto, e credo sia più veloce.

Dopo aver analizzato il documento in un albero lxml, è possibile utilizzare il metodo .xpath() per cercare elementi.

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) 

di possibile interesse per voi è la CSS Selector support; la classe CSSSelector traduce dichiarazioni CSS in espressioni XPath, rendendo la ricerca di td.empformbody che molto più facile:

from lxml.cssselect import CSSSelector 

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

Venendo al punto di partenza: BeautifulSoup stesso fa hanno abbastanza decente CSS selector support:

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

Grazie mille Pieters, ho due informazioni dal codice ur, 1. Un chiarimento sul fatto che non possiamo usare xpath con BS 2. Un bell'esempio su come usare lxml. Possiamo vederlo su una particolare documentazione che "non possiamo implementare xpath usando BS in forma scritta", perché dovremmo mostrare delle prove a qualcuno che chiede chiarimenti, giusto? –

+0

In ogni caso grazie per il tuo aiuto prezioso –

+6

È difficile provare un risultato negativo; la [documentazione di BeautifulSoup 4] (http://www.crummy.com/software/BeautifulSoup/bs4/doc/) ha una funzione di ricerca e non ci sono risultati per 'xpath'. –

1

Ho cercato attraverso il loro docs e sembra che non ci sia l'opzione xpath. Inoltre, come potete vedere here su una domanda simile su SO, l'OP chiede una traduzione da xpath a BeautifulSoup, quindi la mia conclusione sarebbe: no, non è disponibile l'analisi di xpath.

+0

[ 'scrapy'] (http://scrapy.org/) è un'altra opzione per ottenere lxml lavorare spirito BS – inspectorG4dget

+0

sì in realtà fino ad ora ho usato Scrapy che utilizza XPath per recuperare i dati all'interno tags.Its molto pratico e facile da recuperare i dati, ma ho avuto la necessità di fare lo stesso con beautifulsoup così in attesa di esso. –

77

Posso confermare che non esiste supporto XPath all'interno di Beautiful Soup.

+46

Nota: Leonard Richardson è l'autore di Beautiful Soup, come vedrai se clicchi sul suo profilo utente. – senshin

+13

Sarebbe molto bello poter usare XPATH all'interno di BeautifulSoup – DarthOpto

+0

Quindi qual è l'alternativa? –

9

BeautifulSoup ha una funzione denominata findNext da elemento corrente diretto childern, quindi:

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

Sopra codice può imitare la seguente XPath:

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

codice di Martijn non funziona più correttamente (è 4 + anni oramai ...), la riga etree.parse() stampa sulla console e non assegna il valore alla variabile tree. Riferimento this, sono stato in grado di capire questo funziona utilizzando le richieste e 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

Questa è una discussione piuttosto vecchio, ma c'è una soluzione work-around ora, che non può essere stato in BeautifulSoup al momento .

Ecco un esempio di ciò che ho fatto. Io uso il modulo "richieste" per leggere un feed RSS e ottenere il suo contenuto di testo in una variabile chiamata "rss_text". Con ciò, lo eseguo tramite BeautifulSoup, cerca xpath/rss/channel/title e recupera il suo contenuto. Non è esattamente XPath in tutta la sua gloria (caratteri jolly, percorsi multipli, ecc.), Ma se hai solo un percorso di base che vuoi localizzare, questo funziona.

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