Python和BeautifulSoup编码问题

Dav*_*vid 25 python unicode beautifulsoup utf-8

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

http://www.elnorte.ec/

我正在获取请求库的内容:

r = requests.get('http://www.elnorte.ec/')
content = r.content
Run Code Online (Sandbox Code Playgroud)

如果我在那时打印内容变量,所有西班牙语特殊字符似乎都正常工作.但是,一旦我尝试将内容变量提供给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">
...
Run Code Online (Sandbox Code Playgroud)

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

任何指针都将非常感激.

Riz*_*Riz 25

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

soup = BeautifulSoup.BeautifulSoup(content.decode('utf-8','ignore'))
Run Code Online (Sandbox Code Playgroud)

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

你可以用'替换'替换'ignore'并检查'?'的文本 符号,看看什么被丢弃.

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

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


小智 19

你能尝试一下:

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

print x.prettify('latin-1')
Run Code Online (Sandbox Code Playgroud)

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

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

你能证实吗?

  • 最后得到它,只需要:soup = BeautifulSoup(内容,fromEncoding ='latin-1')然后当它有时间解析链接时:i_title = item.contents [0] .encode('latin-1').解码('utf-8')似乎可以解决问题.谢谢你的帮助 :) (2认同)

Sha*_*awn 6

您可以尝试一下,它适用于每种编码

from bs4 import BeautifulSoup
from bs4.dammit import EncodingDetector
headers = {"User-Agent": USERAGENT}
resp = requests.get(url, headers=headers)
http_encoding = resp.encoding if 'charset' in resp.headers.get('content-type', '').lower() else None
html_encoding = EncodingDetector.find_declared_encoding(resp.content, is_html=True)
encoding = html_encoding or http_encoding
soup = BeautifulSoup(resp.content, 'lxml', from_encoding=encoding)
Run Code Online (Sandbox Code Playgroud)

  • 很好的答案,但我会删除“headers”(并不是真正需要的,并且由于您没有定义“USERAGENT”,因此不能盲目地复制粘贴代码)。 (2认同)

vpa*_*hak 5

我建议采取更有条理的万无一失的方法。

# 1. get the raw data 
raw = urllib.urlopen('http://www.elnorte.ec/').read()

# 2. detect the encoding and convert to unicode 
content = toUnicode(raw)    # see my caricature for toUnicode below

# 3. pass unicode to beautiful soup. 
soup = BeautifulSoup(content)


def toUnicode(s):
    if type(s) is unicode:
        return s
    elif type(s) is str:
        d = chardet.detect(s)
        (cs, conf) = (d['encoding'], d['confidence'])
        if conf > 0.80:
            try:
                return s.decode( cs, errors = 'replace' )
            except Exception as ex:
                pass 
    # force and return only ascii subset
    return unicode(''.join( [ i if ord(i) < 128 else ' ' for i in s ]))
Run Code Online (Sandbox Code Playgroud)

你可以推断,无论你抛出什么,它总是会向 bs 发送有效的 unicode。

因此,每次获得新数据时,解析树都会表现得更好,并且不会以更新、更有趣的方式失败。

尝试和错误在代码中不起作用 - 组合太多了:-)