lxml.html и Unicode: извлечение ссылок - PullRequest
0 голосов
/ 22 марта 2012

Приведенный ниже код извлекает ссылки с веб-страницы и показывает их в браузере.С большим количеством страниц в кодировке UTF-8 это прекрасно работает.Но страница французской Википедии http://fr.wikipedia.org/wiki/États_unis, например, выдает ошибку.

# -*- coding: utf-8 -*-

print 'Content-Type: text/html; charset=utf-8\n'
print '''<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>Show Links</title>
</head>
<body>'''

import urllib2, lxml.html as lh

def load_page(url):
    headers = {'User-Agent' : 'Mozilla/5.0 (compatible; testbot/0.1)'}
    try:
        req = urllib2.Request(url, None, headers)
        response = urllib2.urlopen(req)
        page = response.read()
        return page
    except:
        print '<b>Couldn\'t load:', url, '</b><br>'
        return None

def show_links(page):
    tree = lh.fromstring(page)
    for node in tree.xpath('//a'):
        if 'href' in node.attrib:
            url = node.attrib['href']
            if '#' in url:
                url=url.split('#')[0]
            if '@' not in url and 'javascript' not in url:
                if node.text:
                    linktext = node.text
                else:
                    linktext = '-'
                print '<a href="%s">%s</a><br>' % (url, linktext.encode('utf-8'))

page = load_page('http://fr.wikipedia.org/wiki/%C3%89tats_unis')
show_links(page)

print '''
</body>
</html>
'''

Я получаю следующую ошибку:

Traceback (most recent call last):
  File "C:\***\question.py", line 42, in <module>
    show_links(page)
  File "C:\***\question.py", line 39, in show_links
    print '<a href="%s">%s</a><br>' % (url, linktext.encode('utf-8'))
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 3: ordinal not in range(128)

Моя система: Python 2.6 (Windows),lxml 2.3.3, Apache Server (для отображения результатов)

Что я делаю не так?

Ответы [ 2 ]

2 голосов
/ 23 марта 2012

Вам также необходимо кодировать url.

Проблема может быть похожа на:

>>> "%s%s" % (u"", "€ <-non-ascii char in a bytestring")
Traceback (most recent call last):
  File "<input>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 0: ordinal not in
range(128)

Но это работает:

>>> "%s%s" % (u"".encode('utf-8'), "€ <-non-ascii char in a bytestring")
'\xe2\x82\xac <-non-ascii char in a bytestring'

Пустой UnicodeСтрока заставляет все выражение быть преобразованным в Unicode.Следовательно, вы видите Unicode Decode Error.

В общем случае смешивать Unicode и байтовые строки плохая идея.Может показаться, что он работает, но рано или поздно он сломается.Преобразуйте текст в Unicode, как только вы его получите, обработайте, а затем преобразуйте в байты для ввода / вывода.

1 голос
/ 23 марта 2012

lxml возвращает строки байтов, а не юникод.Возможно, было бы лучше decode для проверки байтов в unicode, используя любую кодировку, с которой была обслужена страница, перед кодированием как utf-8.

Если ваш текст уже в utf-8, нет необходимости выполнять какое-либо кодирование или декодирование - просто удалите эту операцию.

Однако, если ваш текст ссылки имеет тип unicode (как вы это говорите), то это Unicodeстрока (каждый элемент представляет кодовую точку Unicode), и кодирование в формате utf-8 должно работать на отлично.

Я подозреваю, что проблема в том, что ваша url строка также строка Unicode,и он также должен быть закодирован как utf-8, прежде чем подставляться в вашу строку байтов.

...