क्या हम सुंदर के साथ xpath का उपयोग कर सकते हैं?


105

मैं एक यूआरएल को स्क्रेप करने के लिए ब्यूटीफुल का उपयोग कर रहा हूं और मेरे पास निम्न कोड था

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 का उपयोग करना संभव है? यदि संभव हो तो, क्या कोई मुझे एक उदाहरण कोड प्रदान कर सकता है ताकि यह अधिक उपयोगी हो?

जवाबों:


168

नहींं, सुंदरसुपे, स्वयं के द्वारा, XPath अभिव्यक्तियों का समर्थन नहीं करता है।

एक वैकल्पिक पुस्तकालय, lxml , XPath 1.0 का समर्थन करता है । इसमें एक ब्यूटीफुल कम्पेटिबल मोड है जहाँ यह कोशिश करेगा और टूटे हुए एचटीएमएल को सोप करेगा। हालाँकि, डिफ़ॉल्ट lxml HTML parser टूटी हुई 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)

आपके लिए संभावित रुचि सीएसएस चयनकर्ता समर्थन है ; CSSSelectorवर्ग 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
बहुत बहुत धन्यवाद पीटर, मुझे उर कोड से दो सूचना मिली, 1। एक स्पष्टीकरण है कि हम xpath का उपयोग बीएस 2 के साथ नहीं कर सकते हैं। lxml का उपयोग करने पर एक अच्छा उदाहरण। क्या हम इसे किसी विशेष दस्तावेज पर देख सकते हैं कि "हम लिखित रूप में बीएस का उपयोग करके xpath को लागू नहीं कर सकते हैं", क्योंकि हमें किसी ऐसे व्यक्ति को कुछ सबूत दिखाना चाहिए जो स्पष्टीकरण के लिए सही पूछते हैं?
शिव कृष्ण बावंडला

8
नकारात्मक साबित करना मुश्किल है; द ब्यूटीफुल 4 डॉक्यूमेंट में एक सर्च फंक्शन है और 'xpath' के लिए कोई हिट नहीं है।
मार्टिन पीटर्स

122

मैं पुष्टि कर सकता हूं कि सुंदर सूप के भीतर कोई XPath समर्थन नहीं है।


76
नोट: लियोनार्ड रिचर्डसन सुंदर सूप के लेखक हैं, जैसा कि आप देखेंगे कि क्या आप उनके उपयोगकर्ता प्रोफ़ाइल के माध्यम से क्लिक करते हैं।
14:30

23
सुंदरसुपर
डार्थऑप्टो के

4
तो क्या विकल्प है?
static_rtti

40

जैसा कि दूसरों ने कहा है, सुंदरसुपे के पास xpath का समर्थन नहीं है। शायद एक xpath से कुछ प्राप्त करने के कई तरीके हैं, जिसमें सेलेनियम का उपयोग करना भी शामिल है। हालाँकि, यहाँ एक समाधान है जो पायथन 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), तो xpaths को रूट द्वारा संदर्भित करने से काम नहीं होगा, आपको सापेक्ष xpaths का उपयोग करना होगा। lxml.de/xpathxslt.html
wordsforthewise

मार्टिज़न का कोड अब ठीक से काम नहीं करता है (यह अब तक 4+ साल पुराना है ...), etree.parse () लाइन कंसोल को प्रिंट करता है और ट्री वैरिएबल को मान असाइन नहीं करता है। यह काफी दावा है। मैं निश्चित रूप से ऐसा नहीं कर सकता, और इसका कोई मतलब नहीं होगा । क्या आप सुनिश्चित हैं कि आप मेरे कोड का परीक्षण करने के लिए Python 2 का उपयोग कर रहे हैं या urllib2Python 3 के लिए लाइब्रेरी उपयोग का अनुवाद किया है urllib.request?
मार्टिन पीटर्स

हाँ, यह मामला हो सकता है कि मैंने जब इसे लिखते समय Python3 का उपयोग किया हो और यह अपेक्षा के अनुरूप काम न करे। बस का परीक्षण किया और तुम्हारा को Python2 के साथ काम करता है, लेकिन python3 ज्यादा पसंद किया जाता है के रूप में 2 सूर्यास्त जा रहा है (अब आधिकारिक तौर पर समर्थित) में 2020 है
wordsforthewise

बिल्कुल सहमत हैं, लेकिन यहाँ सवाल अजगर 2 का उपयोग करता है
मार्टिन पीटर्स

17

BeautifulSoup का एक फ़ंक्शन है जिसका नाम 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 विकल्प नहीं है। इसके अलावा, जैसा कि आप एसओ पर एक समान प्रश्न पर यहां देख सकते हैं , ओपी xpath से सुंदरसूप में अनुवाद के लिए पूछ रहा है, इसलिए मेरा निष्कर्ष होगा - नहीं, कोई xpath पार्सिंग उपलब्ध नहीं है।


हाँ वास्तव में अब तक मैं स्क्रैपी का उपयोग करता था जो डेटा को टैग के अंदर लाने के लिए xpath का उपयोग करता है। डेटा प्राप्त करने के लिए बहुत आसान और आसान है, लेकिन मुझे सुंदरसुपे के साथ भी ऐसा करने की आवश्यकता है ताकि इसमें आगे देख सकें।
शिव कृष्णा बावनदला

1

जब आप सभी सरल lxml का उपयोग करते हैं:

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

लेकिन जब सुंदर बीएस 4 बीएस का उपयोग करें तो सभी सरल:

  • पहले "//" और "@" निकालें
  • दूसरा - "=" से पहले स्टार जोड़ें

इस जादू की कोशिश करो:

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

जैसा कि आप देखते हैं, यह उप-टैग का समर्थन नहीं करता है, इसलिए मैं "/ @ href" भाग को हटा देता हूं


select()CSS चयनकर्ताओं के लिए है, यह XPath बिलकुल नहीं है। जैसा कि आप देख रहे हैं, यह उप-टैग का समर्थन नहीं करता है जबकि मुझे यकीन नहीं है कि अगर यह उस समय सच था, तो यह निश्चित रूप से अब नहीं है।
एएमसी

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

ऊपर lxml के साथ सूप वस्तु के संयोजन का इस्तेमाल किया और एक xpath का उपयोग कर मूल्य निकाल सकते हैं


0

यह एक बहुत पुराना धागा है, लेकिन अब एक काम के आसपास समाधान है, जो शायद उस समय सुंदरसुपर में नहीं था।

यहाँ एक उदाहरण है कि मैंने क्या किया। मैं आरएसएस फ़ीड पढ़ने और "rss_text" नामक एक चर में इसकी पाठ सामग्री प्राप्त करने के लिए "अनुरोध" मॉड्यूल का उपयोग करता हूं। इसके साथ, मैं इसे सुंदरसुपर के माध्यम से चलाता हूं, xpath / rss / चैनल / शीर्षक के लिए खोज करता हूं, और इसकी सामग्री पुनर्प्राप्त करता हूं। यह अपने सभी महिमा (वाइल्डकार्ड, कई पथ, आदि) में बिल्कुल XPath नहीं है, लेकिन अगर आपके पास बस एक मूल पथ है जिसे आप ढूंढना चाहते हैं, तो यह काम करता है।

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

मेरा मानना ​​है कि यह केवल बाल तत्वों को ढूंढता है। XPath एक और बात है?
राफेल
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.