2009-09-30 11 views
32

समस्या

जब पाइथन का उपयोग करके किसी वेबपृष्ठ को स्क्रीन स्क्रैप करना पृष्ठ के चरित्र एन्कोडिंग को जानना होता है। यदि आपको अपने आउटपुट से गलत वर्ण एन्कोडिंग मिलती है तो उसे गड़बड़ कर दिया जाएगा।पाइथन में सही वर्णमाला के साथ किसी भी (!) वेबपृष्ठ को कैसे डाउनलोड करें?

लोग आमतौर पर एन्कोडिंग का पता लगाने के लिए कुछ प्राथमिक तकनीक का उपयोग करते हैं। वे या तो मेटा टैग में परिभाषित हेडर या वर्णमाला से वर्णमाला का उपयोग करते हैं या वे encoding detector (जो मेटा टैग या शीर्षलेखों की परवाह नहीं करते हैं) का उपयोग करते हैं। केवल इन तकनीकों का उपयोग करके, कभी-कभी आपको एक ही परिणाम नहीं मिलेगा जैसा आप ब्राउज़र में करेंगे।

ब्राउज़र्स यह इस तरह से कार्य करें:

  • मेटा टैग हमेशा प्राथमिकता दी जाएगी (या एक्सएमएल परिभाषा)
  • एन्कोडिंग हेडर में निर्धारित लेता है प्रयोग किया जाता है, जब कोई चारसेट एक मेटा टैग में परिभाषित किया गया है
  • हैं एन्कोडिंग को परिभाषित करने के लिए समय की तुलना में एन्कोडिंग बिल्कुल परिभाषित नहीं है।

(ठीक है ... कम से कम इस तरह मेरा मानना ​​है कि अधिकांश ब्राउज़र यह करना है। प्रलेखन वास्तव में दुर्लभ है।)

क्या मैं के लिए देख रहा हूँ एक पुस्तकालय है कि वर्ण सेट का फैसला कर सकते है एक पृष्ठ के रूप में एक ब्राउज़र होगा। मुझे यकीन है कि मैं पहले व्यक्ति नहीं हूं जिसकी इस समस्या के लिए उचित समाधान की आवश्यकता है।

समाधान (मैं इसे अभी तक प्रयास नहीं किया है ...)

Beautiful Soup's documentation के अनुसार

ब्यूटीफुल सूप निम्नलिखित एन्कोडिंग की कोशिश करता है, प्राथमिकता के क्रम में, यूनिकोड में अपने दस्तावेज़ चालू करने के लिए:

  • एक एन्कोडिंग आप सूप निर्माता को fromEncoding तर्क के रूप में में गुजरती हैं।
  • दस्तावेज़ में स्वयं एक एन्कोडिंग खोजा गया: उदाहरण के लिए, एक्सएमएल घोषणा में या (एचटीएमएल दस्तावेजों के लिए) एक http-equiv मेटा टैग में। यदि सुंदर सूप दस्तावेज़ के भीतर इस तरह के एन्कोडिंग को पाता है, तो यह दस्तावेज़ को शुरुआत से फिर से विश्लेषण करता है और नई एन्कोडिंग को आज़माता है। एकमात्र अपवाद यह है कि यदि आपने स्पष्ट रूप से एन्कोडिंग निर्दिष्ट किया है, और वह एन्कोडिंग वास्तव में काम करती है: तो यह दस्तावेज़ में पाई गई किसी भी एन्कोडिंग को अनदेखा कर देगी।
  • फ़ाइल के पहले कुछ बाइट्स को देखकर एक एन्कोडिंग स्नीफ किया गया। यदि इस चरण में एक एन्कोडिंग पता चला है, तो यह यूटीएफ- * एन्कोडिंग, ईबीसीडीआईसी, या ASCII में से एक होगा।
  • एन्कोडिंग chardet लाइब्रेरी द्वारा स्नीफ किया गया है, यदि आपने इसे इंस्टॉल किया है।
  • UTF-8
  • विंडोज-1252
+4

आप डाउनलोड नहीं कर सकते "किसी भी" पृष्ठ। जब ब्राउज़र सही वर्णमाला निर्दिष्ट नहीं होता है, तो ब्राउज़र हर समय गलत लगता है। मैं दैनिक आधार पर गलत अनुमानों को ठीक करने के लिए एफएफ में दृश्य-> एन्कोडिंग मेनू का उपयोग करता हूं। आप जितना भी कर सकते हैं उतना करना चाहते हैं, लेकिन हर पृष्ठ को सही तरीके से अनुमान लगाने पर छोड़ दें। –

