2016-01-17 2 views
0

У меня есть простой скрипт Python, который вытягивает сообщения из reddit и публикует их в Twitter. К сожалению, сегодня у него начались проблемы, которые я предполагаю, из-за чьего-то звания на reddit, имеющего проблему форматирования. Ошибка, что я reciving является:Python-скрипт, получающий UnicodeEncodeError: кодек ascii не может кодировать символ

File "redditbot.py", line 82, in <module> 
    main() 
File "redditbot.py", line 64, in main 
tweeter(post_dict, post_ids) 
File "redditbot.py", line 74, in tweeter 
print post+" "+post_dict[post]+" #python" 
UnicodeEncodeError: 'ascii' codec can't encode character u'\u201c' in position 34: ordinal not in range(128) 

А вот мой сценарий:

# encoding=utf8 
import praw 
import json 
import requests 
import tweepy 
import time 
import urllib2 
import sys 
reload(sys) 
sys.setdefaultencoding('utf8') 

access_token = 'hidden' 
access_token_secret = 'hidden' 
consumer_key = 'hidden' 
consumer_secret = 'hidden' 


def strip_title(title): 
    if len(title) < 75: 
    return title 
else: 
    return title[:74] + "..." 

def tweet_creator(subreddit_info): 
post_dict = {} 
post_ids = [] 
print "[bot] Getting posts from Reddit" 
for submission in subreddit_info.get_hot(limit=2000): 
    post_dict[strip_title(submission.title)] = submission.url 
    post_ids.append(submission.id) 
print "[bot] Generating short link using goo.gl" 
mini_post_dict = {} 
for post in post_dict: 
    post_title = post 
    post_link = post_dict[post] 

    mini_post_dict[post_title] = post_link 
return mini_post_dict, post_ids 

def setup_connection_reddit(subreddit): 
print "[bot] setting up connection with Reddit" 
r = praw.Reddit('PythonReddit PyReTw' 
      'monitoring %s' %(subreddit)) 
subreddit = r.get_subreddit('python') 
return subreddit 



def duplicate_check(id): 
found = 0 
with open('posted_posts.txt', 'r') as file: 
    for line in file: 
     if id in line: 
      found = 1 
return found 

def add_id_to_file(id): 
with open('posted_posts.txt', 'a') as file: 
    file.write(str(id) + "\n") 

def main(): 
subreddit = setup_connection_reddit('python') 
post_dict, post_ids = tweet_creator(subreddit) 
tweeter(post_dict, post_ids) 

def tweeter(post_dict, post_ids): 
auth = tweepy.OAuthHandler(consumer_key, consumer_secret) 
auth.set_access_token(access_token, access_token_secret) 
api = tweepy.API(auth) 
for post, post_id in zip(post_dict, post_ids): 
    found = duplicate_check(post_id) 
    if found == 0: 
     print "[bot] Posting this link on twitter" 
     print post+" "+post_dict[post]+" #python" 
     api.update_status(post+" "+post_dict[post]+" #python") 
     add_id_to_file(post_id) 
     time.sleep(3000) 
    else: 
     print "[bot] Already posted" 

if __name__ == '__main__': 
main() 

Любая помощь будет очень высоко - спасибо заранее!

+1

Не могли бы вы фиксирующую отступа вашего примера? – karlson

+0

Вы можете найти эту статью полезной: [Pragmatic Unicode] (http://nedbatchelder.com/text/unipain.html), которая была написана ветеранкой SO Нед Батчелдер. –

ответ

1

Проблема может возникнуть из-за смешивания строк и юникодовых строк при конкатенации. В качестве альтернативы, предваряя все строковые литералы с u, может быть

from __future__ import unicode_literals 

исправляет вещи для вас. См. here для более глубокого объяснения и принятия решения о том, является ли это вариантом для вас или нет.

2

Вы пытаетесь напечатать строку юникода на своем терминале (или, возможно, файл с помощью перенаправления IO), но кодировка, используемая вашим терминалом (или файловой системой), является ASCII. Из-за этого Python пытается преобразовать его из представления unicode в ASCII, но сбой, поскольку код кода u'\u201c' () не может быть представлен в ASCII. Эффективно ваш код делает это:

>>> print u'\u201c'.encode('ascii') 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
UnicodeEncodeError: 'ascii' codec can't encode character u'\u201c' in position 0: ordinal not in range(128) 

Вы можете попробовать преобразовать в UTF-8:

print (post + " " + post_dict[post] + " #python").encode('utf8') 

или преобразовать в ASCII, как это:

print (post + " " + post_dict[post] + " #python").encode('ascii', 'replace') 

который заменит недопустимые символы ASCII с ?.

Другой способ, который полезен при печати для отладки, чтобы напечатать repr строки:

print repr(post + " " + post_dict[post] + " #python") 

который бы вывести что-то вроде этого:

>>> s = 'string with \u201cLEFT DOUBLE QUOTATION MARK\u201c' 
>>> print repr(s) 
u'string with \u201cLEFT DOUBLE QUOTATION MARK\u201c' 
3

Рассмотрим это простая программа:

print(u'\u201c' + "python") 

Если вы попробуете распечатать на терминале л (с соответствующей кодировкой символов), вы получите

“python 

Однако, если вы попытаетесь перенаправить вывод в файл, вы получите UnicodeEncodeError.

script.py > /tmp/out 
Traceback (most recent call last): 
    File "/home/unutbu/pybin/script.py", line 4, in <module> 
    print(u'\u201c' + "python") 
UnicodeEncodeError: 'ascii' codec can't encode character u'\u201c' in position 0: ordinal not in range(128) 

При печати на терминал Python использует кодировку символов терминала для кодирования unicode. (Клеммы могут печатать только байты, поэтому для печати нужно кодировать unicode.)

При перенаправлении вывода в файл Python не может определить кодировку символов, так как файлы не имеют объявленной кодировки.Поэтому по умолчанию Python2 неявно кодирует весь юникод с использованием кодировки ascii перед записью в файл. Поскольку u'\u201c' не может быть закодирован ascii, a UnicodeEncodeError. (Только первые 127 кодов Unicode могут быть закодированы с помощью ascii).

Эта проблема подробно объясняется в Why Print Fails wiki.

Чтобы устранить эту проблему, во избежание добавления строк unicode и байтов. Это вызывает неявное преобразование с использованием кодека ascii в Python2 и исключение в Python3. Для будущего вашего кода лучше быть явным. Например, кодирование post явно до форматирования и печати байты:

post = post.encode('utf-8') 
print('{} {} #python'.format(post, post_dict[post])) 
Смежные вопросы