Проблема Unicode с парсером Python

Некоторое время я писал плохой Perl, но вместо этого пытаюсь научиться писать плохой Python. Я прочитал о проблеме, с которой я столкнулся уже пару дней (и в результате знаю гораздо больше о юникоде), но у меня все еще возникают проблемы с мошенническим тире в следующем коде:

import urllib2

def scrape(url):
# simplified
    data = urllib2.urlopen(url)
    return data.read()

def query_graph_api(url_list):
# query Facebook's Graph API, store data.
    for url in url_list:
        graph_query = graph_query_root + "%22" + url + "%22"
        query_data = scrape(graph_query)
        print query_data #debug console

### START HERE ####

graph_query_root = "https://graph.facebook.com/fql?q=SELECT%20normalized_url,share_count,like_count,comment_count,total_count%20FROM%20link_stat%20WHERE%20url="

url_list = ['http://www.supersavvyme.co.uk',  'http://www.supersavvyme.co.uk/article/how-to-be-happy–laugh-more']

query_graph_api(url_list)

(Это сильно упрощенное представление парсера, кстати. Оригинал использует sitemap.xml сайта для создания списка URL-адресов, а затем запрашивает Graph API Facebook для получения информации о каждом — вот исходный парсер)

Мои попытки отладить это в основном состояли из попытки подражать бесконечным обезьянам, переписывающим Шекспира. Мой обычный метод (поиск сообщения об ошибке в StackOverflow, копирование и вставка решения) не удался.

Вопрос: как закодировать данные, чтобы расширенные символы, такие как тире во втором URL, не нарушали мой код, но продолжали работать в FQL-запросе?

P.S. Мне даже интересно, правильно ли я задаю вопрос: может ли urllib.urlencode помочь мне здесь (конечно, это graph_query_root будет проще и красивее в создании...

---8<----

Трассировка, которую я получаю от фактического скребка на ScraperWiki, выглядит следующим образом:

http://www.supersavvyme.co.uk/article/how-to-be-happy–laugh-more
Line 80 - query_graph_api(urls)
Line 53 - query_data = scrape(graph_query) -- query_graph_api((urls=['http://www.supersavvyme.co.uk', 'http://...more
Line 21 - data = urllib2.urlopen(unicode(url)) -- scrape((url=u'https://graph.facebook.com/fql?q=SELECT%20url,...more
/usr/lib/python2.7/urllib2.py:126 -- urlopen((url=u'https://graph.facebook.com/fql?q=SELECT%20url,no...more
UnicodeEncodeError: 'ascii' codec can't encode character u'\u2013' in position 177: ordinal not in range(128)

person mediaczar    schedule 28.04.2013    source источник
comment
Можете ли вы включить точный вопрос в свой ...вопрос?   -  person Armin Rigo    schedule 28.04.2013
comment
Не могли бы вы опубликовать трассировку?   -  person MikeHunter    schedule 28.04.2013


Ответы (1)


Если вы используете Python 3.x, все, что вам нужно сделать, это добавить одну строку и изменить другую:

gq = graph_query.encode('utf-8')
query_data = scrape(gq)

Если вы используете Python 2.x, сначала поместите следующую строку вверху файла модуля:

# -*- coding: utf-8 -*- (прочитайте, для чего это здесь)

а затем сделайте все ваши строковые литералы юникодными и кодируйте непосредственно перед переходом к urlopen:

def scrape(url):
# simplified
    data = urllib2.urlopen(url)
    return data.read()

def query_graph_api(url_list):
# query Facebook's Graph API, store data.
    for url in url_list:
        graph_query = graph_query_root + u"%22" + url + u"%22"
        gq = graph_query.encode('utf-8')
        query_data = scrape(gq)
        print query_data #debug console

### START HERE ####

graph_query_root = u"https://graph.facebook.com/fql?q=SELECT%20normalized_url,share_count,like_count,comment_count,total_count%20FROM%20link_stat%20WHERE%20url="

url_list = [u'http://www.supersavvyme.co.uk', u'http://www.supersavvyme.co.uk/article/how-to-be-happy–laugh-more']

query_graph_api(url_list)

Судя по коду, вы используете версию 3.x, которая действительно лучше подходит для таких вещей. Но вам все равно придется кодировать, когда это необходимо. В 2.x лучший совет - делать то, что 3.x делает по умолчанию: использовать unicode во всем коде и кодировать только тогда, когда требуются байты.

person MikeHunter    schedule 28.04.2013