pouvons-nous utiliser xpath avec BeautifulSoup?

j'utilise BeautifulSoup pour gratter une url et j'avais le code suivant

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'})

maintenant dans le code ci-dessus nous pouvons utiliser findAll pour obtenir des tags et des informations les concernant, mais je veux utiliser xpath. Est-il possible d'utiliser XPath avec BeautifulSoup? Si possible, est-ce que quelqu'un peut me fournir un exemple de code pour qu'il soit plus utile?

75
demandé sur Community 2012-07-13 10:55:19

7 réponses

Non, BeautifulSoup, à lui seul, ne supporte pas les expressions XPath.

Une bibliothèque alternative, lxml , ne support de XPath 1.0. Il a un BeautifulSoup mode compatible où il essaiera et analyse HTML cassé la façon dont la soupe fait. Cependant ,le par défaut lxml HTML parser fait tout aussi bien un travail de parsing HTML cassé, et je crois est plus rapide.

une fois que vous avez analysé votre document dans un arbre lxml, vous pouvez utiliser la méthode .xpath() pour rechercher des éléments.

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)

d'intérêt possible pour vous est le CSS Selector support ; la classe CSSSelector traduit les déclarations CSS en expressions XPath, rendant votre recherche pour td.empformbody beaucoup plus facile:

from lxml.cssselect import CSSSelector

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

boucler la boucle: BeautifulSoup lui-même ne avoir assez décent CSS selector support :

for cell in soup.select('table#foobar td.empformbody'):
    # Do something with these table cells.
123
répondu Martijn Pieters 2014-05-13 00:27:24

je peux confirmer qu'il n'y a pas de support XPath dans la belle soupe.

84
répondu Leonard Richardson 2012-07-13 11:44:45

le code de Martijn ne fonctionne plus correctement (il a maintenant plus de 4 ans...), la ligne etree.parse() imprime sur la console et n'attribue pas la valeur à la variable tree . En me référant à ce , j'ai pu comprendre ce travail en utilisant requests et 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
28
répondu wordsforthewise 2017-01-06 21:38:07

BeautifulSoup a une fonction appelée findNext de l'élément actuel dirigé childern, so:

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

code ci-dessus peut imiter le xpath suivant:

div[class=class_value]/div[id=id_value]
10
répondu user3820561 2017-02-03 19:21:31

j'ai cherché dans leur docs et il semble qu'il n'y ait pas d'option xpath. En outre, comme vous pouvez voir ici sur une question similaire sur SO, L'OP demande une traduction de xpath à BeautifulSoup, donc ma conclusion serait - non, il n'y a pas de parsing xpath disponible.

1
répondu Nikola 2017-05-23 10:31:31

c'est un très vieux fil, mais il y a une solution de rechange maintenant, qui n'a peut-être pas été dans BeautifulSoup à l'époque.

Voici un exemple de ce que j'ai fait. J'utilise le module " requêtes "pour lire un flux RSS et obtenir son contenu texte dans une variable appelée"rss_text". Avec cela, je l'exécute par BeautifulSoup, je cherche le XPath/rss/channel / title, et je récupère son contenu. Ce N'est pas exactement XPath dans toute sa gloire (jokers, chemins multiples, etc.), mais si vous avez juste un chemin de base que vous voulez localiser, cela fonctionne.

from bs4 import BeautifulSoup
rss_obj = BeautifulSoup(rss_text, 'xml')
cls.title = rss_obj.rss.channel.title.get_text()
0
répondu David A 2017-12-15 21:46:08

quand vous utilisez lxml tout simple:

tree = lxml.html.fromstring(html)
i_need_element = tree.xpath('//a[@class="shared-components"]/@href')

mais quand utiliser BeautifulSoup BS4 tout simple aussi:

  • d'abord enlever les "//" et "@"
  • deuxième-ajouter l'étoile avant " = "

essayez cette magie:

soup = BeautifulSoup(html, "lxml")
i_need_element = soup.select ('a[class*="shared-components"]')

comme vous le voyez, cela ne supporte pas les sous-tags, donc je supprime" / @href "part

0
répondu Oleksandr Panchenko 2018-08-18 10:15:26