+7

अनुमान लगाने वाले चरित्र सेट बुरा है और हमें इस गड़बड़ी में पहली जगह मिला है। यदि ब्राउज़र ने कभी अनुमान लगाने का प्रयास नहीं किया था, तो डेवलपर्स को HTTP शीर्षलेखों के बारे में जानने के लिए मजबूर होना होगा और हमेशा एन्कोडिंग को सही तरीके से निर्दिष्ट करना होगा। अनुमान लगाना मतलब है कि आप इसे गलत मानने जा रहे हैं –

+0

gnibbler, अनुमान एक अंतिम उपाय –

उत्तर

3

मैं इसके लिए html5lib का प्रयोग करेंगे।

+2

यह वास्तव में अच्छा लगता है। इसके एन्कोडिंग डिस्कवरी के बारे में दस्तावेज़ीकरण: http: //html5lib.readthedocs। –

14

उपयोग Universal Encoding Detector:

>>> import chardet 
>>> chardet.detect(urlread("http://google.cn/")) 
{'encoding': 'GB2312', 'confidence': 0.99} 

अन्य विकल्प बस का उपयोग करने के होगा wget:

import os 
    h = os.popen('wget -q -O foo1.txt http://foo.html') 
    h.close() 
    s = open('foo1.txt').read() 
+0

यह कभी भी विफल नहीं होता है क्योंकि यह कभी-कभी विफल रहता है। यह भी देखें: http://chardet.feedparser.org/docs/faq.html#faq.yippie –

+0

इस दृष्टिकोण है कि आप पृष्ठ की स्पष्ट रूप से निर्दिष्ट वर्ण एन्कोडिंग की अनदेखी के साथ मुख्य समस्या (यिप्पी!)। –

+2

ठीक है, तो यहाँ एक चांदी की बुलेट नहीं है मुझे डर है - तो इसे स्वयं लिखो। :) – rajax

36

जब आप डाउनलोड एक urllib या urllib2 के साथ फ़ाइल करें, आप यह पता लगा सकते हैं कि एक वर्णमाला शीर्षलेख प्रेषित किया गया था:

fp = urllib2.urlopen(request) 
charset = fp.headers.getparam('charset') 

आप HTML में एक मेटा तत्व का पता लगाने का BeautifulSoup उपयोग कर सकते हैं:

soup = BeatifulSoup.BeautifulSoup(data) 
meta = soup.findAll('meta', {'http-equiv':lambda v:v.lower()=='content-type'}) 

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

+0

मुझे लगता है कि यह है 'getparam' – u0b34a0f6ae

+5

@ kaizer.se: ठीक है, यह '3.x में get_param' है (लेकिन फिर, यह भी urllib.request है) –

+0

दुर्भाग्य से (कम से कम अजगर में 2.7) urllib2 बाहर चारसेट Content-Type हैडर से, पार्स नहीं करता है तो आप की तरह कुछ करने की आवश्यकता होगी http://stackoverflow.com/a/1020931/69707 –

1
बजाय एक पेज तो पाने के लिए चारसेट ब्राउज़र का प्रयोग करेंगे, क्यों नहीं बस पृष्ठ लाने और जाँच क्या शब्दसमुच्चय इसे इस्तेमाल करता है करने के लिए एक ब्राउज़र का उपयोग पता लगाना कोशिश कर के

..

from win32com.client import DispatchWithEvents 
import threading 


stopEvent=threading.Event() 

class EventHandler(object): 
    def OnDownloadBegin(self): 
     pass 

def waitUntilReady(ie): 
    """ 
    copypasted from 
    http://mail.python.org/pipermail/python-win32/2004-June/002040.html 
    """ 
    if ie.ReadyState!=4: 
     while 1: 
      print "waiting" 
      pythoncom.PumpWaitingMessages() 
      stopEvent.wait(.2) 
      if stopEvent.isSet() or ie.ReadyState==4: 
       stopEvent.clear() 
       break; 

ie = DispatchWithEvents("InternetExplorer.Application", EventHandler) 
ie.Visible = 0 
ie.Navigate('http://kskky.info') 
waitUntilReady(ie) 
d = ie.Document 
print d.CharSet 
+0

ने इसे origo.hu पर अभी परीक्षण किया है और यह अविश्वसनीय रूप से धीमे होने के बावजूद काम करता है - शायद – Ravi

