سؤال

مشكلة

عند تجريف شاشة على صفحة ويب باستخدام Python One تعرف على ترميز الأحرف للصفحة. إذا حصلت على شخصية ترميز الخطأ، فسيتم افسالة إخراجك.

عادة ما يستخدم الناس بعض التقنية البدائية للكشف عن الترميز. إما استخدامهم Charset من الرأس أو المجذوف المحدد في علامة التعريف أو يستخدمون كاشف الترميز (الذي لا يهتم بعلامات التعريف أو رؤوسه). باستخدام هذه التقنيات واحدة فقط، في بعض الأحيان لن تحصل على نفس النتيجة كما تفعل في متصفح.

المتصفحات تفعل ذلك بهذه الطريقة:

  • علامات التعريف تأخذ دائما الأسبقية (أو تعريف XML)
  • يتم استخدام الترميز المحدد في الرأس عندما لا يكون هناك تجارب محددة في علامة التعريف
  • إذا لم يتم تعريف الترميز على الإطلاق، مما هو الوقت المناسب للكشف عن الترميز.

(حسنا ... على الأقل هذه هي الطريقة التي أعتقد أن معظم المتصفحات تفعل ذلك. وثائق شحيحة حقا.)

ما أبحث عنه هو مكتبة يمكن أن تقرر مجموعة الأحرف من الصفحة بالطريقة التي سيتم بها المتصفح. أنا متأكد من أنني لست أول من يحتاج إلى حل مناسب لهذه المشكلة.

المحلول (أنا لم أحاول ذلك بعد ...)

وفق وثائق حساء جميلة.

الحساء الجميل يحاول الترميزات التالية، من أجل الأولوية، لتحويل المستند إلى Unicode:

  • ترميز تقوم بمرور الوسيطة من منشئ الحساء.
  • ترميز تم اكتشافه في المستند نفسه: على سبيل المثال، في إعلان XML أو (لمستندات HTML) في علامة Meta HTTP-Equiv. إذا وجد الحساء الجميل هذا النوع من الترميز داخل المستند، فإنه يوزع المستند مرة أخرى من البداية ويعطي ترميز جديد. الاستثناء الوحيد هو إذا قمت بتحديد ترميز صريح، وأن ترميز يعمل بالفعل: ثم سوف يتجاهل أي ترميز يجد في المستند.
  • تم استنشاق الترميز من خلال النظر إلى البايت القليلة الأولى من الملف. إذا تم اكتشاف ترميز في هذه المرحلة، فسيكون ذلك أحد الترميزات UTF-* EBCDIC أو ASCII.
  • تم استنزاع الترميز بواسطة مكتبة Chardet، إذا كان لديك تثبيت.
  • UTF-8.
  • Windows-1252.
هل كانت مفيدة؟

المحلول

سأستخدم html5lib. لهذا.

نصائح أخرى

عند تنزيل ملف مع Urllib أو Urllib2، يمكنك معرفة ما إذا كان رأس Charset تم إرساله:

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

يمكنك استخدام BeautifulSoup لتحديد موقع عنصر التعريف في HTML:

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

إذا لم يتوفر أيا منهما، فإن المتصفحات عادة ما تعود إلى تكوين المستخدم، جنبا إلى جنب مع الكشف التلقائي. كما تقترح RAJAX، يمكنك استخدام وحدة Chardet. إذا كان لديك تكوين المستخدم المتاح لإخبارك أن الصفحة يجب أن تكون الصينية (قل)، فقد تكون قادرا على القيام بأفضل.

استخدم ال كاشف الترميز العالمي:

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

سيكون الخيار الآخر هو مجرد استخدام WGE:

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

يبدو أنك بحاجة إلى هجين من الإجابات المقدمة:

  1. جلب الصفحة باستخدام Urllib
  2. يجد <meta> العلامات باستخدام حساء جميل أو طريقة أخرى
  3. إذا لم يكن هناك علامات تابقة، تحقق من الرؤوس التي تم إرجاعها بواسطة Urllib
  4. إذا كان ذلك لا يزال لا يمنحك إجابة، فاستخدم كاشف الترميز العالمي.

أنا بصراحة لا أصدق أنك ستجد أي شيء أفضل من ذلك.

في الواقع إذا قرأت أبعد من الأسئلة الشائعة التي ترتبط بها في التعليقات على الإجابة الأخرى، فهذا ما يدعو مؤلف مكتبة مكتبة الكاشف.

إذا كنت تعتقد أن الأسئلة الشائعة، فهذا ما يفعله المتصفحات (كما هو مطلوب في سؤالك الأصلي) مثل الكاشف هو منفذ رمز استنشق Firefox.

يقوم Scriacy بتنزيل صفحة واكتشاف ترميز صحيح لذلك، على عكس الطلبات. اكتسان (URL). الكتيب أو Urlopen. للقيام بذلك تحاول اتباع قواعد تشبه المتصفح - هذا هو أفضل ما يمكن القيام به، لأن مالكي الموقع لديهم حافز لجعل مواقع الويب الخاصة بهم تعمل في متصفح. يحتاج الرملي إلى أخذ رؤوس HTTP، <meta> العلامات، علامات BOM والاختلافات في ترميز أسماء في الحساب.

التخمين القائم على المحتوى (Chardet، Unicodammit) من تلقاء نفسها ليس حل صحيح، لأنه قد يفشل؛ يجب أن تستخدم فقط كملاذ أخير عند الرؤوس أو <meta> أو علامات BOM غير متوفرة أو لا تقدم أي معلومات.

ليس لديك لاستخدام Scrapy للحصول على وظائف الكشف عن الترميز؛ يتم إطلاق سراحهم (من بين بعض الأشياء الأخرى) في مكتبة منفصلة تسمى W3LIB: https://github.com/scrapy/w3lib..

للحصول على ترميز الصفحة واستخدام جسم Unicode 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,
)

بدلا من محاولة الحصول على صفحة، فإن معرفة الإحسام الذي سيستخدمه المتصفح، فلماذا لا تستخدم متصفحا فقط لجلب الصفحة وتحقق من إذن يستخدمها ..

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

جمهورية الجميلة جرعة هذا مع Unicodedammit: Unicode، اللعنة

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top