用解析器解析出数据之后,接下来就是存储数据。保存数据的形式可以多种多样,最简单的形式是直接保存为文本文件,如txt,json,csv等。另外,还可以保存到数据库中,如关系数据库mysql,非关系数据库MongoDB、Redis等。
txt文件存储
import requests
from pyquery import PyQuery as pq
url='https://www.zhihu.com/explore'
headers={
"User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36"
}
html = requests.get(url,headers=headers).text
doc=pq(html)
items = doc('.explore-tab .feed-item').items()
for item in items:
question = item.find('h2').text()
author = item.find('.author-link-line').text()
answer = pq(item.find('.content').html()).text()
file = open('explore.txt','a',encoding='utf-8')#a表示在文件末尾追加
file.write('\n'.join([question,author,answer]))
file.write('\n'+'='*50+'\n')
file.close()
JSON文件存储
输出JSON
import json
data=[{
'name':'张三',
'gender':'男',
'birthday':'1995-10-10'
}]
with open('data.json','w') as file:
file.write(json.dumps(data,indent=2,ensure_ascii=False))
#indent=2,以缩进2格式存储
#ensure_ascii=False可以存储汉字
打开JSON
import json
with open('data.json','r') as file:
str = file.read()
data=json.loads(str)
print(data)
CSV文件
写文件
import csv
#py3不加newline='',每行会多一行空行
#w换成a可以追加
with open('data.csv','w',newline='') as csvfile:
writer = csv.writer(csvfile)
writer.writerow(['id','name','age'])
writer.writerow(['10001','Mike',20])
writer.writerow(['10002','Bob',22])
writer.writerow(['10003','张三','22'])
id,name,age
10001,Mike,20
10002,Bob,22
10003,张三,22
读文件
import csv
with open('data.csv','r') as csvfile:
reader = csv.reader(csvfile)
for row in reader:
print(row)
Mysql存储
数据库的四属性:
- 原子性
- 一致性:一个状态到另一个状态
- 隔离性:事务之间不干扰
- 持久性:事务一旦提交,永久改变
连接数据库
import pymysql
db = pymysql.connect(host='localhost',user='root',password='zhang110',port=3306)
cursor = db.cursor()
cursor.execute('SELECT VERSION()')
data = cursor.fetchone()
print('版本:',data)
cursor.execute("CREATE DATABASE spiders DEFAULT CHARACTER SET utf8")
db.close()
创建表
import pymysql
db = pymysql.connect(host='localhost',user='root',password='zhang110',port=3306,db='spiders')
cursor = db.cursor()
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.execute(sql)
db.close()
插入数据
import pymysql
db = pymysql.connect(host='localhost',user='root',password='zhang110',port=3306,db='spiders')
cursor = db.cursor()
id='0001'
user='张三'
age=20
sql='insert into students(id,name,age) values(%s,%s,%s)'
try:
cursor.execute(sql,(id,user,age))
db.commit()
except:
db.rollback()#如果失败,调用回滚,什么也不执行
db.close()
用字典数据插入:
import pymysql
db = pymysql.connect(host='localhost',user='root',password='zhang110',port=3306,db='spiders')
cursor = db.cursor()
data={
'id':'0002',
'name':'李四',
'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.values())):
print('Successful')
db.commit()
except:
db.rollback()
db.close()
更新数据
对于关键字相同的,不添加新数据,只更新数据。
import pymysql
db = pymysql.connect(host='localhost',user='root',password='zhang110',port=3306,db='spiders')
cursor = db.cursor()
data={
'id':'0002',
'name':'李四',
'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([" {key}=%s".format(key=key) for key in data])
sql+=update
try:
if cursor.execute(sql,tuple(data.values())*2):
print('Successful')
db.commit()
except:
print('Failed')
db.rollback()
db.close()
删除数据
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()
查询数据
import pymysql
db = pymysql.connect(host='localhost',user='root',password='zhang110',port=3306,db='spiders')
cursor = db.cursor()
sql='select * from students where age>20'
try:
cursor.execute(sql)
print('Count:',cursor.rowcount)
results=cursor.fetchall()
for row in results:
print(row)
except:
print('Error')
db.close()
fetall返回的是全部数据,内存开销很大,可以使用fetone+while逐条取数据:
sql='select * from students where age>20'
try:
cursor.execute(sql)
print('Count:',cursor.rowcount)
row=cursor.fetchone()
while row:
print(row)
row=cursor.fetchone()#指针后移
except:
print('Error')
db.close()
非关系数据库
对于爬虫的数据存储来说,一条数据可能存在某些字段提取失败而缺失的情况,而且数据可能随时调整,数据之间还存在嵌套关系。
如果使用关系型数据存储,一是需要提前建表,而是如果存在数据嵌套关系的话,需要进行序列化操作才可以进行存储,非常不方便。
更多详细方法,参见http://api.mongodb.com/python/current/api/pymongo/collection.html
MongoDB存储
MongoDB是C++编写的非关系数据库,是一个基于分布式文件存储的开源数据库系统。其内容存储形式类似JSON。
import pymongo
#client=pymongo.MongoClient('mongodb://localhost:27017/')
client = pymongo.MongoClient(host='localhost',port=27017)
#指定test数据库
db=client.test
#指定集合
collection=db.students
#删除全部数据
collection.delete_many({})
#插入数据
student={
'id':'0001',
'name':'张三',
'age':20,
'gender':'male'
}
result=collection.insert_one(student)
#插入多条数据
student1={
'id':'0002',
'name':'李四',
'age':21,
'gender':'male'
}
student2={
'id':'0003',
'name':'王五',
'age':20,
'gender':'male'
}
result=collection.insert_many([student1,student2])
#查询数据
result=collection.find_one({'name':'李四'})
print(result)
#多数据查询
result=collection.find({'age':20})
for it in result:
print(it)
使用正则表达式查询:
#查询以M开头的学生
result=collection.find({'name':{'$regex':'^M.*'}})
{'name':{'$regex':'^M.*'}} #name以M开头
{'name':{'$exists':True}} #name属性是否存在
{'age':{'$type':'int'}} #age类型为int
{'age':{'$mod':[5,0]}} #age取模5余数为0
{'$text':{'$search':'Mike'}} #包含Mike字符的文本
{'$where':'obj.fans_count==obj.follows_count'} #自身粉丝数等于关注数
统计
要统计多少条数据:
count=collection.find().count()
统计符合某条件的数据条数:
count=collection.find({'age':20}).count()
排序
result = collection.find().sort('name',pymongo.ASCENDING)#升序排列
偏移
忽略前几个条目:
#忽略前两条
result = collection.find().sort('name',pymongo.ASCENDING).skip(2)
限制条目数量
result = collection.find().limit(2)
更新数据
更新’张三’的年龄为25:
condition = {'name':'张三'}
student = collection.find_one(condition)
student['age'] = 25
result = collection.update_one(condition,{'$set':student})
查询年龄大于20的数据,进行加1处理:
condition = {'age':{'$gt':20}}
result = collection.update_mang(condition,{'$inc':{'age':1}})
删除数据
result = collection.remove('name':'张三')
推荐方法:
result = collection.delete_one({'name':'张三'})
result = collection.delete_many({'age':{'$lt':25}})
删除全部条目数据:
#删除全部数据
collection.delete_many({})
Redis存储
Redis是一个基于内存的高效的键值型非关系型数据库,存储效率高,而且支持多种存储数据结构。
from redis import StrictRedis
redis = StrictRedis(host='localhost',port=6379,db=0,password='')
redis.set('name','Tom')
print(redis.get('name'))
可以通过Redis管理工具查看添加的数据。