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.