[python] BeautifulSoup에서 xpath를 사용할 수 있습니까?

BeautifulSoup을 사용하여 URL을 긁어 내고 다음 코드가 있습니다.

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

이제 위의 코드에서 findAll태그와 관련 정보를 가져 오는 데 사용할 수 있지만 xpath를 사용하고 싶습니다. BeautifulSoup에서 xpath를 사용할 수 있습니까? 가능하다면 누구든지 더 도움이 될 수 있도록 예제 코드를 제공해 주시겠습니까?



답변

아니요, BeautifulSoup 자체는 XPath 표현식을 지원하지 않습니다.

또 다른 라이브러리, LXML는 , 수행 지원의 XPath 1.0. 그것은이 BeautifulSoup로 호환 모드 는 노력 할게요 및 HTML에게 수프가하는 방법을 깨진 구문 분석합니다. 그러나 기본 lxml HTML 파서 는 깨진 HTML을 파싱하는 것과 똑같이 잘 수행하며 더 빠르다고 생각합니다.

문서를 lxml 트리로 구문 분석 한 후에는 .xpath()메서드를 사용하여 요소를 검색 할 수 있습니다 .

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)

도있다 전용 lxml.html()모듈추가 기능이 있습니다.

위의 예 에서는 파서가 스트림에서 직접 읽도록하는 것이 응답을 큰 문자열로 먼저 읽는 것보다 더 효율적이므로 response객체를에 직접 전달했습니다 lxml. requests라이브러리 에서 동일한 작업을 수행하려면 투명 전송 압축 해제를 활성화 한 후 객체 를 설정 stream=True하고 전달 하려고합니다 .response.raw

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)

관심을 가질만한 것은 CSS 선택기 지원입니다 . 이 CSSSelector클래스는 CSS 문을 XPath 표현식으로 변환하여 검색을 td.empformbody훨씬 쉽게 만듭니다 .

from lxml.cssselect import CSSSelector

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

온전한 순환 : BeautifulSoup 자체 매우 완벽한 CSS 선택기를 지원합니다 .

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


답변

뷰티플 수프에 XPath 지원이 없음을 확인할 수 있습니다.


답변

다른 사람들이 말했듯이 BeautifulSoup은 xpath를 지원하지 않습니다. Selenium 사용을 포함하여 xpath에서 무언가를 얻는 방법에는 여러 가지가 있습니다. 그러나 여기에 Python 2 또는 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)

나는 이것을 참고로 사용했다.


답변

BeautifulSoup에는 현재 요소가 지정된 childern에서 findNext 라는 함수가 있습니다 .

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

위의 코드는 다음 xpath를 모방 할 수 있습니다.

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


답변

나는 그들의 문서를 검색 했고 xpath 옵션이없는 것 같습니다. 또한 여기 에서 비슷한 질문에서 볼 수 있듯이 OP는 xpath에서 BeautifulSoup으로의 번역을 요청하므로 내 결론은-아니요, 사용할 수있는 xpath 구문 분석이 없습니다.


답변

lxml을 모두 간단하게 사용할 때 :

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

그러나 BeautifulSoup BS4를 사용할 때도 모두 간단합니다.

  • 먼저 “//”및 “@”제거
  • 두 번째- “=”앞에 별표 추가

이 마술을 시도하십시오.

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

보시다시피 이것은 하위 태그를 지원하지 않으므로 “/ @ href”부분을 제거합니다.


답변

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