网络通信和访问数据库
1.1 基本的网络知识
@TCP/IP
IP是低级的路由协议,它将数据拆分在许多小的数据包中,并通过网络将他们发送到某一特定地址,但无法保证所有包都抵达目的地,也不能保证包按顺序抵达
TCP(传输控制协议),是一种高层协议,是面向连接的可靠数据传输协议,数据包未收到,会重发,并对数据包进行准确性检查,保证数据包按顺序抵达。
@IP地址,IPv4和IPv6
特殊IP地址,127.0.0.1回送地址,只进行本机进程间通信,不进行任何网络传输
@端口(范围:0~65535,小于1024的保留给预定义的服务,如HTTP,80 FTP,20/21 Telnet,23 Email,25等等)
网络通信程序运行提供网络服务或进行通信,需要不同的端口号进行通信,不仅要指定IP地址,还要指定端口号
@HTTP(端口80)/HTTPS(端口443)
HTTP(超文本传输协议)
HTTP/1.1共定义了8种请求方法,GET和POST方法最常用
HTTPS(超文本传输安全协议):HTTP+SSL,用于提供加密通信及对网络服务器身份的鉴定
1.2 搭建自己的Web服务器
1,安装JDK(java开发工具包)
2,配置java运行环境
3,安装Apache Tomcat服务器
4,启动Apache Tomcat服务器
1.3 urllib.request模块
1,发送GET请求
# 发送GET请求,获取响应
import urllib.request # 导入urllib.request模块url = 'http://www.baidu.com/?action=query&ID=10' # 请求URL网址,?后的内容是请求参数,多个参数用&分隔,例如action是参数名,query是参数值req = urllib.request.Request(url) # 创建一个请求对象,默认是GET请求with urllib.request.urlopen(req) as response: # 发送请求,并获取响应对象,可是使用with as代码块管理和释放data = response.read() # 读取数据,为字节序列数据json_data = data.decode() # 将字节序列数据转换为字符串print(json_data) # 输出字符串数据
2,发送POST请求,提交数据
# 发送POST请求,提交数据import urllib.request # 导入urllib.request模块url = 'http://www.baidu.com/'# 准备HTTP参数
params_dict = {'action': 'query', 'ID': '10'}
params_str = urllib.parse.urlencode(params_dict) # 将字典转换为URL参数字符串
print(params_str)# 字符串转换为字节序列数据
params_bytes = params_str.encode()# 创建一个请求对象,设置请求方法为POST
req = urllib.request.Request(url, data=params_bytes) # 发送POST请求,并设置请求方法为POSTwith urllib.request.urlopen(req) as response: # 发送请求,并获取响应对象,可使用with as代码块管理和释放data = response.read() # 读取数据,为字节序列数据json_data = data.decode() # 将字节序列数据转换为字符串print(json_data) # 输出字符串数据
1.4 JSON数据
JSON(JavaScript Object Notation)
构成JSON文档的两种结构为:JSON对象(object)和JSON数组(array)
@1.4.1 JSON对象类似于python中的字典类型
JSON数据中的解码(decode)指将JSON数据转换为python数据,当从网络中接收或从磁盘中读取JSON数据时,需要将其解码为Python数据
{
"name": "a.htm",
"size": "345",
"saved": "true"
}
@1.4.2 JSON数组类似于python中的列表类型,示例如下:
[
"text","html","css"
]
@1.4.3 JSON的数值有字符串,数字,true,false,null,对象或数组。null表示空的对象,而且对象和数组可以嵌套
@1.4.4 使用json模块提供的loads(str)函数进行JSON数据的解码,参数str是JSON字符串,返回python数据。
代码示例:
import urllib.request # 导入urllib.request模块
import json # 导入json模块url = 'http://www.baidu.com/?action=query&ID=10' # 请求URL网址,?后的内容是请求参数,多个参数用&分隔,例如action是参数名,query是参数值req = urllib.request.Request(url) # 创建一个请求对象,默认是GET请求with urllib.request.urlopen(req) as response: # 发送请求,并获取响应对象,可是使用with as代码块管理和释放data = response.read() # 读取数据,为字节序列数据json_data = data.decode() # 将字节序列数据转换为字符串print('JSON字符串:', json_data) # 输出字符串数据py_dict = json.load(json_data) # 解码json字符串,返回字典print('备忘录ID:', py_dict['ID'])print('备忘录日期:', py_dict['CDate'])print('备忘录内容:', py_dict['Content'])print('用户ID:', py_dict['UserID'])
@1.4.5 下载图片示例
# 1.4 下载图片示例
import urllib.request # 导入urllib.request模块url = 'http://www.baidu.com/img/logo.png'req = urllib.request.Request(url) # 创建一个请求对象,默认是GET请求with urllib.request.urlopen(req) as response: # 发送请求,并获取响应对象,可使用with as代码块管理和释放data = response.read() # 读取数据,为字节序列数据f_name = 'logo.png' # 文件名with open(f_name, 'wb') as f: # 创建文件对象,并设置写入模式,wb表示写入二进制数据f.write(data) # 将字节序列数据写入文件print('图片下载完成')
@1.4.6 返回所有备忘录信息示例
# 1.5 返回所有备忘录信息
import urllib.request # 导入urllib.request模块
import jsonurl = 'http://www.baidu.com/' # 请求URL网址req = urllib.request.Request(url) # 创建一个请求对象,默认是GET请求with urllib.request.urlopen(req) as response: # 发送请求,并获取响应对象,可是使用with as代码块管理和释放data = response.read() # 读取数据,为字节序列数据json_data = data.decode() # 将字节序列数据转换为字符串py_dict = json.load(json_data) # 解码json字符串,返回字典record_array = py_dict['Record'] # 获取备忘录数组for record_obj in record_array:print('--------备忘录信息--------')print('备忘录ID:', record_obj['ID'])print('备忘录日期:', record_obj['CDate'])print('备忘录内容:', record_obj['Content'])print('用户ID:', record_obj['UserID'])
2.1 SQLite数据库
SQLite是嵌入式系统使用的关系数据库,目前的主流版本是SQLite 3。SQLite是开源的,采用C语言编写而成,具有可移植性强、可靠性高 、小而易用等特点。SQLite提供了对SQL-92标准的支持,支持多表、索引、事务、视图和触发。
@2.1.1 SQLite的数据类型,是无数据类型的数据库
支持的数据类型:
INTEGER(有符号的整数类型)
REAL(浮点类型)
TEXT(字符串类型,采用UTF-8,UTF-16)
BLOB(二进制大对象类型,能够存放任意二进制数据)
@2.1.2 Python数据类型与SQLite数据类型的映射
Python数据类型 | SQLite数据类型 |
---|---|
None | NULL |
int | INTEGRE |
float | REAL |
str | TEXT |
bytes | BLOB |
@2.1.3 使用GUI管理工具管理SQLite数据库
如DB Browser for SQLite。
自行下载安装,打开后如下图
1. 创建数据库
2.创建数据表
3.执行SQL语句
4.浏览数据
2.2 数据库编程的基本操作
数据库编程主要分为两类:查询(Read)和修改(C插入,U更新,D删除)
查询数据和修改数据
2.3 sqlite3模块API(使用此模块访问数据库)
@ 2.3.1 数据库连接对象Connection
访问第一步是数据库连接
通过connect(database)函数建立数据库连接,参数database是SQLite数据库的文件路径,连接成功,返回数据库连接对象Connection。
Connection有如下重要方法:
close()关闭数据库连接,关闭之后再使用数据库连接将引发异常
commit()提交数据库事务
rollback()回滚数据库事务
cursor()获得Cursor游标对象
@ 2.3.2 游标对象Cursor
一个Cursor游标对象表示一个数据库游标,游标暂时保存了SQL操作所影响到的数据。游标是通过数据库连接创建的。
游标Cursor对象有很多方法和属性,其中的基本SQL操作方法如下:
execute(sql[,parameters]):执行一条SQL语句,sql是SQL语句 ,parameters是为SQL提供的参数,可以是序列或字典类型。返回值是 整数,表示执行SQL语句影响的行数。
executemany(sql[,seq_of_params]):执行批量SQL语句,sql是S QL语句,seq_of_params是为SQL提供的参数,seq_of_params是序列。 返回值是整数,表示执行SQL语句影响的行数。
在通过execute()和executemany()方法执行SQL查询语句后, 还要通过提取方法从查询结果集中返回数据,相关提取方法如下:
fetchone():从结果集中返回只有一条记录的序列,如果没有数 据,则返回None。
fetchmany(size=cursor.arraysize):从结果集中返回小于等于size 记录数的序列,如果没有数据,则返回空序列,size在默认情况下是整 个游标的行数。
fetchall():从结果集中返回所有数据。
2.4 数据库的CRUD操作示例
@2.4.1 数据插入(Creat)
数据插入操作的SQL语句INSERT,代码如下:
import sqlite3 # 导入sqlite3模块
import os# 数据库文件路径
db_path = r'D:\桌面文件\DB\新建数据库的相关文件\school_db.db'# 检查文件是否存在
if not os.path.exists(db_path):print(f"数据库文件 {db_path} 不存在!")
i_name = input('请输入姓名:') # 获取用户输入的姓名
i_sex = input('请输入性别(1表示男,0表示女):') # 获取用户输入的性别
i_birthday = input('请输入生日(YYYYMMDD):') # 获取用户输入的生日try:# 连接到SQLite数据库con = sqlite3.connect(r'D:\桌面文件\DB\新建数据库的相关文件\school_db.db')# 创建一个Cursor对象,用于执行SQL命令cursor = con.cursor()# 执行SQL查询操作sql = 'INSERT INTO student(s_name, s_sex, s_birthday) VALUES (?, ?, ?)'cursor.execute(sql, [i_name, i_sex, i_birthday]) # 执行SQL命令,参数放到序列或元组中# 提取数据库事务con.commit()print('插入成功!')except sqlite3.Error as e:print('插入数据失败:{}'.format(e))# 回滚数据库事务con.rollback()finally:# 关闭游标if cursor:cursor.close()# 关闭数据库连接if con:con.close()
@2.4.2 数据查询(Read)
SQL查询语句是SELECT,根据是否带有WHERE子句,分为:无条件查询和有条件查询
***********无条件查询,没有WHERE子句**********,代码如下:
import sqlite3 # 导入sqlite3模块
import os# 数据库文件路径
db_path = r'D:\桌面文件\DB\新建数据库的相关文件\school_db.db'# 检查文件是否存在
if not os.path.exists(db_path):print(f"数据库文件 {db_path} 不存在!")try:# 连接到SQLite数据库con = sqlite3.connect(r'D:\桌面文件\DB\新建数据库的相关文件\school_db.db')# 创建一个Cursor对象,用于执行SQL命令cursor = con.cursor()# 执行SQL查询操作sql = 'SELECT s_id, s_name, s_sex, s_birthday FROM student'cursor.execute(sql) # 执行SQL命令# 提取结果集result_set = cursor.fetchall()for row in result_set:print('学号:{0} - 姓名:{1} - 性别:{2} - 生日:{3}'.format(row[0], row[1], row[2], row[3]))except sqlite3.Error as e:print('数据库查询发生错误:{}'.format(e))finally:# 关闭游标if cursor:cursor.close()# 关闭数据库连接if con:con.close()
*************有条件查询**************有WHERE子句,WHERE子句是查询条件,
代码如下:
# 有条件查询,有WHERE子句,WHERE自己是查询条件
import sqlite3 # 导入sqlite3模块
import os# 数据库文件路径
db_path = r'D:\桌面文件\DB\新建数据库的相关文件\school_db.db'# 检查文件是否存在
if not os.path.exists(db_path):print(f"数据库文件 {db_path} 不存在!")istr = input('请输入生日(YYYYMMDD):') # 获取用户输入的生日try:# 连接到SQLite数据库con = sqlite3.connect(r'D:\桌面文件\DB\新建数据库的相关文件\school_db.db')# 创建一个Cursor对象,用于执行SQL命令cursor = con.cursor()# 执行SQL查询操作sql = 'SELECT s_id, s_name, s_sex, s_birthday FROM student WHERE s_birthday < ?' # 查询学生信息cursor.execute(sql, [istr]) # 执行SQL命令,参数放到序列或元组中# 提取结果集result_set = cursor.fetchall()for row in result_set:print('学号:{0} - 姓名:{1} - 性别:{2} - 生日:{3}'.format(row[0], row[1], row[2], row[3]))except sqlite3.Error as e:print('数据库查询发生错误:{}'.format(e))finally:# 关闭游标if cursor:cursor.close()# 关闭数据库连接if con:con.close()
@2.4.3 数据更新(Update)
数据更新操作的SQL语句是UPDATE。示例如下:
import sqlite3 # 导入sqlite3模块
import os# 数据库文件路径
db_path = r'D:\桌面文件\DB\新建数据库的相关文件\school_db.db'# 检查文件是否存在
if not os.path.exists(db_path):print(f"数据库文件 {db_path} 不存在!")
i_id = input('请输入学号:') # 获取用户输入的学号
i_name = input('请输入姓名:') # 获取用户输入的姓名
i_sex = input('请输入性别(1表示男,0表示女):') # 获取用户输入的性别
i_birthday = input('请输入生日(YYYYMMDD):') # 获取用户输入的生日try:# 连接到SQLite数据库con = sqlite3.connect(r'D:\桌面文件\DB\新建数据库的相关文件\school_db.db')# 创建一个Cursor对象,用于执行SQL命令cursor = con.cursor()# 执行SQL查询操作sql = 'UPDATE student SET s_name=?, s_sex=?, s_birthday=? WHERE s_id=?'cursor.execute(sql, [i_name, i_sex, i_birthday, i_id]) # 执行SQL命令,参数放到序列或元组中# 提取数据库事务con.commit()print('更新数据库成功')except sqlite3.Error as e:print('更新数据库失败:{}'.format(e))# 回滚数据库事务con.rollback()finally:# 关闭游标if cursor:cursor.close()# 关闭数据库连接if con:con.close()
@2.4.4数据删除(Delete)
数据删除操作SQL语句是DELETE。示例如下:
import sqlite3 # 导入sqlite3模块
import os# 数据库文件路径
db_path = r'D:\桌面文件\DB\新建数据库的相关文件\school_db.db'# 检查文件是否存在
if not os.path.exists(db_path):print(f"数据库文件 {db_path} 不存在!")
i_id = input('请输入要删除学生的学号:') # 获取学号try:# 连接到SQLite数据库con = sqlite3.connect(r'D:\桌面文件\DB\新建数据库的相关文件\school_db.db')# 创建一个Cursor对象,用于执行SQL命令cursor = con.cursor()# 执行SQL查询操作sql = 'DELETE FROM student WHERE s_id=?'cursor.execute(sql, [i_id]) # 执行SQL命令,参数放到序列或元组中# 提取数据库事务con.commit()print('删除数据成功')except sqlite3.Error as e:print('删除数据失败:{}'.format(e))# 回滚数据库事务con.rollback()finally:# 关闭游标if cursor:cursor.close()# 关闭数据库连接if con:con.close()
可以看到下图s_id=5的学生张三被删除
2.5 防止 SQL注入攻击
示例如下:
import sqlite3 # 导入sqlite3模块
import os# 数据库文件路径
db_path = r'D:\桌面文件\DB\新建数据库的相关文件\school_db.db'# 检查文件是否存在
if not os.path.exists(db_path):print(f"数据库文件 {db_path} 不存在!")istr = input('请输入生日(YYYYMMDD):') # 获取用户输入的生日try:# 连接到SQLite数据库con = sqlite3.connect(r'D:\桌面文件\DB\新建数据库的相关文件\school_db.db')# 创建一个Cursor对象,用于执行SQL命令cursor = con.cursor()# 执行SQL查询操作
# sql = 'SELECT s_id, s_name, s_sex, s_birthday FROM student WHERE s_birthday < ?' # 查询学生信息
# cursor.execute(sql, [istr]) # 执行SQL命令,参数放到序列或元组中sql = 'SELECT s_id, s_name, s_sex, s_birthday FROM student WHERE s_birthday < ' + istr # 查询学生信息,这种方式容易造成,SQL注入攻击cursor.execute(sql) # 执行SQL命令,参数放到序列或元组中# 提取结果集result_set = cursor.fetchall()for row in result_set:print('学号:{0} - 姓名:{1} - 性别:{2} - 生日:{3}'.format(row[0], row[1], row[2], row[3]))except sqlite3.Error as e:print('数据库查询发生错误:{}'.format(e))finally:# 关闭游标if cursor:cursor.close()# 关闭数据库连接if con:con.close()
图一是查询20050101之前的
图二SQL注入是查询所有数据,如果是删除,损失可想而知!!!!