2011-08-28 17 views
23

मैं BeautifulSoup का उपयोग कर अजगर के साथ एक क्रॉलर लिख रहा हूँ, और सब कुछ सफलता से जा रहा था जब तक मैं इस साइट में भाग:अजगर और BeautifulSoup एन्कोडिंग मुद्दों

http://www.elnorte.ec/

मैं अनुरोध पुस्तकालय के साथ सामग्री हो रही है :

r = requests.get('http://www.elnorte.ec/') 
content = r.content 

यदि मैं उस बिंदु पर सामग्री चर का प्रिंट करता हूं, तो सभी स्पैनिश विशेष वर्ण ठीक काम कर रहे हैं। हालांकि, एक बार मैं BeautifulSoup को यह सब गड़बड़ हो जाता है सामग्री चर को खिलाने के लिए प्रयास करें:

soup = BeautifulSoup(content) 
print(soup) 
... 
<a class="blogCalendarToday" href="/component/blog_calendar/?year=2011&amp;month=08&amp;day=27&amp;modid=203" title="1009 artículos en este día"> 
... 

यह जाहिरा तौर पर सभी स्पेनिश विशेष वर्ण (लहजे और whatnot) ऊपर garbling है। मैंने content.decode ('utf-8') करने की कोशिश की है, content.decode ('latin-1'), ने सुंदर स्नूप पर एन्कोडिंग पैरामीटर के साथ गड़बड़ करने की भी कोशिश की है, इसे एन्कोडिंग = 'utf-8' से सेट करके और एन्कोडिंग से = 'लैटिन -1', लेकिन अभी भी कोई पासा नहीं है।

किसी भी पॉइंटर्स की बहुत सराहना की जाएगी।

उत्तर

17

आप की कोशिश कर सकते:

r = urllib.urlopen('http://www.elnorte.ec/') 
x = BeautifulSoup.BeautifulSoup(r.read) 
r.close() 

print x.prettify('latin-1') 

मैं सही उत्पादन मिलता है। ओह, इस विशेष मामले में आप x.__str__(encoding='latin1') भी कर सकते हैं।

मुझे लगता है कि यह सामग्री आईएसओ -885 9 -1 (5) में है और मेटा http-equiv सामग्री-प्रकार गलत तरीके से "यूटीएफ -8" कहता है।

क्या आप पुष्टि कर सकते हैं? ऐसा करने से आप किसी भी छोड़ दी जाएगी द्वारा

soup = BeautifulSoup.BeautifulSoup(content.decode('utf-8','ignore')) 

:

+0

हाय Gaikokujin, आपके उत्तर के लिए धन्यवाद के लिए काम करता है की कोशिश कर सकते हैं, कर रहे हैं। आप काफी सही हैं, अगर मैं इसे 'लैटिन -1' पैरामीटर से प्रसन्न करता हूं, तो मुझे स्ट्रिंग वापस सभी सही उच्चारण और सभी के साथ मिलती है। हालांकि, मुझे लिंक को संसाधित करने के लिए सूप के माध्यम से जाना होगा, और यदि मैं फिर से स्ट्रिंग से सूप बनाने की कोशिश करता हूं, तो यह फिर से उच्चारण को गड़बड़ कर देता है। – David

+0

दरअसल, कभी भी ध्यान न दें, अब मुझे आपके सुझाव का प्रयास करते समय एक त्रुटि मिल रही है: यूनिकोड एन्कोड त्रुटि: 'लैटिन -1' कोडेक स्थिति 62-63 में अक्षरों को एन्कोड नहीं कर सकता: क्रमशः श्रेणी में नहीं (256) – David

+0

ऐसा लगता है कि यह फिर से काम करता है अगर मैं करता हूं: x = BeautifulSoup.BeautifulSoup (r.read(), एन्कोडिंग = 'लैटिन -1' से), लेकिन फिर, अगर मैं प्रीटीफाइड स्ट्रिंग से नया सूप बनाने का प्रयास करता हूं, तो यह फिर से गड़बड़ करता है:/ – David

19

आपके मामले में यह पेज गलत utf-8 डेटा जो BeautifulSoup confuses और यह लगता है कि अपने पृष्ठ का उपयोग करता है windows-1252, तो आप इस चाल कर सकते हैं बनाता है पृष्ठ स्रोत और सुंदर सूप से गलत प्रतीक अतिथि एन्कोडिंग दाएं होंगे।

