문제

문제

Python One을 사용하여 웹 페이지를 사용하여 화면 스크래프를 할 때는 페이지의 문자 인코딩을 알아야합니다. 캐릭터가 출력보다 잘못 인코딩을 받으면 엉망이됩니다.

사람들은 일반적으로 인코딩을 감지하기 위해 기초 기술을 사용합니다. 그들은 헤더의 숯을 사용하거나 메타 태그에 정의 된 숯불을 사용하거나 인코딩 검출기 (메타 태그 또는 헤더에 관심이 없습니다). 이 기술을 하나만 사용하면 때로는 브라우저에서와 동일한 결과를 얻지 못합니다.

브라우저는 다음과 같은 방식으로 수행합니다.

  • 메타 태그는 항상 우선 순위 (또는 XML 정의)를 취합니다.
  • 헤더에 정의 된 인코딩은 메타 태그에 정의 된 숯이없는 경우 사용됩니다.
  • 인코딩이 전혀 정의되지 않은 경우 검출을 인코딩 할 시간입니다.

(글쎄 ... 적어도 그것은 대부분의 브라우저가 그렇게한다고 믿는 방식입니다. 문서화는 정말 부족합니다.)

내가 찾고있는 것은 브라우저와 같은 페이지의 캐릭터 세트를 결정할 수있는 라이브러리입니다. 나는이 문제에 대한 적절한 해결책이 필요한 최초의 사람이 아니라고 확신합니다.

해결책 (아직 시도하지 않았습니다 ...)

에 따르면 아름다운 수프의 문서.

Beautiful Soup은 우선 순위로 다음 인코딩을 시도합니다. 문서를 유니 코드로 전환합니다.

  • 인코딩은 수프 생성자에 대한 인코딩 인수로 전달됩니다.
  • 문서 자체에서 발견 된 인코딩 : 예를 들어, XML 선언 또는 HTML 문서의 경우) 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}

다른 옵션은 wget을 사용하는 것입니다.

  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. 여전히 답을주지 않으면 범용 인코딩 탐지기를 사용하십시오.

솔직히 당신이 그보다 더 좋은 것을 찾을 것이라고 믿지 않습니다.

실제로 다른 답변에 대한 의견에 연결된 FAQ를 더 읽으면 Detector Library의 저자가 옹호하는 것입니다.

FAQ를 믿는다면, 검출기는 Firefox 스니핑 코드의 포트이기 때문에 브라우저가 원래 질문에서 요청한대로 브라우저가하는 일입니다.

스크랩은 요청 (url) .text 또는 urlopen과 달리 페이지를 다운로드하고 올바른 인코딩을 감지합니다. 그렇게하려면 브라우저와 같은 규칙을 따르려고 시도합니다. 웹 사이트 소유자가 웹 사이트를 브라우저에서 작동시킬 인센티브가 있기 때문에 이것은 최선의 규칙입니다. 스크랩은 HTTP 헤더를 가져 가야합니다. <meta> 태그, BOM 마크 및 인코딩 이름의 차이점.

내용 기반 추측 (Chardet, UnicodedAmmit) 자체는 실패 할 수 있으므로 올바른 솔루션이 아닙니다. 헤더 또는 <meta> 또는 BOM 마크를 사용할 수 없거나 정보를 제공하지 않습니다.

인코딩 탐지 기능을 얻기 위해 스크레이프를 사용할 필요는 없습니다. 그들은 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,
)

페이지를 가져 오려고 시도한 다음 브라우저가 사용하는 숯불을 알아내는 대신 브라우저를 사용하여 페이지를 가져 와서 사용하는 charset을 확인하십시오.

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

BeautifulSoup이 이것을 unicodedammit으로 복용합니다. 유니 코드, 젠장

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top