一、Python 操作 Mysql的方式
Python 操作 Mysql 主要包含下面 3 种方式:
- Python-MySql
- Python-MySql 由 C 语法打造,接口精炼,性能最棒;但是由于环境依赖多,安装复杂,已停止更新,仅支持 Python2;
- PyMysql
- PyMysql 为替代 Python-Mysql 而生,纯 Python 语言编写的 Mysql 操作客户端,安装方便,支持 Python3;
- SQLAlchemy
- SQLAlchemy 是一个非常强大的 ORM 框架,不提供底层的数据库操作,主要是通过定义模型对应数据表结构,在 Python Web 编程领域应用广泛
由于 Python-MySql 不支持 Python3,所以本文只谈后 2 种操作方式
二、PyMysql
首先,使用 pip 安装依赖 ;
# 安装依赖 pip3 install pymysql
连接数据库,获取数据库连接对象及游标对象;
什么是游标
在 MySQL 中,存储过程或函数中的查询有时会返回多条记录,而使用简单的 SELECT 语句,没有办法得到第一行、下一行或前十行的数据,这时可以使用游标来逐条读取查询结果集中的记录。游标在部分资料中也被称为光标。
三、连接数据库
使用 pymysql 中的 connect() 方法,传入数据库的 HOST 地址、端口号、用户名、 密码、待操作数据库的名称,即可以获取数据库的连接对象;然后,再通过数据库连接对象,获取执行数据库具体操作的游标对象
【步骤】:
- 导入pymysql包
- 创建数据库链接对象
- 创建游标对象
- 使用cursor() 方法
- 执行增删改查操作
- 使用execute()执行单条增删改查
- 使用executemany()执行多条数据的增删改查
- 执行完之后将连接对象提交
- 使用commit()方法
- 将连接对象关闭
- 使用close()方法
我们对Class_Linux库中的students表进行增删改查操作:
原始students表:
1)新增
新增包含新增单条数据和新增多条数据
对于单条数据的插入,只需要编写一条插入的 SQL 语句,然后作为参数执行上面游标对象的 execute(sql) 方法,最后使用数据库连接对象的 commit() 方法将数据提交到数据库中
新增单条数据
import pymysql def connect_mysql(): # 1、创建数据库链接对象 mysql_db = pymysql.connect(host='192.168.198.142', port=3306, user='root', password='Nebula@123', database='Class_Linux') # 2、创建游标对象 mysql_course = mysql_db.cursor() # 3、执行增删改查操作 # 使用execute()执行单条增删改查 mysql_course.execute('insert into students values(NULL,"李白",23,"男",176,1)') # 4、执行完之后提交 mysql_db.commit() # 5、将连接对象关闭 mysql_db.close() if __name__ == '__main__': connect_mysql()
运行之后,去Linux中的students表查看是否插入成功:
插入成功!
新增多条数据
使用执行游标对象的 executemany() 方法,传入插入的 SQL 语句及 位置变量列表, 可以实现一次插入多条数据
import pymysql def connect_mysql(): mysql_db = pymysql.connect(host='192.168.198.142', port=3306, user='root', password='Nebula@123', database='Class_Linux') mysql_course = mysql_db.cursor() # 使用位置变量传参 insert_query = 'insert into students values(NULL,%s,%s,%s,%s,%s)' datas = [("杜甫", 24, "男", 176, 1), ("白居易", 23, "男", 176, 1), ("王安石", 23, "男", 176, 1)] # 插入多条数据 mysql_course.executemany(insert_query, datas) mysql_db.commit() mysql_db.close() if __name__ == '__main__': connect_mysql()
查询后,插入成功!
2)查询
查询分为三步,分别是:
- 通过游标对象执行具体的 SQL 语句
- 通过游标对象,获取到元组数据
- 遍历元组数据,查看结果
比如:查看数据表中所有的记录
import pymysql def connect_mysql(): mysql_db = pymysql.connect(host='192.168.198.142', port=3306, user='root', password='Nebula@123', database='Class_Linux') mysql_course = mysql_db.cursor() select_query = 'select * from students' mysql_course.execute(select_query) # 拿到students表中的的数据,每一条数据都以元组的形式嵌套在一个大元组里 rows = mysql_course.fetchall() print(rows) # 打印结果 for row in rows: id = row[0] name = row[1] age = row[2] print('id:', id,'name:',name,'age:',age) if __name__ == '__main__': connect_mysql()
如果需要按条件查询某一条记录,只需要修改 SQL 语句即可实现;
import pymysql def connect_mysql(): mysql_db = pymysql.connect(host='192.168.198.142', port=3306, user='root', password='Nebula@123', database='Class_Linux') mysql_course = mysql_db.cursor() # 按id查询 SQL_QUERY_WITH_CONDITION = "SELECT * FROM students WHERE id={};" # 输入数字几就查询那一条数据 mysql_course.execute(SQL_QUERY_WITH_CONDITION.format(26)) # 拿到students表中的的数据,每一条数据都以元组的形式嵌套在一个大元组里 rows = mysql_course.fetchall() # 打印结果 for row in rows: id = row[0] name = row[1] age = row[2] print('id:', id,'name:',name,'age:',age) if __name__ == '__main__': connect_mysql()
将查询数据改成交互式:import pymysql while True: user_input = int(input("请输入您想查询的用户id:")) def connect_mysql(): mysql_db = pymysql.connect(host='192.168.198.142', port=3306, user='root', password='Nebula@123', database='Class_Linux') mysql_course = mysql_db.cursor() # 按id查询 SQL_QUERY_WITH_CONDITION = "SELECT * FROM students WHERE id={};" mysql_course.execute(SQL_QUERY_WITH_CONDITION.format(user_input)) # 拿到students表中的的数据,每一条数据都以元组的形式嵌套在一个大元组里 rows = mysql_course.fetchall() # 打印结果 for row in rows: id = row[0] name = row[1] age = row[2] print('id:', id,'name:',name,'age:',age) if __name__ == '__main__': # range(28)表示范围在28之内,不包括28 if user_input in range(28): connect_mysql() else: print("您所输入的id号不正确,请重新输入!")
3)更新
和 新增操作 类似,更新操作也是通过游标对象去执行更新的 SQL 语句,最后利用数 据库连接对象将数据真实更新到数据库中
【步骤】:
- 导包
- 创建连接对象
- 创建游标对象
- 执行语句
- 提交连接对象
- 关闭连接对象
# 1、导包 import pymysql def connect_mysql(): # 2、创建连接对象 mysql_db = pymysql.connect(host='192.168.198.142', port=3306, user='root', password='Nebula@123', database='Class_Linux') # 3、创建游标对象 mysql_course = mysql_db.cursor() update_query = 'update students set name="%s",age=%s WHERE id=%s' sql_update = update_query % ("王五五", 30, 27) # 4、执行语句 mysql_course.execute(sql_update) # 5、提交连接对象 mysql_db.commit() # 6、关闭连接对象 mysql_db.close() if __name__ == '__main__': connect_mysql()
修改之前:
修改之后:
4)删除
删除操作同查询、新增操作类似,只需要变更 SQL 语句即可
【步骤】:
- 导包
- 创建连接对象
- 创建游标对象
- 执行语句
- 释放资源
# 1、导包 import pymysql def connect_mysql(): # 2、创建连接对象 mysql_db = pymysql.connect(host='192.168.198.142', port=3306, user='root', password='Nebula@123', database='Class_Linux') # 3、创建游标对象 mysql_course = mysql_db.cursor() # 删除(通过id去删除数据) delete_query = 'delete from students where id=%d' sql_delete = delete_query % (27) # 4、执行sql语句 mysql_course.execute(sql_delete) # 5、释放资源 mysql_db.commit() mysql_db.close() if __name__ == '__main__': connect_mysql()
删除前:
删除后:
四、保存爬取到的数据到MySQL里
之前写的爬取飞卢网站的小说标题,作者,小说类型
import re import requests response = requests.get('https://b2.faloo.com/y_0_1.html') def parse_url(): # 标题 div_text1 = re.findall(re.compile(r'<div class="TwoBox02_08">(.*?)</div>'), response.text) title_list = [] for i in div_text1: title_list.append(re.findall(re.compile(r'<h1 class="fontSize17andHei" title="(.*?)">'), i)[ 0]) # 加下标是为了去掉括号[],因为使用?取消贪婪匹配后每一个符合条件的都是列表形式,使用下标可以将每一个小列表中的字符串取出来 # print(title_list) # 作者 div_text2 = re.findall(re.compile(r'<div class="TwoBox02_09">(.*?)</div>'), response.text) author_list = [] for i in div_text2: author_list.append(re.findall(re.compile(r'<a href="//b2.faloo.com/.* title="(.*?)"'), i)[ 0]) # 加下标是为了去掉括号[],因为使用?取消贪婪匹配后每一个符合条件的都是列表形式,使用下标可以将每一个小列表中的字符串取出来 # print(author_list) # 类型 div_text3 = re.findall(re.compile(r'<span class="fontSize14andHui">(.*?)</a>'), response.text) model_list = [] for i in div_text3: model_list.append(re.findall(re.compile(r'<a href="//b2.faloo.com/l.*" title="(.*?)" target="_blank">'), i)[ 0]) # 加下标是为了去掉括号[],因为使用?取消贪婪匹配后每一个符合条件的都是列表形式,使用下标可以将每一个小列表中的字符串取出来 # print(model_list) # 将爬取到的内容合并 multi_list = map(list, zip(title_list, author_list, model_list)) all_list = list(multi_list) # print(all_list) return all_list def write_data(): with open('./novel.txt', 'w', encoding='utf-8') as fw: fw.write('书名 作者 类型\n') for i in parse_url(): fw.write(' '.join(i) + '\n') if __name__ == '__main__': print(parse_url()) write_data()
新建spider_and_pymysql_2.py文件
import pymysql # 导入自定义模块 from spider.Feilu_spider4 import parse_url # 插入数据 def insert_info(all_list): mysql_db = pymysql.connect(host='192.168.198.142', port=3306, user='root', password='Nebula@123', database='Class_Linux') mysql_course = mysql_db.cursor() # db = connect_mysql()[0] # course = connect_mysql()[1] # 创建表 create_table_sql = "create table if not exists novel_info(id int NOT NULL auto_increment primary key," \ "novel_name varchar(100)," \ "novel_author varchar(30)," \ "novel_type varchar(30))" mysql_course.execute(create_table_sql) # 插入多条数据 try: sql_insert = 'insert into novel_info values(NULL,"%s","%s","%s");' mysql_course.executemany(sql_insert, all_list) print("爬取到数据,开始插入") print(all_list) mysql_db.commit() print("数据插入成功!") except Exception as e: print(e, "数据插入失败!") print("操作成功!") if __name__ == '__main__': insert_info(parse_url())
去MySQL查看发现插入成功!
【可能出现的报错!】
如果你的程序没有报错,去MySQL查看发现id被占了但是没有数据,例如下面的情况
查看表,发现没有数据:
随便插入一条数据; 再查看,发现id被占了
这可能是因为在我的代码里,我将创建连接对象和创建游标对象单独封装成立一个函数,在insert_info函数中,没有重新创建连接对象和创建游标对象,而是利用return调用了它的返回值,如果你也有这样的问题,就请给插入数据的函数重新创建连接对象和创建游标对象,下面是错误的代码:
import pymysql # 导入自定义模块 from spider.Feilu_spider4 import parse_url # 连接数据库 def connect_mysql(): mysql_db = pymysql.connect(host='192.168.198.142', port=3306, user='root', password='Nebula@123', database='Class_Linux') mysql_course = mysql_db.cursor() return mysql_db, mysql_course # 插入数据 def insert_info(all_list): db = connect_mysql()[0] course = connect_mysql()[1] # 创建表 create_table_sql = "create table if not exists novel_info(id int NOT NULL auto_increment primary key," \ "novel_name varchar(100)," \ "novel_author varchar(30)," \ "novel_type varchar(30))" # 为啥加个)就行了????? course.execute(create_table_sql) # 插入多条数据 try: sql_insert = 'insert into novel_info values(NULL,"%s","%s","%s");' course.executemany(sql_insert, all_list) print("爬取到数据,开始插入") print(all_list) db.commit() print("数据插入成功!") except Exception as e: print(e, "数据插入失败!") print("操作成功!") if __name__ == '__main__': # connect_mysql() insert_info(parse_url())