2015-12-15 13 views
15

कहानी:अक्षम विशेष "वर्ग" विशेषता से निपटने

जब आप BeautifulSoup के साथ HTML पार्स, class विशेषता एक multi-valued attribute माना जाता है और एक विशेष ढंग से नियंत्रित किया जाता है:

याद रखें कि एक भी टैग के "वर्ग" विशेषता के लिए कई मान हो सकते हैं। जब आप एक टैग की खोज करते हैं जो एक निश्चित सीएसएस वर्ग से मेल खाता है, तो आप इसके किसी भी सीएसएस वर्ग के खिलाफ मेल खाते हैं।

इसके अलावा

, एक उद्धरण एक अंतर्निहित HTMLTreeBuilder अन्य पेड़ बिल्डर कक्षाएं, जैसे, उदाहरण के लिए के लिए एक आधार, HTMLParserTreeBuilder रूप BeautifulSoup द्वारा इस्तेमाल किया:

# The HTML standard defines these attributes as containing a 
# space-separated list of values, not a single value. That is, 
# class="foo bar" means that the 'class' attribute has two values, 
# 'foo' and 'bar', not the single value 'foo bar'. When we 
# encounter one of these attributes, we will parse its value into 
# a list of values if possible. Upon output, the list will be 
# converted back into a string. 

प्रश्न:

class को सामान्य एकल-मूल्यवान विशेषता के रूप में संभालने के लिए मैं BeautifulSoup को कैसे कॉन्फ़िगर कर सकता हूं? दूसरे शब्दों में, मैं नहीं चाहता कि यह class विशेष रूप से संभालें और इसे नियमित विशेषता मानें।

FYI करें, यहाँ उपयोग-मामले जब यह सहायक हो सकता है में से एक है:

मैं क्या कोशिश की है:

मैं वास्तव में बनाया है यह कस्टम पेड़ बिल्डर क्लास बनाकर और class को विशेष रूप से प्रबंधित विशेषताओं की सूची से हटाकर काम करता है:

from bs4.builder._htmlparser import HTMLParserTreeBuilder 

class MyBuilder(HTMLParserTreeBuilder): 
    def __init__(self): 
     super(MyBuilder, self).__init__() 

     # BeautifulSoup, please don't treat "class" specially 
     self.cdata_list_attributes["*"].remove("class") 


soup = BeautifulSoup(data, "html.parser", builder=MyBuilder()) 

मैं इस दृष्टिकोण में क्या पसंद नहीं है यह है कि काफी "अप्राकृतिक" और "जादुई" "निजी" आंतरिक _htmlparser आयात करने से जुड़े। मुझे उम्मीद है कि एक आसान तरीका है।

नोट: मैं अर्थ मैं "xml" -only सुविधाओं (जो एक और वैकल्पिक हल किया गया है हो सकता है) के साथ HTML पार्स करने के लिए नहीं करना चाहते हैं सभी अन्य HTML पार्स संबंधित सुविधाओं को बचाने के लिए चाहते हैं।

+2

मैंने सोचा कि यह एक बग था जब मैंने आपके अवतार को एक सुंदरता प्रश्न के तहत कोई उत्तर नहीं दिया और फिर मुझे एहसास हुआ कि * सवाल पूछा गया है! मैं आपकी मदद नहीं कर सकता सब कुछ मैंने कोशिश नहीं की है या दो पुनरावृत्तियों में शामिल नहीं है। – dstudeba

+0

मुझे नहीं पता कि यह कैसे करें, लेकिन उदाहरण के रूप में प्रदान किए गए विशिष्ट उपयोग मामले के लिए मैंने एक अलग उत्तर प्रदान किया (इसलिए मैंने इसे वहां पोस्ट किया)। यह मेरी राय में आसान है लेकिन अन्य उपयोग मामलों के लिए पर्याप्त नहीं हो सकता है – rll

+0

इसे एक सीएसएस चयनकर्ता के रूप में उपयोग करना? शायद उस मामले में सबसे सरल विकल्प एक सामान्य श्रेणी चयनकर्ता का उपयोग नहीं किया जा सकता है, लेकिन एक विशेषता चयनकर्ता। चयनकर्ता '.myclass' वही है जो '[वर्ग = ~ "myclass"]' है, लेकिन चयनकर्ता '[वर्ग = "वर्ग"]' एक तत्व है जिसका "वर्ग" विशेषता मान बिल्कुल "myclass" के बराबर है (नहीं एक अंतरिक्ष sepated सूची में myclass)। –

उत्तर

6

मुझे इस दृष्टिकोण में क्या पसंद नहीं है यह है कि यह "निजी" आंतरिक _htmlparser आयात करने में काफी "अप्राकृतिक" और "जादुई" है। मुझे उम्मीद है कि एक आसान तरीका है।

हाँ, आप इसे bs4.builder बजाय से आयात कर सकते हैं:

from bs4 import BeautifulSoup 
from bs4.builder import HTMLParserTreeBuilder 

class MyBuilder(HTMLParserTreeBuilder): 
    def __init__(self): 
     super(MyBuilder, self).__init__() 
     # BeautifulSoup, please don't treat "class" as a list 
     self.cdata_list_attributes["*"].remove("class") 


soup = BeautifulSoup(data, "html.parser", builder=MyBuilder()) 

और अगर यह काफी महत्वपूर्ण है कि आप अपने आप को दोहराने के लिए नहीं करना चाहती है, अपने स्वयं के मॉड्यूल में बिल्डर रखा, और यह रजिस्टर के साथ register_treebuilders_from() ताकि इसे प्राथमिकता दी जा सके।

+0

हालांकि यह काम करता है, मुझे नफरत है कि मेरे आईडीई (पायचॉन प्लगइन के साथ पीईचर्म और इंटेलिजे आईडीईए) 'bs4.builder' आयात के बारे में शिकायत करते हैं। वे कहते हैं, "अनसुलझा संदर्भ 'HTMLParserTreeBuilder'" और जब मैं इसके लिए पूछता हूं तो यह इसके लिए घोषणा पर कूद नहीं सकता है। क्या अन्य आईडीई इस बारे में बेहतर हैं? –

2

वर्ग HTMLParserTreeBuilder वास्तव में upper module_init__.py पर घोषित किया जाता है, तो निजी submodule से सीधे आयात करने की कोई जरूरत नहीं है। यही कारण है कि कहा कि मैं यह निम्नलिखित तरीके से करना होगा:

import re 

from bs4 import BeautifulSoup 
from bs4.builder import HTMLParserTreeBuilder 

bb = HTMLParserTreeBuilder() 
bb.cdata_list_attributes["*"].remove("class") 

soup = BeautifulSoup(bs, "html.parser", builder=bb) 
found_elements = soup.find_all(class_=re.compile(r"^name\-single name\d+$")) 
print found_elements 

यह मूल रूप से (शायद थोड़ा और स्पष्ट) ओपी में के रूप में वर्ग को परिभाषित करने के रूप में ही है, लेकिन मुझे नहीं लगता कि करने के लिए एक बेहतर तरीका है कर दो।

संबंधित मुद्दे