【问题标题】:How to avoid b' and UTF-8 literals in MySQL using Python 3如何使用 Python 3 在 MySQL 中避免 b' 和 UTF-8 文字
【发布时间】:2018-12-29 07:25:18
【问题描述】:

我有点新手。所以我试图解析html页面并将内容放在MySQL的列中,但是我似乎无法让实际的外来字符出现,例如我得到xc3xa1而不是á。我的表有 utf8mb4 作为其字符集和排序规则 utf8mb4_unicode_ci。我有以下设置:

Database_cnx = pymysql.connect(user='XXXX', password='XXXX',
                              host='XXXX',
                              database='XXXX',
                              use_unicode=True,
                              charset='utf8mb4')

article_content = str(row[3].encode("utf-8")).replace("'", "\'").replace("\"", "\'")

q_i = ("INSERT INTO article_items (" + ", ".join(article_table_col_name_new) + ")"
"VALUES ({:d}, \"{:s}\", \"{:s}\", \"{:s}\", \"{:s}\", \"{:s}\", \"{:s}\")".format(row[0], urlparse(row[1]).netloc, row[1], row[2].replace("\"", "'"), article_content, datetime.fromtimestamp(row[4]).strftime("%Y-%m-%d"), updated)
)

那么我怎样才能让我的专栏中只出现实际的文章内容,而不是 b' 字节和 utf-8 文字。谢谢

【问题讨论】:

    标签: python mysql utf-8 python-3.5 utf8mb4


    【解决方案1】:

    我得到的是 xc3xa1 而不是 á

    这表示问题在于将数据插入数据库。回到那个代码,让我们讨论一下。

    (可能是\xc3\xa1,但反斜杠在某个地方丢失了。)C3A1á 的UTF-8 编码的十六进制。

    您可以通过获取字符串长度来仔细检查 - 对于á,它应该是 1(字符)或 2(字节),但对于 \xc3\xa1,显然是 8。

    【讨论】:

      【解决方案2】:

      问题在于您将字符串显式编码为 UTF-8 字节,然后将该 UTF-8 字节转换为其字符串表示形式。

      这就是这段代码的意思:

      str(row[3].encode("utf-8"))
      

      如果你不想那样做,就不要那样做:

      row[3]
      

      这里有一个例子说明你在做什么:

      >>> s = 'à'
      >>> s
      'à'
      >>> s.encode('utf-8')
      b'\xc3\xa0'
      >>> str(s.encode('utf-8'))
      "b'\\xc3\\xa0'"
      

      你想要的是第一个。

      更一般地说,在bytes 上调用str 几乎没有用处。如果你不可避免地有一个bytes 并且你需要一个str,你可以通过调用decode 方法得到它。但在这种情况下,您不会不可避免地拥有bytes。 (我的意思是,你可以row[3].encode("utf-8").decode("utf-8"),但这显然很愚蠢。)


      作为旁注(但非常重要),您不应该尝试将str.format 您的值添加到 SQL 字符串中。只需使用查询参数。 Here's the obligatory xkcd link 解释了安全/安全问题,最重要的是,您正在使您的代码更加复杂,甚至效率更低。

      换句话说,不要这样做:

      "VALUES ({:d}, \"{:s}\", \"{:s}\", \"{:s}\", \"{:s}\", \"{:s}\", \"{:s}\")".format(row[0], urlparse(row[1]).netloc, row[1], row[2].replace("\"", "'"), article_content, datetime.fromtimestamp(row[4]).strftime("%Y-%m-%d"), updated)
      

      ……就这样做吧:

      "VALUES (%s, %s, %s, %s, %s, %s, %s)"
      

      然后,当您稍后执行查询时,将参数传递给execute,而不需要复杂地转换为字符串以及引用和替换嵌入的引号,只需将值原样传递给execute

      db.execute(q_i, (
          row[0], urlparse(row[i]).netloc, row[1], row[2], article_content, 
          datetime.fromtimestamp(row[4]).strftime("%Y-%m-%d"), updated))
      

      事实上,如果您的倒数第二列是(或可能是)DATETIME 列而不是 CHAR/VARCHAR/TEXT/whatever,那么您甚至不需要 strftime ;只需传递datetime 对象即可。

      请注意,这意味着您根本不需要对article_content 执行任何操作。引用的东西既不是必需的也不是一个好主意(除非你有其他一些特定于应用程序的原因,你需要避免文章中的" 字符),并且编码的东西没有解决任何问题,而只会导致一个新问题.

      【讨论】:

        猜你喜欢
        • 2016-04-21
        • 1970-01-01
        • 2018-04-02
        • 2017-05-23
        • 2016-01-05
        • 2018-05-17
        • 2010-10-07
        相关资源
        最近更新 更多