Python 中数据存储的方式和其他语言没什么区别,主要分为两个方面:文件存储和数据库存储。
文件存储
文件存储的方法也分为很多种,主要包括:
- Python 内置方法
- NumPy 模块方法
- os 模块方法
- csv 模块方法
Python 内置方法
在不需要借助任何外界库的前提下,python 内置方法其实也可以完成我们需要的文件存取任务:
open() 方法
file object = open(file_name [, access_mode][, buffering])
该方法意义在于按照指定模式打开文件,其中,各个参数的含义如下:
- file_name:file_name 变量是一个包含了你要访问的文件名称的字符串值。
- access_mode:access_mode决定了打开文件的模式:只读,写入,追加等(可选,默认为只读)。
- buffering: 如果 buffering 的值被设为 0,就不会有寄存。如果 buffering 的值取 1,访问文件时会寄存行。如果将 buffering 的值设为大于 1 的整数,表明了这就是的寄存区的缓冲大小。如果取负值,寄存区的缓冲大小则为系统默认。
简单示例:
1
2
3
4
5
| #!/usr/bin/python
# -*- coding: UTF-8 -*-
file = open('tttt.py')
print(file.read())
|
这是一个最简单的读取文件, 上面我们实际上使用的是一个相对路径,当然我们也可以使用绝对路径:
1
2
3
4
5
| #!/usr/bin/python
# -*- coding: UTF-8 -*-
file = open('C:\\Users\\Administrator\\Desktop\\tttt.py')
print(file.read())
|
我们常用 /
来表示相对路径,\
来表示绝对路径,上面的路径里 \\
是转义的意思。
接下来我们再来看看第二个参数如何使用,第二个参数是文件的打开模式,可用的模式有如下几个:
字符 | 意义 |
---|
r | 读取(默认) |
w | 写入,并先截断文件 |
x | 排它性创建,如果文件已经存在则失败 |
a | 写入,如果文件存在则在末尾追加 |
b | 二进制模式 |
t | 文本模式(默认) |
+ | 打开用于更新(读取与写入) |
默认模式为 r
(打开用于读取文本,与 rt
同义)。 模式 w+
与 w+b
将打开文件并清空内容。 模式 r+
与 r+b
将打开文件并不清空内容。
值得注意的是,打开一个文件的方式有两种,一种是字节流的方式,另一种则是已经编码的字符方式,根据你的具体需要而定。
1
2
3
4
5
6
7
8
9
10
| #!/usr/bin/python
# -*- coding: UTF-8 -*-
file = open('tttt.py', 'r+')
print(file.read())
file.write('dlc')
print(file.read())
file.close()
|
write()
方法可将任何字符串写入一个打开的文件。该方法不会在字符串的结尾添加换行符 \n
.
close()
方法刷新缓冲区里任何还没写入的信息,并关闭该文件。
除了这个内置函数外,Python 还有很多常用的内置函数:https://docs.python.org/zh-cn/3/library/functions.html#open
NumPy 模块方法
NumPy 是使用 Python 进行科学计算的基础软件包。除其他外,它包括:
- 功能强大的N维数组对象。
- 精密广播功能函数。
- 集成 C/C+ 和 Fortran 代码的工具。
- 强大的线性代数、傅立叶变换和随机数功能。
我们今天只关心它的一个特别的功能就是 I/O 操作,NumPy 可以读写磁盘上的文本数据或二进制数据。它有两个相关函数 load()
和 save()
.
1
2
3
4
5
6
7
8
9
| import numpy as np
a = np.array([1,2,3,4,5])
# 保存到 outfile.npy 文件上
np.save('outfile.npy',a)
# 保存到 outfile2.npy 文件上,如果文件路径末尾没有扩展名 .npy,该扩展名会被自动加上
np.save('outfile2',a)
|
NumPy还有两个常用的字符读写方法 loadtxt()
和 savetxt()
:
1
2
3
4
5
6
7
8
| import numpy as np
a=np.arange(0,10,0.5).reshape(4,-1)
#改为保存为整数,以逗号分隔
np.savetxt("a.txt",a,fmt="%d",delimiter=",")
#load时也要指定为逗号分隔
b = np.loadtxt("a.txt",delimiter=",")
print('b=\n',b)
|
os 模块方法
Python 的 os 模块封装了常见的文件和目录操作,官方文档:https://docs.python.org/3/library/os.path.html
常用的方法如下:
方法 | 说明 |
---|
os.mkdir | 创建目录 |
os.rmdir | 删除目录 |
os.rename | 重命名 |
os.remove | 删除文件 |
os.getcwd | 获取当前工作路径 |
os.walk | 遍历目录 |
os.path.join | 连接目录与文件名 |
os.path.split | 分割文件名与目录 |
os.path.abspath | 获取绝对路径 |
os.path.dirname | 获取路径 |
os.path.basename | 获取文件名或文件夹名 |
os.path.splitext | 分离文件名与扩展名 |
os.path.isfile | 判断给出的路径是否是一个文件 |
os.path.isdir | 判断给出的路径是否是一个目录 |
咱们着重看一下 os.write(fd, str)
方法和 os.read(fd,n)
:
os.read(fd,n)
fd − This is the file descriptor of the file(文件描述符).
n − These are n bytes from file descriptor fd(读几个字节).
1
2
3
4
5
6
7
8
9
10
| #!/usr/bin/python
# -*- coding: UTF-8 -*-
import os
file = os.open('tttt.py', os.O_RDWR | os.O_APPEND )
print(os.read(file, 10))
os.write(file, str.encode('dlc'))
print(os.read(file, 10))
os.close(file)
|
从这里我们其实可以看出,Python 内置的 read()
和 write()
方法更适合具体的文件读写,而 os 模块
更适合文件和目录的操作,各有侧重。
csv 模块方法
CSV 是逗号分割值的文件格式,其文件以纯文本的形式存储表格数据。 CSV 文件的每一行都用换行符分割,列与列之间用逗号分割,它可以用 Excel 打开。
例如我新建了一个 Excel 内容如下:
导出 csv 内容如下:
使用 csv 模块读出数据:
1
2
3
4
5
6
7
8
9
| #!/usr/bin/python
# -*- coding: UTF-8 -*-
import csv
with open('tttt.csv', 'r') as myFile:
lines = csv.reader(myFile)
for line in lines:
print(line)
|
这里使用到了 with
语句,详细可参考:https://www.ibm.com/developerworks/cn/opensource/os-cn-pythonwith/index.html
数据库存储
Python 标准数据库接口为 Python DB-API,Python DB-API 为开发人员提供了数据库应用编程接口。Python 数据库接口支持非常多的数据库,你可以选择适合你项目的数据库:
- GadFly
- mSQL
- MySQL
- PostgreSQL
- Microsoft SQL Server 2000
- Informix
- Interbase
- Oracle
- Sybase
操作 MySQL
MySQLdb 是 python 操作 mysql 数据库的一个库。mysql 的几乎所有的操作都可以实现。
安装方法:
1
| pip install MySQL-python
|
mysqlclient 是 MySQLdb 的 fork 版,增加了对 python 3.x 的支持和其它优化,推荐替代 MySQLdb.
首先需要安装 mysqlclient 库,连接 Python 和 MySQL. 本文出自水寒的博客:https://dp2px.com
1
| pip install mysqlclient
|
安装完成后我们可以尝试使用 Python 操作 MySQL,首先我们通过 Navicat 创建一个数据库:
官方文档地址:https://mysqlclient.readthedocs.io/
创建一个表,插入一条数据:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| #!/usr/bin/python
# -*- coding: UTF-8 -*-
import MySQLdb
conn = MySQLdb.connect(host='192.168.1.37', user='root', passwd='123456', db='lixiaoqiang')
cur = conn.cursor()
cur.execute("create table student(id int, name varchar(20), age varchar(10))")
cur.execute("insert into student values('1', 'XiaoMing', '18')")
cur.close()
conn.commit()
conn.close()
|
如果我们要更新这条数据,可以使用如下 SQL:
1
| delete from student where id = 1;
|
假如我们要修改则使用如下 SQL:
1
| update student set age = '19' where id = 1;
|
当然了,也可以使用占位符来插入数据:
1
2
3
4
5
6
7
8
9
| import MySQLdb
conn = MySQLdb.connect(host='192.168.1.37', user='root', passwd='123456', db='lixiaoqiang')
cur = conn.cursor()
sql = "insert into student values(%s, %s, %s)"
cur.execute(sql, (2, 'XiaoHong', '20'))
cur.close()
conn.commit()
conn.close()
|
你也可以使用占位符的方式一次插入多条数据,这个时候需要使用 executemany()
函数,例如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| #!/usr/bin/python
# -*- coding: UTF-8 -*-
import MySQLdb
conn = MySQLdb.connect(host='192.168.1.37', user='root', passwd='123456', db='lixiaoqiang')
cur = conn.cursor()
sql = "insert into student values(%s, %s, %s)"
cur.executemany(sql, [
(3, 'Tom', '21'),
(4, 'Jack', '23'),
(5, 'Heiwa', '24'),
(6, 'xiaoM', '26'),
(7, 'Yahei', '28'),
])
cur.close()
conn.commit()
conn.close()
|
接下来我们来看看如何查询表中的数据,查询数据需要使用 SQL 语句加 fetchone()
和 fetchmany()
函数:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| #!/usr/bin/python
# -*- coding: UTF-8 -*-
import MySQLdb
conn = MySQLdb.connect(host='192.168.1.37', user='root', passwd='123456', db='lixiaoqiang')
cur = conn.cursor()
cur.execute("select * from student")
print(cur.fetchone())
print(cur.fetchone())
print(cur.fetchone())
print(cur.fetchone())
cur.close()
conn.commit()
conn.close()
|
fetchone()
方法可以帮助我们获得表中的数据,可是每次执行 cur.fetchone()
获得的数据都不一样,换句话说我没执行一次,游标会从表中的第一条数据移动到下一条数据的位置,所以,我再次执行的时候得到的是第二条数据。
scroll(0,'absolute')
方法可以将游标定位到表中的第一条数据。还是没解决我们想要的结果,如何获得表中的多条数据并打印出来呢?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| #!/usr/bin/python
# -*- coding: UTF-8 -*-
import MySQLdb
conn = MySQLdb.connect(host='192.168.1.37', user='root', passwd='123456', db='lixiaoqiang')
cur = conn.cursor()
allexe = cur.execute("select * from student")
info = cur.fetchmany(allexe)
for item in info:
print(item)
cur.close()
conn.commit()
conn.close()
|
操作 MongoDB
很多时候我们爬取的数据都是 JSON 格式的,这个时候使用非关系型数据库 MongeDB 就会方便很多,它是非常流行的 NoSQL 数据库之一。
社区版是免费的,下载地址:https://www.mongodb.com/download-center
注册后去邮箱验证,然后登录去下载,有两个安装包,一个是服务另一个是仪表盘。
先安装好下面那个服务程序后会自动启动 mongodb 服务,此时你可以选择安装图形化仪表盘也可以不安装,仪表盘如下:
创建一个 Database 和一个表 student 如下:
紧接着我们使用 pymongo 来查询这条数据:
1
2
3
4
5
6
7
8
9
10
11
12
| #!/usr/bin/python
# -*- coding: UTF-8 -*-
from pymongo import MongoClient
client = MongoClient('localhost', 27017)
db = client.testpython
collection = db.student
result = collection.find_one({'gender': 'man'})
print(result)
|
然后我们插入一条数据,再查询出所有数据:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| #!/usr/bin/python
# -*- coding: UTF-8 -*-
from pymongo import MongoClient
client = MongoClient('localhost', 27017)
db = client.testpython
collection = db.student
xiaogang = {"name": "xiaogang", "age": 20, "gender": "woman"}
collection.insert_one(xiaogang)
result = collection.find()
for item in result:
print(item)
|
还记得我们上一篇 《Python 的网络请求 Requests 模块使用》 的爬取豆瓣Top250 的案例吗,我们接下来尝试将爬取的数据存入 MongoDB 数据库:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
| #!/usr/bin/python
# -*- coding: UTF-8 -*-
import requests
from bs4 import BeautifulSoup
from pymongo import MongoClient
headers = {
'user-agent' : 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36
(KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36',
'Host': 'movie.douban.com'
}
def getMovieData():
movies = []
for i in range(0, 10):
link = 'https://movie.douban.com/top250?start=' + str(i * 25) + '&filter='
r = requests.get(link, headers=headers, timeout=3)
print("响应状态码:", r.status_code)
soup = BeautifulSoup(r.text, "lxml")
div_list = soup.find_all('div', class_='item')
for each in div_list:
movieimg = each.find('div', class_='pic').a.img['src'].strip()
moviename = each.find('div', class_='hd').a.span.text.strip()
moviestar = each.find('span', class_='rating_num').text.strip()
movie = {'name': moviename, 'img': movieimg, 'star': moviestar}
movies.append(movie)
return movies
def insertDB(movies):
client = MongoClient('localhost', 27017)
db = client.testpython
collection = db.movie
collection.insert_many(movies)
movies = getMovieData()
print("爬取成功,开始写入数据库")
insertDB(movies)
print("写入数据库成功")
|