3

यह आप की तरह लगता है प्रस्तुत जवाब में से एक संकर की जरूरत है:

  1. urllib का उपयोग कर पृष्ठ लायें सुंदर सूप या अन्य विधि का उपयोग कर <meta> टैग ढूंढें
  2. कोई मेटा टैग मौजूद हैं, तो हेडर urllib
  3. द्वारा लौटाए गए चेक करते हैं कि अभी भी आप एक जवाब नहीं दे करता है, सार्वभौमिक एन्कोडिंग डिटेक्टर का उपयोग करें।

मैं ईमानदारी से विश्वास नहीं करता कि आप उससे बेहतर कुछ भी ढूंढने जा रहे हैं।

तथ्य यदि आप पूछे जाने वाले प्रश्न आप अन्य जवाब पर टिप्पणी में से जुड़ा हुआ में आगे पढ़ने में, कि क्या डिटेक्टर पुस्तकालय अधिवक्ताओं के लेखक।

आप पूछे जाने वाले प्रश्न विश्वास करते हैं, यह है कि क्या अन्य ब्राउज़रों (के रूप में अपने मूल प्रश्न में अनुरोध) के रूप में डिटेक्टर फ़ायरफ़ॉक्स सूँघने कोड का एक बंदरगाह है। UnicodeDammit साथ

+0

के बजाय फ़ायरफ़ॉक्स सक्रियक्स घटक के साथ प्रयास करें मुझे यह पता चलता है कि इसके लिए कोई मौजूदा लाइब्रेरी/स्निपेट नहीं है। –

+0

स्टोबर ने feedparser.py के अस्तित्व की ओर इशारा किया (जो दुर्भाग्यवश केवल एक्सएमएल के लिए है), लेकिन इसमें मेरी अधिकांश चीजें हैं। –

+0

एल्गोरिदम सही नहीं है, क्योंकि HTTP शीर्षलेखों को मेटा टैग पर प्राथमिकता लेनी चाहिए। यह बीओएम अंक और एन्कोडिंग सामान्यीकरण चरण को भी याद करता है (एचटीएमएल/एचटीटीपी में एन्कोडिंग नाम पाइथन द्वारा प्रदान किए गए नामों के समान नहीं हैं)। –

2

Scrapy एक पेज डाउनलोड करता है और इसके लिए एक सही एन्कोडिंग का पता लगाता है, के विपरीत requests.get (यूआरएल) .text या urlopen। ऐसा करने के लिए यह ब्राउज़र-जैसे नियमों का पालन करने का प्रयास करता है - यह सबसे अच्छा है जो कर सकता है, क्योंकि वेबसाइट मालिकों को अपनी वेबसाइटों को ब्राउज़र में काम करने के लिए प्रोत्साहित किया जाता है। स्केच को HTTP शीर्षलेख, <meta> टैग, बीओएम अंक और खाते में एन्कोडिंग नामों में अंतर लेने की आवश्यकता है।

सामग्री-आधारित अनुमान (चार्डेट, यूनिकोडडैमिट) अपने आप पर एक सही समाधान नहीं है, क्योंकि यह असफल हो सकता है; इसे केवल अंतिम उपाय के रूप में उपयोग किया जाना चाहिए जब शीर्षलेख या <meta> या बीओएम अंक उपलब्ध नहीं हैं या कोई जानकारी प्रदान नहीं करते हैं।

आपको एन्कोडिंग पहचान कार्यों को प्राप्त करने के लिए स्केपर का उपयोग करने की आवश्यकता नहीं है; वे w3lib नामक एक अलग पुस्तकालय में (कुछ अन्य सामानों के साथ) जारी किए जाते हैं: https://github.com/scrapy/w3lib

प्राप्त करने के लिए पेज एन्कोडिंग और यूनिकोड शरीर का उपयोग w3lib.encoding.html_to_unicode समारोह, एक सामग्री आधारित फ़ॉलबैक अनुमान लगा साथ: एक सही अक्षरों के समूह के साथ

import chardet 
from w3lib.encoding import html_to_unicode 

def _guess_encoding(data): 
    return chardet.detect(data).get('encoding') 

detected_encoding, html_content_unicode = html_to_unicode(
    content_type_header, 
    html_content_bytes, 
    default_encoding='utf8', 
    auto_detect_fun=_guess_encoding, 
) 
संबंधित मुद्दे