Apakah perubahan formatter string Python dalam edisi terbaru merusak konektor MySQL?
Saya sedang menulis skrip sederhana - atau seharusnya sederhana - untuk memperoleh tweet dari API Twitter (saya memiliki kunci pengembang / aplikasi dan saya menggunakan antarmuka Tweepy, tidak menggores atau semacamnya - saya mungkin meninggalkan Tweepy untuk sesuatu yang lebih dekat API modern tetapi hampir pasti bukan itu yang menyebabkan masalah ini di sini).
Saya memiliki instance MySQL yang saya sambungkan dan dapat melakukan kueri dengan baik, sampai tiba saatnya untuk memasukkan tweet - yang memiliki banyak karakter khusus, hampir pasti. Untuk memperjelas, saya menggunakan driver / konektor Python resmi untuk MySQL.
import mysql.connector
from mysql.connector import errorcode
Sekarang, saya sadar StackOverflow TERTINGGI dengan utas di mana orang mendapatkan kesalahan persis saya - cukup menyatakan untuk memeriksa manual sintaks MySQL. Utas ini, yang tidak terlalu tua (dan saya tidak menggunakan Python terbaru, saya menggunakan 3.7.9 untuk kompatibilitas dengan beberapa perpustakaan NLP) bersikeras jawabannya adalah menempatkan string yang memiliki karakter khusus ke dalam yang lama- gaya format string DALAM metode cursor.execute, untuk menyertakan placeholder variabel string dalam tanda kutip, dan untuk melewatkan tupel dengan nilai kedua yang kosong jika, seperti dalam kasus saya, hanya satu variabel yang akan disisipkan. Ini juga merupakan solusi yang diposting sebagai bagian dari respons laporan bug di situs web MySQL - namun, saya tidak berhasil.
Inilah yang saya dapatkan - mengikuti petunjuk di lusinan halaman di sini dan situs web database resmi:
for tweet in tweepy.Cursor(twilek.search, q=keyword, tweet_mode='extended').items():
twi_tweet = tweet.full_text
print(twi_tweet)
twi_tweet = twi_tweet.encode('utf8')
requests_total+=1
os.environ['TWITTER_REQUESTS'] = str(requests_total)
requests_total = int(os.environ.get('TWITTER_REQUESTS'))
# insert the archived tweet text into the database table
sql = 'USE hate_tweets'
ms_cur.execute(sql)
twi_tweet = str(twi_tweet)
insert_tweet = re.sub(r'[^A-Za-z0-9 ]+', '', twi_tweet)
ms_cur.execute("INSERT INTO tweets_lgbt (text) VALUES %s" % (insert_tweet,))
cnx.commit()
print(ms_cur.rowcount, "record inserted.")
(twilek adalah objek kursor saya karena saya bodoh)
hasil yang diharapkan : pemformat string melewati MySQL string tweet yang dimodifikasi yang dapat diproses dan ditambahkan sebagai baris ke tabel tweets_lgbt
hasil aktual : penyisipan gagal karena kesalahan sintaks untuk tweet apa pun
Saya sudah mencoba menggunakan regex untuk menghapus semuanya kecuali alfanumerik dan spasi - masalah yang sama. Saya bertanya-tanya apakah fitur format string baru dari versi Python saat ini telah merusak kompatibilitas dengan konektor ini? Saya lebih suka menggunakan driver resmi tetapi saya akan beralih ke ORM jika saya harus. (Saya mencoba fitur yang lebih baru seperti string F, dan ternyata mereka menyebabkan hasil yang sama.)
Jawaban
Beginilah cara Anda memasukkan baris ke tabel Anda,
insert_tweet = "ABCEFg 9 XYZ"
"INSERT INTO tweets_lgbt (text) VALUES ('%s');"%(insert_tweet)
"INSERT INTO tweets_lgbt (text) VALUES ('ABCEFg 9 XYZ');"
Hal-hal yang perlu diperhatikan
Argumen untuk pemformat string sama seperti argumen untuk suatu fungsi. Jadi, Anda tidak dapat menambahkan koma di bagian akhir untuk mengubah string menjadi tupel di sana.
Jika Anda mencoba memasukkan beberapa nilai sekaligus, Anda dapat menggunakan cursor.executemany atau jawaban ini .
Saya memiliki pengamatan ini:
- yang
VALUESklausul membutuhkan kurungVALUES (%s) - kutipan / pelolosan nilai harus didelegasikan ke metode kursor
execute, dengan menggunakan tempat penampung tanpa tanda kutip di SQL dan meneruskan nilai sebagai argumen kedua:cursor.execute(sql, (tweet_text,))ataucursor.executemany(sql, [(tweet_text1,), (tweet_text2,)]) - setelah langkah-langkah ini diterapkan, tidak perlu encoding / stringifying / regex-ifying: dengan asumsi
twi_textadalah astrdan charset / collation database mendukung rentang UTF-8 penuh (misalnya utf8mb4) maka penyisipan akan berhasil.- secara khusus, pengkodean a
strdan kemudian memanggilstrhasil harus dihindari: Anda berakhir dengan"b'my original string'"
- secara khusus, pengkodean a
Versi kode yang dimodifikasi dalam pertanyaan ini berfungsi untuk saya:
import mysql.connector
DDL1 = """DROP TABLE IF EXISTS tweets_lgbt"""
DDL2 = """\
CREATE TABLE tweets_lgbt (
`text` VARCHAR (256))
"""
# From https://twitter.com/AlisonMitchell/status/1332567013701500928?s=20
insert_tweet = """\
Particularly pleased to see @SarahStylesAU
quoted in this piece for the work she did
👌
Thrive like a girl: Why women's cricket in Australia is setting the standard
"""
# Older connector releases don't support with...
with mysql.connector.connect(database='test') as cnx:
with cnx.cursor() as ms_cur:
ms_cur.execute(DDL1)
ms_cur.execute(DDL2)
ms_cur.execute("INSERT INTO tweets_lgbt (`text`) VALUES (%s)", (insert_tweet,))
cnx.commit()
print(ms_cur.rowcount, "record inserted.")