python3爬虫实践(一)——python3基本知识之文件与数据库存储

python3基本知识

1. 数据类型
  • python 中常见的数据类型有数、字符串、列表(list)、元组(tuple)、集合(set)、字典(dictionary)。除此之外,还可以自己自定义数据类型(自定义类)。
普通的数,比如1、2…
字符串双(单)引号引起来的数据
列表用“[]”表示,多个元素之间用逗号隔开,取值用下标表示,下标从 0 开始;列表的元素是可以重新赋值的
元组用“()”表示,多个元素之间用逗号隔开,取值用下标表示,下标从 0 开始;列表的元素是不可以重新赋值的
字典格式为:{键:值,键:值,键:值,…},取值用下标表示,下标用键表示,表示为:字典[键名]
集合作用是去重,例如:e=set(“aaabb”) --> e={“a”,“b”} ;集合数据类型可以用差并级运算
2. TXT 文本存储
  • 先看一个代码例子:
file = open('XXX.txt','a',encoding = 'utf-8')
file.write('XXX')
file.close()
  • 利用 Python 提供的 open() 方法打开一个文本文件,获取一个文件操作对象,这里赋值为 file ,接着利用 file 对象的 write() 方法将内容写入文件,最后调用 close() 方法将其关闭。open 方法的第一个参数是存储目标文件名称,第三个参数是文件的编码方式,第二个参数是打开文本的方式,下面介绍几种常用的文件打开方式。
a以追加的方式打开一个文件。如果文件已经存在,文件指针将会放在文件结尾,即新的内容将会写入到已有内容之后。如果文件不存在,则创建新文件写入
ab以二进制追加方式打开一个文件。如果文件已经存在,文件指针将会放在文件结尾,即新的内容将会写入到已有内容之后。如果文件不存在,则创建新文件写入
w以写入方式打开文件。如果文件已存在,则将其覆盖。如果不存在,则创建新文件
wb以二进制写入方式打开文件。如果文件已存在,则将其覆盖。如果不存在,则创建新文件
r以只读方式打开文件。文件的指针将会放在文件的开头。这是默认模式
rb以二进制只读方式打开文件。文件的指针将会放在文件的开头
  • TXT 文件写入还有一种方法,那就是使用 with as 语法。在 with 控制块结束时,文件自动关闭,所以不需要在调用 close 语法了。代码如下:
with open('XXX.txt','a',encoding = 'utf-8') as file:
	file.write('XXX')
3. CSV 文件存储

(1)写入

  • 先看一个代码例子:
import csv

