2012-02-06 1 views
15

RSS 피드를 feedparser로 구문 분석하고 SQLAlchemy를 사용하여 mySQL 테이블에 삽입하려고합니다. 나는 실제로 이것을 잘 실행시킬 수 있었지만 오늘 피드에는 설명에 줄임표 문자가있는 항목이 있었는데 다음과 같은 오류가 발생했습니다 :유니 코드 ellipsis가 mySQL 테이블에 올바르게 삽입되도록 SQLAlchemy를 얻으려면 어떻게해야합니까?

UnicodeEncodeError : 'latin-1'코덱은 문자 ' \ n2026 위치 35에 : 서수가 범위 내에 있지 않음 (256)

엔진에 convert_unicode = True 옵션을 추가하면 삽입 기능을 사용할 수 있지만 줄임표가 나타나지 않습니다. 문자. 이것은 내가 알고있는 한 라틴 -1에 수평 줄임표가 없기 때문에 의미가있는 것처럼 보입니다. 인코딩을 utf-8로 설정하더라도 차이가 나는 것 같지 않습니다. phpmyadmin을 사용하여 삽입을하고 줄임표를 포함하면 잘 돌아갑니다.

나는 문자 인코딩을 이해하지 못하거나 내가 지정한 것을 SQLAlchemy로 가져 오는 방법을 알고있다. 누구든지 이상한 문자없이 텍스트를 가져 오는 방법을 알고 있습니까?

UPDATE 내가이 일을 알아 낸하지만 난 그게 중요한 이유는 정말 모르겠어요 생각

... 여기

코드입니다 : 여기

import sys 
import feedparser 
import sqlalchemy 
from sqlalchemy import create_engine, MetaData, Table 

COMMON_CHANNEL_PROPERTIES = [ 
    ('Channel title:','title', None), 
    ('Channel description:', 'description', 100), 
    ('Channel URL:', 'link', None), 
] 

COMMON_ITEM_PROPERTIES = [ 
    ('Item title:', 'title', None), 
    ('Item description:', 'description', 100), 
    ('Item URL:', 'link', None), 
] 

INDENT = u' '*4 

def feedinfo(url, output=sys.stdout): 
    feed_data = feedparser.parse(url) 
    channel, items = feed_data.feed, feed_data.entries 

    #adding charset=utf8 here is what fixed the problem 

    db = create_engine('mysql://user:[email protected]/db?charset=utf8') 
    metadata = MetaData(db) 
    rssItems = Table('rss_items', metadata,autoload=True) 
    i = rssItems.insert(); 

    for label, prop, trunc in COMMON_CHANNEL_PROPERTIES: 
    value = channel[prop] 
    if trunc: 
     value = value[:trunc] + u'...' 
    print >> output, label, value 
    print >> output 
    print >> output, "Feed items:" 
    for item in items: 
    i.execute({'title':item['title'], 'description': item['description'][:100]}) 
    for label, prop, trunc in COMMON_ITEM_PROPERTIES: 
     value = item[prop] 
     if trunc: 
     value = value[:trunc] + u'...' 
     print >> output, INDENT, label, value 
    print >> output, INDENT, u'---' 
    return 

if __name__=="__main__": 
    url = sys.argv[1] 
    feedinfo(url) 

출력은 /입니다 charset 옵션을 사용하지 않고 코드를 실행하면 추적을 할 수 없습니다.

Channel title: [H]ardOCP News/Article Feed 
Channel description: News/Article Feed for [H]ardOCP... 
Channel URL: http://www.hardocp.com 

Feed items: 
    Item title: Windows 8 UI is Dropping the 'Start' Button 
    Item description: After 15 years of occupying a place of honor on the desktop, the "Start" button will disappear from ... 
    Item URL: http://www.hardocp.com/news/2012/02/05/windows_8_ui_dropping_lsquostartrsquo_button/ 
    --- 
    Item title: Which Crashes More? Apple Apps or Android Apps 
    Item description: A new study of smartphone apps between Android and Apple conducted over a two month period came up w... 
    Item URL: http://www.hardocp.com/news/2012/02/05/which_crashes_more63_apple_apps_or_android/ 
    --- 
