最近版本中 Python 的字符串格式化程序更改是否破坏了 MySQL 连接器?

Has Python's string formatter changes in recent editions broken the MySQL connector?

我正在编写一个简单的 - 或者它应该是简单的 - 脚本来从 Twitter 的 API 获取推文(我有 developer/app 键并且正在使用 Tweepy 界面,而不是抓取或任何东西那种 - 我可能会放弃 Tweepy 以获得更接近现代的东西 API 但这几乎肯定不是导致这里问题的原因)。

我有一个 MySQL 实例,我连接到它并可以很好地查询,直到需要插入推文 - 它有很多特殊字符,几乎不可避免。需要说明的是,我使用官方 Python driver/connector 作为 MySQL.

import mysql.connector
from mysql.connector import errorcode

现在,我知道 Whosebug 上充斥着线程,人们在这些线程中得​​到了我的确切错误 - 只是说明要检查 MySQL 语法手册。这些线程并没有那么旧(而且我没有使用最新的 Python,我使用 3.7.9 来与某些 NLP 库兼容)坚持认为答案是放置具有特殊字符的字符串到 cursor.execute 方法中的旧式格式字符串中,将字符串变量占位符括在引号中,并传递一个第二个值为空的元组,如果在我的情况下,只插入一个变量。这也是 MySQL 网站上作为错误报告响应的一部分发布的解决方案 - 然而,我没有成功。

这是我得到的 - 按照此处数十页和官方数据库网站上的说明进行操作:

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 是我的光标对象,因为我是个笨蛋)

预期结果:字符串格式化程序传递 MySQL 修改后的推文字符串,它可以处理并将其作为一行添加到 tweets_lgbt table

实际结果:插入失败,任何推文都存在语法错误

我试过使用正则表达式去除除字母数字和空格之外的所有内容——同样的问题。我想知道当前 Python 版本的新字符串格式功能是否破坏了与此连接器的兼容性?我更喜欢使用官方驱动程序,但如果必须的话,我会切换到 ORM。 (我确实尝试了 F 弦等较新的功能,发现它们导致了相同的结果。)

这就是您应该如何向 table、

中插入一行
insert_tweet = "ABCEFg 9 XYZ"
"INSERT INTO tweets_lgbt (text) VALUES ('%s');"%(insert_tweet)
"INSERT INTO tweets_lgbt (text) VALUES ('ABCEFg 9 XYZ');"

注意事项

  1. 字符串格式化程序的参数就像 功能。所以,你不能在末尾添加逗号来转换字符串 那里的一个元组。

  2. 如果您尝试一次插入多个值,您可以使用 cursor.executemany or this .

我有这些观察:

  • VALUES 子句 需要 括号 VALUES (%s)
  • 值的引用/转义应委托给游标的 execute 方法,方法是在 SQL 中使用不带引号的占位符并将值作为第二个参数传递:cursor.execute(sql, (tweet_text,))cursor.executemany(sql, [(tweet_text1,), (tweet_text2,)])
  • 一旦应用了这些步骤就不需要 encoding/stringifying/regex-ifying:假设 twi_text 是一个 str 并且数据库的 charset/collation 支持完整的 UTF-8 范围(对于例如 utf8mb4) 那么插入应该成功。
    • 特别是要避免对 str 进行编码,然后对结果调用 str:你最终会得到 "b'my original string'"

这个问题中代码的修改版本对我有用:

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.")