Problèmes d'encodage Python et BeautifulSoup

j'écris un crawler avec Python en utilisant BeautifulSoup, et tout se passait à merveille jusqu'à ce que je tombe sur ce site:

http://www.elnorte.ec /

j'obtiens le contenu avec la bibliothèque des requêtes:

r = requests.get('http://www.elnorte.ec/')
content = r.content

si je fais une impression de la variable de contenu à ce point, tous les caractères spéciaux espagnols semblent fonctionner très bien. Cependant, une fois que j'ai essayé d'alimenter la variable de contenu à BeautifulSoup tout se foiré:

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

il est apparemment en train de brouiller tous les caractères spéciaux espagnols (accents et autres). J'ai essayé de faire du contenu.decode('utf-8'), le contenu.decode ('latin-1'), a également essayé de jouer avec le paramètre fromEncoding pour embellir le morceau, le mettant à fromEncoding=' utf-8'et fromEncoding=' latin-1', mais toujours pas de dés.

tout pointeur serait très apprécié.

23
demandé sur David 2011-08-28 10:18:10

5 réponses

pourriez-vous essayer:

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

print x.prettify('latin-1')

j'obtiens la bonne sortie. OH, dans ce cas particulier vous pouvez aussi x.__str__(encoding='latin1') .

je suppose que c'est parce que le contenu est dans ISO-8859-1(5) et le meta http-equiv content-type dit incorrectement"UTF-8".

pouvez-vous confirmer?

18
répondu Gaikokujin Kun 2011-08-28 17:38:45

dans votre cas, cette page a des données utf-8 erronées qui confond BeautifulSoup et lui fait penser que votre page utilise windows-1252, vous pouvez faire ce tour:

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

en faisant cela, vous écarterez tous les symboles erronés de la source de la page et BeautifulSoup devinera l'encodage correctement.

Vous pouvez remplacer "ignorer" par "remplacer" et vérifier le texte pour"?'symboles pour voir ce qui a été jeté.

en fait c'est un tâche très difficile d'écrire crawler qui peut deviner encodage page à chaque fois avec 100% chance (les navigateurs sont très bons à ce jour), vous pouvez utiliser des modules comme "chardet", mais, par exemple, dans votre cas, il va deviner encodage ISO-8859-2, ce qui n'est pas correct trop.

si vous avez vraiment besoin d'être en mesure d'obtenir l'encodage pour n'importe quel utilisateur de page peut éventuellement fournir - vous devriez soit construire un multi-niveau(essayer utf-8, essayer latin1, essayer etc...) fonction de détection(comme nous l'avons fait dans notre projet) ou utilisez un code de détection de firefox ou de chrome comme module C.

21
répondu Riz 2018-04-03 07:03:14

la première réponse est juste, ces fonctions sont parfois efficaces.

    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
2
répondu Tabares 2012-07-03 15:51:11

je suggère une approche plus méthodique.

# 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 ]))

vous pouvez raisonner peu importe ce que vous lancez à ceci, il enverra toujours unicode valide à bs.

comme résultat votre arbre analysé se comportera beaucoup mieux et ne manquera pas de nouvelles façons plus intéressantes chaque fois que vous avez de nouvelles données.

Essai et Erreur ne fonctionne pas dans le Code - Il y a trop de combinaisons :-)

2
répondu vpathak 2016-12-03 12:47:02

vous pouvez essayer ceci, qui fonctionne pour chaque encodage

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)
1
répondu Shawn 2018-06-29 09:15:25