with open('XXX.txt','w',encoding = 'utf-8') as csvfile:
	writer = csv.writer(csvfile)
	writer.writerow(['id','name',age'])
	writer.writerow(['1001','Jack',12])
	writer.writerow(['1002','李四',11])
	writer.writerow([['1003','李四',12],['1004','李四',13]])		#多行一起写入
  • 文本的打开方式和 TXT 的一样可以更改。如果想修改列与列之间的分隔符(上面代码是逗号作为分隔符),可以传入 delimiter 参数,代码如下:
import csv

with open('XXX.txt','w',encoding = 'utf-8') as csvfile:
	writer = csv.writer(csvfile,delimiter = ' ')		#以空格为分隔符
	writer.writerow(['id','name',age'])
	writer.writerow(['1001','Jack',12])
	writer.writerow(['1002','李四',11])
  • 一般情况下,爬虫爬取的都是结构化数据,我们一般会用字典来表示。在 csv 库中也提供了字典的写入方式,代码如下:
import csv

with open('XXX.csv','w',encoding = 'utf-8') as csvfile:
	writer = csv.writer(csvfile,fieldnames = fieldnames)		
	writer.writeheader()
	writer.writerow({'id':'1001','name':'Jack','age':12})
	writer.writerow({'id':'1002','name':'Mack','age':11})

(2)读取

  • 先看一个代码例子:
import csv

with open('XXX.csv','r',encoding = 'utf-8') as csvfile:
	reader = csv.reader(csvfile)
	for row in reader:
		print(row)
  • 构造一个 reader 对象,通过遍历输出每行的内容。另外,如果接触过 pandas 的话,可以利用 read_csv() 方法将数据从 csv 文件中读取出来,代码如下:
import pandas as pd

df = pd.read_csv('XXX.csv')
print(df)
4. 关系型数据库存储
  • 关系数据模型有多种,这里主要介绍 Python3 下的 MySQL 的存储,使用的库是 PyMySQL。

(1)连接数据库

  • 首先尝试连接一下数据库。假设当前的 MySQL 运行在本地,用户名为 root,密码为123456,运行端口为3306。先利用 PyMySQL 连接 MySQL,然后创建一个新的数据库,名字为 spiders,代码如下:
import pymysql

bd = pymysql.connect(host = 'localhost',user = 'root',password = '123456',port = 3306)
cursor = db.cursor()
cursor.execute('SELECT VERSION()')
data = cursor.fetchone()
print('Database version:',data)
cursor.execute("CREATE DATABASE spiders DEFAULT CHARACTER SET utf8")
db.close()
  • 在 connect 方法的 host 参数中,本地运行数据库,传入 localhost 即可,远程运行需传入其公网 ip 地址。连接成功后,需要在调用 cursor 方法获得 MySQL 的操作游标,利用游标来执行 SQL 语句。这里我们执行了两句 SQL,直接用 ececute 方法执行即可。第一句 SQL 用于获取 MySQL 当前版本,fetchone 方法获取第一条数据,即版本号。第二句 SQL 执行创建新数据库的操作,数据库名为 spiders,默认编码为 UTF-8。

(2)创建表

  • 先看一个代码例子:
import pymysql

bd = pymysql.connect(host = 'localhost',user = 'root',password = '123456',port = 3306,db = 'spiders')
sql = 'CREATE TABLE IF NOT EXISTS students (id VARCHAR(255) NOT NULL,name VARCHAR(255) NOT NULL,age INT NOT NULL,PRIMARY KEY(id))'
cursor = db.cursor()
cursor.execute(sql)
db.close()
  • 新创建一个数据表 students,sql 就是标准的 SQL 语句。

(3)插入数据

  • 先看一个代码例子:
import pymysql

id = '20120001'
user = 'Bob'
age = 20
db = pymysql.connect(host = 'localhost',user = 'root',password = '123456',port = '3306',db = 'spiders')
cursor = db.cursor()
sql = 'INSERT INTO students(id,name,age) values(%s,%s,%s)'
try:
	cursor.execute(sql,(id,name,age))
	db.commit()
except:
	#异常处理,执行失败调用 rollback 方法执行数据回滚,相当于什么都没发生
	db.rollback()		
db.close()
  • 代码中值得注意的是,需要执行 db 对象的 commit 方法才实现数据插入,这个方法才是真正将语句提交到数据库执行的方法,对于数据插入、更新、删除操作,都需要调用该方法才能生效。这里涉及到事务的原子性问题,commit 和 roolback 方法为事务的实现提供了支持。
  • 上面的插入方法也有不便的地方,比如要添加新的属性时,就要改写 sql 语句,相应的元组参数((id,name,age))也需要更改。在很多情况下,我们要达到的效果是插入方法无需改动,做一个通用的方法,只需要传入一个动态变化的字典就好,代码如下:
data = {
	'id':'20120001'
	'name':'Bob'
	'age':20
}
table = 'students'
keys = ','.join(data.keys())
values = ','.join(['%s']*len(data))
sql = 'INSERT INTO {table}({keys}) VALUES ({values})'.format(table = table,keys = keys,values = values)
try:
	if cursor.execute(sql,tuple(data.valus())):
		print('Successful')
		db.commit()
except:
	print('Failed')
	db.rollback()
db.close()
  • 这个是动态构造 sql 语句,不需要再去修改 sql 语句和插入操作,只需要传入一个字典数据就可以了。

(4)更新数据

  • 先看一个代码例子:
sql = 'UPDATE students SET age = $s WHERE name = %s'
try:
	cursor.execute(sql,(25,'Bob'))
	db.commit()
except:
	db.rollback()		
db.close()
  • 上面是一个最简单的更新数据的 sql 语句,同样用占位符 %s 的方式构造,然后执行 execute 方法,传入元组形式的参数。但是在实际的操作中我们还需要考虑其他问题,比如去重,如果数据存在,则更新数据,如果数据不存在,这插入数据,代码如下:
data = {
	'id':'20120001'
	'name':'Bob'
	'age':21
}
table = 'students'
keys = ','.join(data.keys())
values = ','.join(['%s']*len(data))
sql = 'INSERT INTO {table}({keys}) VALUES ({values}) ON DUPLICATE KEY UPDATE'.format(table = table,keys = keys,values = values)
update = ','.join(["{keys} = %s".format(kry = key) for key in data])
sql += update
try:
	if cursor.excute(sql,tuple(data.values())*2):
		print('Successful')
		db.commit()
except:
	print('Failed')
	db.rollback()
db.close()
  • 这里构造的其实是插入语句,但是我们在后面加了 ON DUPLICATE KEY UPDATE。这行代码的意思是如果主键(id)已经存在,就执行更新操作。

(5)删除数据

  • 删除操作相对简单,直接使用 DELETE 语句即可,只是需要指定要删除的目标表名和删除条件,而且仍然需要使用 db 和 commit 方法才能生效,代码如下:
table = 'students'
condition = 'age > 20'
sql = 'DELETE FROM {table} WHERE {condition}'.format(table = table,condition = condition)
try:
	cursor.execute(sql)
	db.commit()
except:
	db.rollback()
db.close()
  • 判断条件可以很复杂也可以很简单,注意这里直接将条件当作字符串来传递,以实现删除操作。

(6)查询数据

  • 先看一个代码例子:
sql = 'SELECT * FROM students WHERE age >= 20'
try:
	cursor.execute(sql)
	# 输出查询得到的结果个数
	print('Count:',cursor.rowcount)
	# 取出结果中的第一个数据
	one = cursor.fetchone()
	print('One:',one)
	# 取出结果中第二个及剩下的数据
	results = cursor.fetchall()
	print('Results:',results)
	# 输出元组的存储方式
	print('Results Type:',type(results))
	for row in results:
		print(row)
except:
	print('Error')
  • 调用 fetchone 方法可以获取结果的第一条数据,返回结果是元组形式。调用 fetchall 方法可以获取结果的全部数据,但是这个全部数据是剩下的全部数据。
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值