Traceback (most recent call last): 
    File "parse.py", line 47, in <module> 
    feedinfo(url) 
    File "parse.py", line 36, in feedinfo 
    i.execute({'title':item['title'], 'description': item['description'][:100]}) 
    File "/usr/local/lib/python2.7/site-packages/sqlalchemy/sql/expression.py", line 2758, in execute 
    return e._execute_clauseelement(self, multiparams, params) 
    File "/usr/local/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 2304, in _execute_clauseelement 
    return connection._execute_clauseelement(elem, multiparams, params) 
    File "/usr/local/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 1538, in _execute_clauseelement 
    compiled_sql, distilled_params 
    File "/usr/local/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 1639, in _execute_context 
    context) 
    File "/usr/local/lib/python2.7/site-packages/sqlalchemy/engine/default.py", line 330, in do_execute 
    cursor.execute(statement, parameters) 
    File "build/bdist.linux-i686/egg/MySQLdb/cursors.py", line 159, in execute 
    File "build/bdist.linux-i686/egg/MySQLdb/connections.py", line 264, in literal 
    File "build/bdist.linux-i686/egg/MySQLdb/connections.py", line 202, in unicode_literal 
UnicodeEncodeError: 'latin-1' codec can't encode character u'\u2026' in position 35: ordinal not in range(256) 

그래서 mysql을 연결 문자열에 harset 않았다. 나는 그것이 라틴어 -1로 기본 설정되어 있다고 가정합니까? content_engine의 인코딩 플래그를 utf8로 설정하려고 시도했지만 아무 것도하지 않았습니다. 누구든지 테이블과 필드가 utf8 유니 코드로 설정되어있을 때 왜 latin-1을 사용하는지 알 수 있습니까? 나는 또한 그것을 제거하기 전에 .encode ('cp1252')를 사용하여 항목 [ 'description]을 인코딩하려고 시도했다. 그리고 그것은 연결 문자열에 charset 옵션을 추가하지 않고도 잘 동작했다. 그건 latin-1에서 효과가 없었어야했는데 분명히 그랬을까요? 나는 해결책을 가지고 있지만 답 :

+0

삽입하는 데 사용하는 코드를 표시 할 수 있습니까? 줄임표가 나오는 줄은 어디 있습니까? utf-8을 사용할 때 오류 메시지가 " 'latin-1'코덱을 말합니까? – geoffspear

+0

문제가되는 데이터를 입력하십시오. 사용중인 코드를 제공 할 수 있다면 당신이하려고하는 것을 이해하는 것이 도움이 될 것입니다. :) – Nilesh

+0

나는 위의 코드를 웹 사이트 hardocp.com에서 오는 줄임표와 함께 추가했습니다. 여기에 줄임표가있는 스 니펫이 있습니다. Microsoft는 몇 가지 좋은 것을 찾고 있습니다 ... .. 편견. 위 코드를 포함 시켰습니다. – kvedananda

답변

29

UnicodeEncodeError: 'latin-1' codec can't encode character u'\u2026' 
in position 35: ordinal not in range(256) 

일부 파이썬 코드가 라틴 -1로 문자 \u2026을 변환하려고하고있는 것처럼 보입니다 오류 메시지 (ISO8859-를 사랑 1) 문자열, 실패하고 있습니다. 놀라운 점은 그 문자가 U+2026 HORIZONTAL ELLIPSIS인데, 이는 ISO8859-1에 동등한 문자가 하나도 없다는 것을 의미합니다.

당신은 당신의 SQLAlchemy의 연결 호출 쿼리 ?charset=utf8을 추가하여 문제를 해결 :

SQLAlchemy의 문서의 섹션 Database Urlsmysql로 시작하는 URL이 mysql-python 드라이버를 사용하여 MySQL의 방언을 나타내고 있음을 알 수

import sqlalchemy 
from sqlalchemy import create_engine, MetaData, Table 

