贴一个自己写的PYTHON数据上传函数

发布于 2023-11-23  429 次阅读


  • 前面一篇写了个从csv文件读数据查重并上传数据库的脚本,这一篇写一个实时上传数据的脚本

编写准备

  • 首先还是pymysql库,首先创建一个数据库连接对象,并传入mysql服务地址,账号密码和数据库名
import pymysql

host = 'localhost'
user = 'your_username'
password = 'your_password'
database = 'your_database'

conn = pymysql.connect(host=host, user=user, password=password, database=database)
  • 也有其他的一些参数
port:数据库的端口号(默认为 3306)。
charset:连接使用的字符集(默认为 "utf8")。
autocommit:是否自动提交事务(默认为 False)。
ssl:用于安全连接的 SSL 配置。
  • 然后这样就能执行sql命令了
cursor = conn.cursor()
cr1="ALTER TABLE %s CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"%table_name
cursor.execute(cr1)
  • 为了方便改这些配置,我们使用configparser库简单地从.ini文件里面读取配置文件,这样我们在不同地方使用脚本时就不用老是改代码了

  • .ini文件基本格式如下

; 这是注释行,以分号开头

[section1]
key1 = value1
key2 = value2

[section2]
key3 = value3
key4 = value4
  • 除了.ini格式,还有一些其他的典型配置文件格式,python也基本上都有相关的库
JSON(JavaScript Object Notation):一种轻量级的数据交换格式,具有易读和易写的特点。
YAML(YAML Ain't Markup Language):一种人类可读的数据序列化格式,常用于配置文件和数据传输。
XML(eXtensible Markup Language):一种用于存储和传输数据的标记语言,具有良好的可扩展性。
TOML(Tom's Obvious, Minimal Language):一种易于阅读和编写的配置文件格式,注重简洁性和可读性。
  • 使用configparser需要先实例化一个对象
config = configparser.ConfigParser()
  • 然后调用read函数读指定文件的内容,这里读相同目录下的config.ini,如果你用的vscode直接执行脚本可能出现一个有趣的问题,vscode默认设置了工作目录,比如我的工作目录在桌面,那么无论我的脚本放在哪里,直接读config.ini都是指读工作目录(桌面)的config.ini而不是与py文件相同目录下的文件,所以如果报文件不存在可以用绝对路径(记得加\\防转义)或者直接用终端执行

config.read('config.ini', encoding='utf-8')
  • 调用方式这里使用最简单的键名加数字直接调用(也有更正常的调用方式),比如配置文件为
[database]
host=127.0.0.1
user=root
password=123456
database=miaomiao
[miao]
key=gcpb
cookie=sk-
  • 要调用miao的section下面cookie的值
cookie=config.items('miao')[1][1]
  • 同样的,config.items('miao')[0][1]的值就是"cookie",config.items('miao')[0][1]为gcpb

  • 最后就是以前写过的正则的使用了,因为非utf编码上传可能会出问题,所以写个函数正则过滤一下

def remove_non_utf8(text):
        utf8_text = re.sub(r'[^\x00-\x7F\u4E00-\u9FA5]+', '', text)
        return utf8_text

一些问题

  • 在使用过程中出现的问题让我们可以更好的修改这个函数,这里放几个我发现的问题
  • 在读文件的时候有时会报错

  • 这是因为configparser.ConfigParser()这个类用于解析含有特殊字符转义的配置文件。它会对配置文件中的值进行处理,将特殊字符转义为其原始形式。例如,% 字符会被转义为 %%,以避免被解析为格式化字符串中的占位符。这个类适用于处理复杂的配置文件,例如包含格式化字符串或特殊字符的配置文件。
  • 也就是说它不会对防止特殊字符转义,所以将特殊字符当作控制语句处理了,解决办法很简单,configparser.RawConfigParser():这个类用于解析不含有特殊字符转义的配置文件。它不会对配置文件中的值进行任何处理,而是将其原样返回。如果配置文件中包含特殊字符,它们将被视为普通字符。
  • configparser.RawConfigParser()configparser.ConfigParser() 是 configparser 模块中两个不同的类,用于解析和处理配置文件。它们之间的区别在于如何处理特殊字符转义。
config = configparser.RawConfigParser()
config.read('config.ini', encoding='utf-8')
  • 然后是有的时候正好传了个数字到re.sub函数里面,这个正则函数只能处理字符串,遇到数字会报错,所以要进一步加上str防止意外情况
utf8_text = re.sub(r'[^\x00-\x7F\u4E00-\u9FA5]+', '', str(text))
  • 另外,在低版本的windows下(高版本没试过)用记事本打开config.ini文件很可能导致文件编码变成utf-8-bom,需要用编码软件调一下,而且打开一次就会变回去,这会导致\ufeff编码报错.最好的办法是直接用第三方文本编辑器,比如我用的nodepad++

脚本代码

  • 脚本实现了无表创建表,然后根据设定的字段监测是否重复,最后去除非utf-8编码的字符并上传
import pymysql
import time
import configparser
import re
config = configparser.RawConfigParser()
config.read('config.ini', encoding='utf-8')

def remove_non_utf8(text):
        # 使用正则表达式匹配非UTF-8字符并替换为空字符串
        utf8_text = re.sub(r'[^\x00-\x7F\u4E00-\u9FA5]+', '', str(text))
        return utf8_text
def upload(table_name,head,values):
        try:
            conn = pymysql.connect(host=config.items('database')[0][1], user=config.items('database')
            [1][1], password=config.items('database')[2][1], database=config.items('database')[3][1])
            cursor = conn.cursor()
        except:
            print("数据库连接失败")
            time.sleep(1000000)
        try:
            create_table_query = f"CREATE TABLE IF NOT EXISTS {table_name} ({','.join([f'{header} TEXT' for header in head])})"
            cr1="ALTER TABLE %s CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"%table_name
            cursor.execute(create_table_query)
            cursor.execute(cr1)

            existing_data_query1 = f"SELECT * FROM {table_name}"
            cursor.execute(existing_data_query1)
            existing_data1 = cursor.fetchall()
            existing_data_set1 = set(tuple(row) for row in existing_data1)

            # 插入数据

            cf=0
            for i in existing_data_set1:
                #print(values[0],i[0])
                if values[3]==i[3] or values[4]==i[4]:#判断数据是否重复的字段
                    cf=1
                    break
            if cf==0:
                insert_query = f"INSERT INTO {table_name}({','.join(head)}) VALUES({','.join(['%s'] * len(head))})"
                cursor.execute(insert_query, values)
                # 提交事务
                conn.commit()

        except Exception as e:
            print(f"导入数据出错: {str(e)}")
            conn.rollback()
        finally:
            cursor.close()
            conn.close()

head=['name', 'age']
cont=[remove_non_utf8('jack'),remove_non_utf8('18')]
upload('netease_comm',head,cont)
head=['name', 'age']
cont=[remove_non_utf8('tom'),remove_non_utf8('16')]
upload('netease_comm',head,cont)
届ける言葉を今は育ててる
最后更新于 2024-02-08