sqlite3.ProgrammingError : 8 비트 바이트 열을 해석 할 수있는 text_factory를 사용하지 않는 한 8 비트 바이트 열을 사용해서는 안됩니다.


90

Python에서 SQLite3를 사용하여 UTF-8 HTML 코드 조각의 압축 된 버전을 저장하려고합니다.

코드는 다음과 같습니다.

...
c = connection.cursor()
c.execute('create table blah (cid integer primary key,html blob)')
...
c.execute('insert or ignore into blah values (?, ?)',(cid, zlib.compress(html)))

어느 시점에서 오류가 발생합니까?

sqlite3.ProgrammingError: You must not use 8-bit bytestrings unless you use a text_factory that can interpret 8-bit bytestrings (like text_factory = str). It is highly recommended that you instead just switch your application to Unicode strings.

'blob'대신 'text'를 사용하고 HTML 스 니펫을 압축하지 않으면 모두 잘 작동합니다 (db는 크지 만). 'blob'을 사용하고 Python zlib 라이브러리를 통해 압축하면 위의 오류 메시지가 나타납니다. 나는 주위를 둘러 보았지만 이것에 대한 간단한 답을 찾을 수 없었다.

답변:


94

sqlite3에서 유니 코드 문자열 대신 8 비트 문자열을 사용하려면 sqlite 연결을 위해 approptiate text_factory를 설정합니다.

connection = sqlite3.connect(...)
connection.text_factory = str

7
이진 데이터를 텍스트로 구문 분석하려고하기 때문에 다른 인코딩에 문제가 발생할 수 있습니다. 대신 sqlite3.Binary를 사용하는 것이 가장 좋습니다.
MarioVilas 2014

35

해결책을 찾았습니다. 검색에 조금 더 시간을 투자 했어야했습니다.

해결책은 다음과 같이 값을 Python '버퍼'로 '캐스트'하는 것입니다.

c.execute('insert or ignore into blah values (?, ?)',(cid, buffer(zlib.compress(html))))

바라건대 이것은 다른 사람을 도울 것입니다.


1
이 작업을 수행했을 때 데이터베이스는 base36 텍스트로 가득 차 있었기 때문에 BLOB를 직접 저장하는 것보다 데이터베이스가 더 커졌습니다.
Brian Minton 2014 년

3
이것은 올바르지 않습니다. 문서에 나와있는대로 sqlite3.Binary를 대신 사용해야합니다.
MarioVilas 2014


허. 또한 pysqlite 문서의이 섹션은 실제로 buffer () 사용을 권장하는 것처럼 보입니다. "따라서 다음 Python 유형을 문제없이 SQLite로 전송할 수 있습니다. ..."[Python 유형] buffer ... [SQLite 유형] BLOB " docs.python.org/2/library/sqlite3.html#introduction
stevegt

35

BLOB 유형으로 작업하려면 먼저 zlib 압축 문자열을 이진 데이터로 변환해야합니다. 그렇지 않으면 sqlite가이를 텍스트 문자열로 처리하려고합니다. 이것은 sqlite3.Binary ()로 수행됩니다. 예를 들면 :

c.execute('insert or ignore into blah values (?, ?)',(cid, 
sqlite3.Binary(zlib.compress(html))))

작동합니다. 그러나 이것이 왜 필요한지 궁금합니다. "BLOB"유형이 이미이 열의 데이터가 2 진임을 표시 했습니까? Python 2에서 문자열은 텍스트 또는 바이너리 일 수 있습니다. sqlite3는 객체 (zlib 압축 문자열)를 BLOB 유형의 바이너리로 처리해야하지 않습니까?
user1783732

나는 파이썬이 올바른 데이터 유형을 참조하기 위해 전체 데이터베이스 스키마를 메모리에 가지고 있다고 생각하지 않습니다.
MarioVilas 2014

SQLite는 동적 유형을 사용하기 때문에 : sqlite.org/datatype3.html @ user1783732
Lester Cheung

1

통사론:

5 가지 유형의 가능한 스토리지 : NULL, INTEGER, TEXT, REAL 및 BLOB

BLOB는 일반적으로 피클 모델 또는 딜 피클 모델을 저장하는 데 사용됩니다.

> cur.execute('''INSERT INTO Tablename(Col1, Col2, Col3, Col4) VALUES(?,?,?,?)''', 
                                      [TextValue, Real_Value, Buffer(model), sqlite3.Binary(model2)])
> conn.commit()

> # Read Data:
> df = pd.read_sql('SELECT * FROM Model, con=conn) 
> model1 = str(df['Col3'].values[0]))
> model2 = str(df['Col'].values[0]))

0

원시 출력 대신 repr (html)을 사용하여 값을 저장 한 다음 사용할 값을 검색 할 때 eval (html)을 사용할 수 있습니다.

c.execute('insert or ignore into blah values (?, ?)',(1, repr(zlib.compress(html))))

1
이와 같이 eval 및 repr을 사용하는 것은 매우 더럽습니다. 데이터 소스를 얼마나 신뢰하든 상관 없습니다.
Jason Fried

동의합니다. 여기서 eval ()보다 낫습니다. 올바른 솔루션은 sqlite3.Binary를 사용하는 것이지만, 어떤 이유로 든 할 수 없다면 base64와 같은 안전한 방법으로 데이터를 인코딩하는 것이 좋습니다.
MarioVilas 2014
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.