kunnen we XPath gebruiken met BeautifulSoup?

Ik gebruik BeautifulSoup om een ​​URL te schrapen en ik had de volgende code om de td-tag te vinden waarvan de klasse 'empformbody'is:

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

Nu kunnen we in de bovenstaande code findAllgebruiken om tags en informatie over hen te krijgen, maar ik wil XPath gebruiken. Is het mogelijk om XPath te gebruiken met BeautifulSoup? Geef me indien mogelijk een voorbeeldcode.


Antwoord 1, autoriteit 100%

Nee, BeautifulSoup op zichzelf ondersteunt geen XPath-expressies.

Een alternatieve bibliotheek, lxml, ondersteuntXPath 1.0. Het heeft een BeautifulSoup-compatibele moduswaar het zal proberen om gebroken HTML te ontleden zoals Soup dat doet. De standaard lxml HTML-parserkan echter net zo goed kapotte HTML ontleden, en ik geloof dat het sneller is .

Zodra u uw document in een lxml-boomstructuur hebt geparseerd, kunt u de methode .xpath()gebruiken om naar elementen te zoeken.

try:
    # Python 2
    from urllib2 import urlopen
except ImportError:
    from urllib.request import urlopen
from lxml import etree
url =  "http://www.example.com/servlet/av/ResultTemplate=AVResult.html"
response = urlopen(url)
htmlparser = etree.HTMLParser()
tree = etree.parse(response, htmlparser)
tree.xpath(xpathselector)

Er is ook een speciale lxml.html()-modulemet extra functionaliteit.

Merk op dat ik in het bovenstaande voorbeeld het response-object rechtstreeks aan lxmlheb doorgegeven, omdat het efficiënter is om de parser rechtstreeks uit de stream te laten lezen dan het antwoord in een grote snaar eerst. Om hetzelfde te doen met de requestsbibliotheek, wil je stream=Trueinstellen en het response.rawobject na het inschakelen van transparante transportdecompressie:

import lxml.html
import requests
url =  "http://www.example.com/servlet/av/ResultTemplate=AVResult.html"
response = requests.get(url, stream=True)
response.raw.decode_content = True
tree = lxml.html.parse(response.raw)

Van mogelijk belang voor u is de CSS Selector-ondersteuning; de klasse CSSSelectorvertaalt CSS-statements naar XPath-expressies, wat het zoeken naar td.empformbodyveel gemakkelijker maakt:

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

De cirkel rond: BeautifulSoup zelf heefteen zeer complete CSS selector ondersteuning:

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

Antwoord 2, autoriteit 83%

Ik kan bevestigen dat er geen XPath-ondersteuning is binnen Beautiful Soup.


Antwoord 3, autoriteit 27%

Zoals anderen al hebben gezegd, heeft BeautifulSoup geen xpath-ondersteuning. Er zijn waarschijnlijk een aantal manieren om iets van een xpath te krijgen, waaronder het gebruik van Selenium. Hier is echter een oplossing die werkt in Python 2 of 3:

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)

Ik heb ditals referentie gebruikt.


Antwoord 4, autoriteit 9%

BeautifulSoup heeft een functie genaamd findNextvan huidig ​​element gericht kind, dus:

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

Bovenstaande code kan het volgende xpath imiteren:

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

Antwoord 5, autoriteit 8%

from lxml import etree
from bs4 import BeautifulSoup
soup = BeautifulSoup(open('path of your localfile.html'),'html.parser')
dom = etree.HTML(str(soup))
print dom.xpath('//*[@id="BGINP01_S1"]/section/div/font/text()')

Hierboven is de combinatie van Soup-object met lxml gebruikt en men kan de waarde extraheren met xpath


Antwoord 6, autoriteit 2%

wanneer je lxml gebruikt, heel eenvoudig:

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

maar bij gebruik van BeautifulSoup BS4 ook nog eens heel eenvoudig:

  • verwijder eerst “//” en “@”
  • tweede – ster toevoegen vóór “=”

probeer deze magie:

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

zoals je ziet, ondersteunt dit geen sub-tag, dus ik verwijder het “/@href” gedeelte


Antwoord 7

Ik heb hun documentendoorzocht en het lijkt erop dat er geen XPath-optie.

Ook, zoals je hierkunt zien op een vergelijkbare vraag over SO vraagt ​​de OP om een ​​vertaling van XPath naar BeautifulSoup, dus mijn conclusie zou zijn – nee, er is geen XPath-parsing beschikbaar.


Antwoord 8

Misschien kun je het volgende proberen zonder XPath

from simplified_scrapy.simplified_doc import SimplifiedDoc 
html = '''
<html>
<body>
<div>
    <h1>Example Domain</h1>
    <p>This domain is for use in illustrative examples in documents. You may use this
    domain in literature without prior coordination or asking for permission.</p>
    <p><a href="https://www.iana.org/domains/example">More information...</a></p>
</div>
</body>
</html>
'''
# What XPath can do, so can it
doc = SimplifiedDoc(html)
# The result is the same as doc.getElementByTag('body').getElementByTag('div').getElementByTag('h1').text
print (doc.body.div.h1.text)
print (doc.div.h1.text)
print (doc.h1.text) # Shorter paths will be faster
print (doc.div.getChildren())
print (doc.div.getChildren('p'))

Antwoord 9

Dit is een behoorlijk oude thread, maar er is nu een tijdelijke oplossing, die op dat moment misschien niet in BeautifulSoup zat.

Hier is een voorbeeld van wat ik heb gedaan. Ik gebruik de “requests”-module om een RSS-feed te lezen en de tekstinhoud in een variabele genaamd “rss_text” te krijgen. Daarmee voer ik het door BeautifulSoup, zoek naar de xpath /rss/channel/title en haal de inhoud ervan op. Het is niet bepaald XPath in al zijn glorie (jokertekens, meerdere paden, enz.), maar als je gewoon een basispad hebt dat je wilt vinden, werkt dit.

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

Antwoord 10

gebruik soup.find(class_='myclass')

Other episodes