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でUnicode文字列の代わりに8ビット文字列を使用したい場合は、sqlite接続に適切な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テキストでいっぱいでした。そのため、データベースを直接保存するよりもデータベースが大きくなります。
ブライアンミントン2014年

3
これは正しくありません。ドキュメントにあるように、代わりにsqlite3.Binaryを使用する必要があります。
MarioVilas 2014

sqlite3.Binary()は単なるbuffer()のエイリアスのようです、少なくともgithub.com/ghaering/pysqlite/blob/master/lib/dbapi2.py#L54
stevegt

ええと。また、pysqliteドキュメントのこのセクションは、実際にbuffer()の使用を奨励しているようにも見えます。 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」はすでにこの列のデータがバイナリであることを示していますか?Python 2では、文字列はテキストでもバイナリでもかまいません。sqlite3は、オブジェクト(zlib圧縮文字列)をBLOBタイプのバイナリとして処理するだけではいけませんか?
user1783732 2014年

Pythonが正しいデータ型を参照するためにメモリ内にデータベーススキーマ全体を持っているとは思いません-ほとんどの場合、それは渡されたものに基づいて実行時に型を推測するだけなので、バイナリ文字列はテキスト文字列と区別できません。
MarioVilas 14

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.