आप 'अनदेखा' को 'प्रतिस्थापित' से प्रतिस्थापित कर सकते हैं और '?' के लिए टेक्स्ट चेक कर सकते हैं यह देखने के लिए प्रतीकों को छोड़ दिया गया है।

दरअसल क्रॉलर लिखना बहुत मुश्किल काम है जो 100% मौका के साथ हर बार पेज एन्कोडिंग का अनुमान लगा सकता है (ब्राउज़र आजकल बहुत अच्छे हैं), आप 'चार्डेट' जैसे मॉड्यूल का उपयोग कर सकते हैं, उदाहरण के लिए, आपके मामले में यह आईएसओ -885 9 -2 के रूप में एन्कोडिंग अनुमान लगाएगा, जो भी सही नहीं है।

यदि आपको वास्तव में किसी भी पृष्ठ के लिए एन्कोडिंग प्राप्त करने में सक्षम होना आवश्यक है तो उपयोगकर्ता संभवतः आपूर्ति कर सकता है - आपको या तो बहु-स्तर बनाना चाहिए (utf-8 का प्रयास करें, लैटिन 1 आज़माएं, कोशिश करें आदि ...) पहचान फ़ंक्शन (जैसे हम हमारी परियोजना में किया था) या सी मॉड्यूल के रूप में फ़ायरफ़ॉक्स या क्रोमियम से कुछ पहचान कोड का उपयोग करें।

2

पहला उत्तर सही है, यह कार्य कुछ बार प्रभावशाली हैं।

def __if_number_get_string(number): 
     converted_str = number 
     if isinstance(number, int) or \ 
      isinstance(number, float): 
       converted_str = str(number) 
     return converted_str 


    def get_unicode(strOrUnicode, encoding='utf-8'): 
     strOrUnicode = __if_number_get_string(strOrUnicode) 
     if isinstance(strOrUnicode, unicode): 
      return strOrUnicode 
     return unicode(strOrUnicode, encoding, errors='ignore') 

    def get_string(strOrUnicode, encoding='utf-8'): 
     strOrUnicode = __if_number_get_string(strOrUnicode) 
     if isinstance(strOrUnicode, unicode): 
      return strOrUnicode.encode(encoding) 
     return strOrUnicode 
0

मैं एक और अधिक विधिवत मूर्ख सबूत दृष्टिकोण लेने का सुझाव दूंगा।

# 1. get the raw data 
raw = urllib.urlopen('http://www.elnorte.ec/').read() 

# 2. detect the encoding and convert to unicode 
content = toUnicode(raw) # see my caricature for toUnicode below 

# 3. pass unicode to beautiful soup. 
soup = BeautifulSoup(content) 


def toUnicode(s): 
    if type(s) is unicode: 
     return s 
    elif type(s) is str: 
     d = chardet.detect(s) 
     (cs, conf) = (d['encoding'], d['confidence']) 
     if conf > 0.80: 
      try: 
       return s.decode(cs, errors = 'replace') 
      except Exception as ex: 
       pass 
    # force and return only ascii subset 
    return unicode(''.join([ i if ord(i) < 128 else ' ' for i in s ])) 

आप इससे कोई फर्क नहीं पड़ता कि आप इस पर फेंकते हैं, यह हमेशा बीएस के लिए वैध यूनिकोड भेज देगा।

नतीजतन आपका पार्सड पेड़ बहुत बेहतर व्यवहार करेगा और हर बार आपके पास नया डेटा होने पर नए और दिलचस्प तरीकों से असफल नहीं होगा।

परीक्षण और त्रुटि कोड में काम नहीं करता है - अभी भी कई संयोजनों :-)

0

आप इस जो हर एन्कोडिंग

from bs4 import BeautifulSoup 
    from bs4.dammit import EncodingDetector 
    headers = {"User-Agent": USERAGENT} 
    resp = requests.get(url, headers=headers) 
    http_encoding = resp.encoding if 'charset' in resp.headers.get('content-type', '').lower() else None 
    html_encoding = EncodingDetector.find_declared_encoding(resp.content, is_html=True) 
    encoding = html_encoding or http_encoding 
    soup = BeautifulSoup(resp.content, 'lxml', from_encoding=encoding) 
संबंधित मुद्दे