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.