db = create_engine('mysql://user:[email protected]/db?charset=utf8') 
.

다음 섹션 Custom DBAPI connect() arguments은 쿼리 인수가 기본 DBAPI로 전달됨을 알려줍니다.

드라이버 의 mysql-python 드라이버가 무엇을할까요? 해당 설명서의 Functions and attributes 섹션에서 charset 속성에 대해 "...존재하는 경우 연결 문자 집합이이 문자 집합으로 변경됩니다. "

연결 문자 집합의 의미를 확인하려면 MySQL 5.6 참조 설명서의 10.1.4. Connection Character Sets and Collations을 참조하십시오. 긴 이야기를 짧게 말하면 MySQL은 들어오는 쿼리를 데이터베이스의 문자 집합과 다른 인코딩으로 해석 할 수 있으며 반환 된 쿼리 결과의 인코딩과 다릅니다.

보고 한 오류 메시지가 SQL 오류가 아닌 파이썬처럼 보입니다 SQLAlchemy 나 mysql-python에있는 어떤 것이 쿼리를 기본 연결 인코딩 인 latin-1으로 변환하기 전에 변환하려고 시도하고 있다고 가정 할 것입니다. connect() 호출에서은 연결 인코딩을 변경하고 U+2026 HORIZONTAL ELLIPSIS은 통과 할 수 있습니다.

업데이트 :. 나는 그것이 잘 통과 할 설명을 사용하여 함수 .encode ('CP1252')를 캐릭터 세트 옵션을 제거하고 인코딩 할 경우 당신은 또한 "물어 어떻게 생략 부호가 CP1252으로 통과 할 수 있지만, 유니 코드가 아닌가? "

encoding cp1252 has 가로 줄임표 문자는 바이트 값이 \x85입니다. 따라서 U+2026 HORIZONTAL ELLIPSIS을 포함하는 유니 코드 문자열을 오류없이 cp1252에 인코딩 할 수 있습니다.

파이썬에서 유니 코드 문자열과 바이트 문자열은 두 가지 다른 데이터 유형입니다. MySQLdb에는 SQL 연결을 통해 바이트 문자열 만 전송하는 정책이있을 수 있습니다. 따라서 유니 코드 문자열로 수신 된 쿼리를 바이트 문자열로 인코딩하지만 쿼리를 바이트 문자열로만 수신하게됩니다.

게시 한 추적에서 마지막 두 줄 (오류가 발생한 곳과 가장 가까운 부분)은 메서드 이름이 literal이고 그 뒤에 unicode_literal이 표시됩니다. 이는 MySQLdb가 유니 코드 문자열로받은 쿼리를 바이트 문자열로 인코딩한다는 이론을 뒷받침하는 경향이 있습니다.

직접 쿼리 문자열을 인코딩하면이 인코딩을 다르게하는 MySQLdb 부분을 우회합니다. 그러나 MySQL 연결 문자 집합과 다른 방식으로 쿼리 문자열을 인코딩하면 인코딩이 일치하지 않아 텍스트가 잘못 저장 될 수 있습니다.

+0

거의 대답합니다. 한 가지는 charset 옵션을 제거한 다음 .encode ('cp1252')를 사용하여 설명을 인코딩하면 잘 처리됩니다. 생략 부호는 cp1252로 통과 할 수 있지만 유니 코드는 통과 할 수 없습니까? 내가 뭔가를 놓치고 있지만 그것이 무엇인지 모르겠다. – kvedananda

+0

감사! 이것은 이해되기 시작했습니다 ... – kvedananda

+0

+1 "귀하가 SQLAlchemy 연결 호출에서 쿼리를 추가하여 문제를 해결 했습니까? charset = utf8" – btk

0

charset=utf8을 연결 문자열에 추가하면 도움이되지만 convert_unicode=Truecreate_engine에 추가 할 때 상황이 발생했습니다. SQLAlchemy 문서는 성능을 향상시키는 것만을 말하지만, 제 경우에는 잘못된 인코더 문제를 실제로 해결했습니다.