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


106

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를 사용할 수 있습니까? 가능하다면 누구든지 더 도움이 될 수 있도록 예제 코드를 제공해 주시겠습니까?

답변:


169

아니요, 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.

2
Pieters에게 감사드립니다. UR 코드에서 두 가지 정보를 얻었습니다. BS 2에서 xpath를 사용할 수 없다는 설명 lxml 사용 방법에 대한 좋은 예. 특정 문서에서 "서면으로 BS를 사용하여 xpath를 구현할 수 없습니다"라는 내용을 볼 수 있습니까? 설명 권한을 요청하는 사람에게 증거를 보여야하기 때문입니다.
— Shiva Krishna Bavandla 2012

8
부정적인 것을 증명하는 것은 어렵습니다. BeautifulSoup로 4 문서 검색 기능을 가지고 있으며, 'XPath는'에 대한 조회수가 없습니다.
— Martijn Pieters

123

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


76
참고 : Leonard Richardson은 Beautiful Soup의 저자이며 사용자 프로필을 클릭하면 확인할 수 있습니다.
— senshin 2014 년

23
BeautifulSoup 내에서 XPATH를 사용할 수 있으면 매우 좋을 것입니다
— DarthOpto 2014

4
그렇다면 대안은 무엇입니까?
— static_rtti

40

다른 사람들이 말했듯이 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)

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


한 가지 경고 : 루트 외부에 무언가가있는 경우 (예 : 외부 <html> 태그 외부에 \ n) 루트로 xpath를 참조하는 것이 작동하지 않으며 상대 xpath를 사용해야합니다. lxml.de/xpathxslt.html
— wordsforthewise

Martijn의 코드는 더 이상 제대로 작동하지 않습니다 (현재 4 년 이상되었습니다 ...). etree.parse () 행이 콘솔에 인쇄되고 값을 tree 변수에 할당하지 않습니다. 그것은 상당한 주장입니다. 나는 확실히 그것을 재현 할 수 없으며, 그것은 말이되지 않을 것 입니다. Python 2를 사용하여 내 코드를 테스트하거나 urllib2라이브러리 사용을 Python 3으로 변환 urllib.request했습니까?
— Martijn Pieters

예, 그 글을 작성할 때 Python3을 사용했지만 예상대로 작동하지 않은 경우 일 수 있습니다. 방금 테스트를 마치고 Python2에서 작동하지만 Python3은 2020 년에 2가 더 이상 공식적으로 지원되지 않으므로 훨씬 선호됩니다.
— wordsforthewise

절대적으로 동의하지만 여기의 질문 은 Python 2를 사용합니다 .
— Martijn Pieters

17

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]

1

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


예, 실제로 지금까지는 xpath를 사용하여 태그 내부의 데이터를 가져 오는 스크래피를 사용했습니다. 매우 편리하고 데이터를 가져 오기가 쉽지만 beautifulsoup에서도 동일한 작업을 수행해야하므로 기대하고 있습니다.
— Shiva Krishna Bavandla

1

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"부분을 제거합니다.


select()CSS 선택자를위한 것이며 XPath가 아닙니다. 보시다시피 이것은 하위 태그를 지원하지 않습니다 . 그 당시에 그것이 사실인지 확실하지 않지만 지금은 아닙니다.
— AMC

1

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

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

위는 Soup 개체와 lxml의 조합을 사용했으며 xpath를 사용하여 값을 추출 할 수 있습니다.


0

이것은 꽤 오래된 스레드이지만 현재는 BeautifulSoup에 없었던 해결 방법이 있습니다.

여기 내가 한 일의 예가 있습니다. "요청"모듈을 사용하여 RSS 피드를 읽고 "rss_text"라는 변수에서 텍스트 내용을 가져옵니다. 이를 통해 BeautifulSoup을 통해 실행하고 xpath / rss / channel / title을 검색하고 그 내용을 검색합니다. 모든 영광 (와일드 카드, 다중 경로 등)에서 정확히 XPath는 아니지만 기본 경로 만 찾으면 작동합니다.

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

나는 이것이 단지 자식 요소를 찾는다고 믿는다. XPath는 또 다른 것입니까?
— raffaem
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.