Hat Pythons Änderungen am String-Formatierer in den letzten Editionen den MySQL-Connector beschädigt?
Ich schreibe ein einfaches - oder es sollte einfach sein - Skript, um Tweets von der Twitter-API abzurufen (ich habe Entwickler- / App-Schlüssel und verwende die Tweepy-Oberfläche, kein Scraping oder ähnliches - ich kann Tweepy für etwas näheres wegwerfen die moderne API, aber das ist mit ziemlicher Sicherheit nicht der Grund für dieses Problem.
Ich habe eine MySQL-Instanz, mit der ich mich verbinde und die ich problemlos abfragen kann, bis es an der Zeit ist, den Tweet einzufügen - der fast zwangsläufig viele Sonderzeichen enthält. Um klar zu sein, verwende ich den offiziellen Python-Treiber / Connector für MySQL.
import mysql.connector
from mysql.connector import errorcode
Jetzt ist mir bewusst, dass StackOverflow mit Threads übersät ist, in denen die Leute meinen genauen Fehler erhalten - einfach angegeben, um das MySQL-Syntaxhandbuch zu überprüfen. Diese Threads, die nicht allzu alt sind (und ich verwende nicht das neueste Python, ich verwende 3.7.9, um mit einigen NLP-Bibliotheken kompatibel zu sein), bestehen darauf, dass die Antwort darin besteht, die Zeichenfolge mit den Sonderzeichen in eine alte zu setzen. Stil Format Zeichenfolge INNERHALB der Methode cursor.execute, um Platzhalter für Zeichenfolgenvariablen in Anführungszeichen zu setzen und ein Tupel mit einem leeren zweiten Wert zu übergeben, wenn wie in meinem Fall nur eine Variable eingefügt werden soll. Dies ist auch eine Lösung, die als Teil einer Fehlerberichtantwort auf der MySQL-Website veröffentlicht wurde - und dennoch habe ich keinen Erfolg.
Folgendes habe ich: Befolgen Sie die Anweisungen auf Dutzenden von Seiten hier und auf der offiziellen Datenbank-Website:
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 ist mein Cursor-Objekt, weil ich ein Trottel bin)
Erwartetes Ergebnis : Der String-Formatierer übergibt MySQL einen modifizierten Tweet-String, den er verarbeiten und als Zeile zur Tabelle tweets_lgbt hinzufügen kann
Tatsächliches Ergebnis : Das Einfügen schlägt aufgrund eines Syntaxfehlers für einen Tweet fehl
Ich habe versucht, Regex zu verwenden, um alles außer alphanumerischen Zeichen und Leerzeichen zu entfernen - dasselbe Problem. Ich frage mich, ob die neuen Funktionen des Zeichenfolgenformats der aktuellen Python-Versionen die Kompatibilität mit diesem Connector beeinträchtigt haben. Ich bevorzuge den offiziellen Treiber, aber ich werde zu einem ORM wechseln, wenn ich muss. (Ich habe die neueren Funktionen wie F-Strings ausprobiert und festgestellt, dass sie das gleiche Ergebnis verursachen.)
Antworten
So sollten Sie eine Zeile in Ihre Tabelle einfügen,
insert_tweet = "ABCEFg 9 XYZ"
"INSERT INTO tweets_lgbt (text) VALUES ('%s');"%(insert_tweet)
"INSERT INTO tweets_lgbt (text) VALUES ('ABCEFg 9 XYZ');"
Dinge zu beachten
Die Argumente für einen Zeichenfolgenformatierer entsprechen genau den Argumenten für eine Funktion. Sie können also am Ende kein Komma hinzufügen, um dort eine Zeichenfolge in ein Tupel umzuwandeln.
Wenn Sie versuchen, mehrere Werte gleichzeitig einzufügen, können Sie cursor.executemany oder diese Antwort verwenden .
Ich habe diese Beobachtungen:
- Die
VALUES
Klausel erfordert KlammernVALUES (%s)
- Das Anführungszeichen / Escapezeichen von Werten sollte an die
execute
Methode des Cursors delegiert werden, indem nicht zitierte Platzhalter in SQL verwendet und die Werte als zweites Argument übergeben werden:cursor.execute(sql, (tweet_text,))
odercursor.executemany(sql, [(tweet_text1,), (tweet_text2,)])
- Sobald diese Schritte angewendet wurden, ist keine Codierung / Zeichenfolge / Regex-Prüfung mehr erforderlich: Unter der Annahme, dass
twi_text
astr
und der Zeichensatz / die Sortierung der Datenbank den gesamten UTF-8-Bereich (z. B. utf8mb4) unterstützt, sollte die Einfügung erfolgreich sein.- Insbesondere ist es zu vermeiden , a zu codieren
str
und dannstr
das Ergebnis aufzurufen : Sie haben am Ende"b'my original string'"
- Insbesondere ist es zu vermeiden , a zu codieren
Diese modifizierte Version des Codes in der Frage funktioniert für mich:
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.")