Python和BeautifulSoup编码问题

时间:2011-08-28 06:18:10

标签: python unicode utf-8 beautifulsoup

我正在使用BeautifulSoup编写一个Python爬虫,一切都在游泳,直到我遇到这个网站:

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">
...

它显然是在拼乱所有西班牙语的特殊角色(口音和诸如此类的东西)。我尝试过做content.decode('utf-8'),content.decode('latin-1'),也尝试将fromEncoding参数搞砸到BeautifulSoup,将其设置为fromEncoding ='utf-8'和fromEncoding ='拉丁-1',但仍然没有骰子。

任何指针都会非常感激。

3 个答案:

答案 0 :(得分:23)

在你的情况下,这个页面有错误的utf-8数据混淆了BeautifulSoup并让它认为你的页面使用了windows-1252,你可以做到这一点:

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

通过执行此操作,您将丢弃页面源中的任何错误符号,BeautifulSoup将正确猜测编码。

你可以用'replace'替换'ignore'并检查'?'的文字符号,以查看丢弃的内容。

实际上编写一个非常困难的任务,每次都可以100%的几率猜测页面编码(浏览器现在非常擅长),你可以使用像'chardet'这样的模块,但是,例如,在你的情况下它将猜测编码为ISO-8859-2,这也是不正确的。

如果你真的需要能够获得用户可能提供的任何页面的编码 - 你应该建立一个多级别(尝试utf-8,尝试latin1,尝试等...)检测功能(就像我们做的那样)在我们的项目中)或使用firefox或chromium的一些检测代码作为C模块。

答案 1 :(得分:18)

你可以尝试一下:

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

print x.prettify('latin-1')

我得到了正确的输出。 哦,在这种特殊情况下你也可以x.__str__(encoding='latin1')

我想这是因为内容在ISO-8859-1(5)中,并且元http-equiv内容类型错误地说“UTF-8”。

你能证实吗?

答案 2 :(得分: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