如何在python中下载任何(!)网页和正确的字符集?

Tar*_*mán 34 python screen-scraping urllib urllib2 character-encoding

问题

当使用python对网页进行屏幕抓取时,必须知道页面的字符编码.如果你得到的字符编码错误,你的输出就会搞砸了.

人们通常使用一些基本技术来检测编码.它们使用标题中的字符集或元标记中定义的字符集,或者使用编码检测器(不关心元标记或标题).通过仅使用这些技术,有时您将无法获得与浏览器相同的结果.

浏览器这样做:

  • 元标记始终优先(或xml定义)
  • 当元标记中没有定义字符集时,将使用标头中定义的编码
  • 如果根本没有定义编码,那么就是编码检测的时间.

(嗯......至少这是我认为大多数浏览器都这样做的方式.文档非常缺乏.)

我正在寻找的是一个可以像浏览器一样决定页面字符集的库.我确信我不是第一个需要妥善解决这个问题的人.

解决方案(我还没试过......)

根据Beautiful Soup的文档.

美丽的汤按优先级顺序尝试以下编码,将您的文档转换为Unicode:

  • 作为fromEncoding参数传递给汤构造函数的编码.
  • 在文档本身中发现的编码:例如,在XML声明中或(对于HTML文档)的http-equiv META标记.如果Beautiful Soup在文档中找到这种编码,它会从头开始再次解析文档并尝试新编码.唯一的例外是如果您明确指定了编码,并且该编码实际上有效:那么它将忽略它在文档中找到的任何编码.
  • 通过查看文件的前几个字节来嗅探编码.如果在此阶段检测到编码,则它将是UTF-*编码,EBCDIC或ASCII之一.
  • 如果安装了chardet库,则会对其进行嗅探.
  • UTF-8
  • Windows的1252

Mar*_*wis 37

当您使用urllib或urllib2下载文件时,您可以找出是否传输了字符集标头:

fp = urllib2.urlopen(request)
charset = fp.headers.getparam('charset')
Run Code Online (Sandbox Code Playgroud)

您可以使用BeautifulSoup在HTML中查找元素:

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

如果两者都不可用,浏览器通常会回退到用户配置,并结合自动检测.正如rajax建议的那样,你可以使用chardet模块.如果您有可用的用户配置,告诉您该页面应该是中文(例如),您可以做得更好.

  • @ kaizer.se:对; 它是3.x中的`get_param`(但是,它也是urllib.request) (5认同)

raj*_*jax 14

使用通用编码检测器:

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

另一个选择就是使用wget:

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

  • 好吧,我恐怕没有银弹 - 所以自己写吧.:) (2认同)
  • @Kalmi:你链接到chardet faq; 不到10行,他链接到feedparser,它做你想要的:http://code.google.com/p/feedparser/source/browse/trunk/feedparser/feedparser.py#3133(当然,他只处理xml文件,但你需要90%的机器在那里...) (2认同)

Tob*_*obu 3

我会为此使用html5lib 。

  • 这看起来真的很好。有关如何进行编码发现的文档:http://html5lib.readthedocs.org/en/latest/movingparts.html#encoding-discovery (2认同)