Python爬虫之数据的存储

数据的存储

一、TXT文本文件存储

TXT文本几乎兼容任何平台,缺点就是不利于检索

1、实例

import re

import requests
from pyquery import PyQuery as pq

url = 'https://ssr1.scrape.center/'
html = requests.get(url).text	# 用requests库提取网站首页的HTML代码
doc = pq(html)
items = doc('.el-card').items()	# 用pyquery库将电影的名称、类别、上映时间、评分信息提取出来。

file = open('moives.txt','w',encoding='utf-8')
for item in items:
    # 电影名称
    name = item.find('a > h2').text()
    file.write(f'名称:{name}\n')
    # 类别
    categories  = [item.text() for item in item.find('.categories button span').items()]
    file.write(f'类别:{categories}\n')
    # 上映时间
    published_at = item.find('.info:contains(上映)').text()
    published_at = re.search('(\d{4}-\d{2}-\d{2})',published_at).group(1) \
    if published_at and re.search('\d{4}-\d{2}-\d{2}',published_at) else None
    file.write(f'上映时间:{published_at}\n')
    score = item.find('p.score').text()
    file.write(f'{"=" * 50}\n')
file.close()

# open方法的第一个参数是要保存的目标文件名称;第二个参数代表数据以何种方式写入文本,此处为w,表示以覆盖的方式写入;第三个参数指定了文件的编码为utf-8

2、打开方式

  • r:以只读方式打开一个文件,意思是只能读取内容,而不能写入。这也是默认方式
  • rb:以二进制只读方式打开一个文件,通常用于打开二进制文件,例如音频、图片。视频等。
  • r+:以读写方式打开一个文件,既可以读文件又可以写文件。
  • rb+:以二进制读写方式打开一个文件、同样既可以读又可以写。
  • w:以写入方式打开一个文件。若存在则覆盖。不存在则创建。
  • wb:二进制的写入。
  • w+:以读写方式打开一个文件,若存在则覆盖。不存在则创建
  • wb+:二进制的读写。
  • a:以追加方式打开一个文件,存在则追加,不存在则创建。
  • ab:二进制追加。
  • a+:以读写方式打开一个文件,存在则追加,不存在则创建
  • ab+:二进制的读写追加方式

3、简化写法

with open('moives.txt','w',encoding='utf-8') as file:
    file.write(f'名称:{name}\n')
    file.write(f'类别:{categories}\n')
    file.write(f'上映时间:{published_at}\n')
    file.write(f'评分:{score}\n')

二、JSON文件存储

JSON,全称:JavaScript Object Notation,也就是JavaScript对象标记,通过对象和数组的组合来表示数据,是一种轻量级的数据交换方式

1、对象和数组

  • 对象在JavaScript中是指用花括号{}包围起来的内容,数据结构是{key1:value1,key2:value2,…}这种键值对结构。在面向对象的语言中,key表示对象的属性,value表示属性对应的值,前者可以使用整数和字符串表示,后者可以是任意类型。
  • 数组在JavaScript中是指用[]包围起来的内容,数据结构是[“java”,“javascript”,“vb”,…]这种索引结构。
# 这是一个JSON对象
[{
	"name":"Bob",
	"gender":"male",
	"birthday":"1992-10-18"
},{
	"name":"Selina",
	"gender":"female",
	"birthday":"1995-10-18"
}]

2、读取JSON

可以调用JSON库中的loads方法将JSON文本字符串转为JSON对象。实际上,JSON对象就是Python中列表和字典的嵌套与组合。反过来,我们可以通过dumps方法将JSON对象转为文本字符串。

print(type(str))	# <class 'str'>
data = json.loads(str)
print(data)	
print(type(data))	# <class 'list'> 列表类型

可以用索引取值:

data[0]['name']
data[0].get('name')
# 推荐使用get方法,即使键名不存在也不会报错。
  • 注意、JSON的数据需要用双引号包围起来,而不能使用单引号。
# 读取JSON文本文件 法1:
with open('data.json',encoding='utf-8') as file:
    str = file.read()
    data = json.loads(str)
    print(data)
    
# 读取JSON文本文件 法2:
data = json.load(open('data.json',encoding='utf-8'))
print(data) 

3、输出JSON

调用dumps方法将JSON对象转化为字符串。

import json

data = [{
    'name':'Bob',
    'gender':'male',
    'birthday':'1992-10-18'
}]
with open('data.json','w',encoding='utf-8') as file:
    file.write(json.dumps(data))
  • 若想保存JSON对象的缩进格式,可以再往dumps方法中添加一个参数indent,代表缩进字符的个数。
with open('data.json','w',encoding='utf-8') as file:
    file.write(json.dumps(data,indent=2))

要想输出中文,还需要指定参数ensure_ascii为False,以及规定文件输出的编码:

with open('data.json','w',encoding='utf-8') as file:
    file.write(json.dumps(data,indent=2,ensure_ascii=False))

三、CSV文件存储

CSV,全称Comma-Separated Values,中文叫做逗号分隔值或字符分隔值,其文件以纯文本形式****存储表格数据

1、写入

import csv

with open('data.csv','w') as csvfile:	# 打开data.csv文件,指定模式为写入。
    writer = csv.writer(csvfile)		# 使用csv库的writer方法初始化对象
    writer.writerow(['id','name','age'])# 调用writerow方法传入每行的数据
    writer.writerow(['10001','Mike','20'])
    writer.writerow(['10002','Bob','22'])
    writer.writerow(['10003','Jordan','21'])
  • 若要修改列与列之间的分隔符,传入delimiter参数
with open('data.csv','w') as csvfile:
    writer = csv.writer(csvfile,delimiter=' ')
    writer.writerow(['id','name','age'])
  • 也可调用writerows写入多行,此时参数需要传入二维列表:
with open('data.csv','w') as csvfile:
    writer = csv.writer(csvfile)
    writer.writerow(['id','name','age'])
    writer.writerow([['10001','Mike','20'],['10002','Bob','22'],['10003','Jordan','21']])
  • 一般情况下,爬虫爬取到的都是结构化数据,我们一般会用字典表示这种数据。csv也提供了字典的写入方式。
with open('data.csv','w') as csvfile:
    fieldnames = ['id','name','age']
    writer = csv.DictWriter(csvfile,fieldnames=fieldnames)
    writer.writeheader()
    writer.writerow({'id':'10001','name':'Mike','age':'20'})
    writer.writerow({'id':'10002','name':'Bob','age':'22'})
    writer.writerow({'id':'10003','name':'Jordan','age':'21'})
    
# 需要追加模式则w改为a
# 要写入中文则,添加编码格式encoding='utf-8' 

2、读取

with open('data.csv','r',encoding='utf-8') as csvfile:
    reader = csv.reader(csvfile)
    for row in reader:
        print(row)

四、MySql存储

  • 关系型数据库是基于关系模型的数据库,而关系模型是通过二维表来保存的,所以关系型数据库中数据的存储方式就是行列组成的 表,每一列代表一个字段,每一行代表一条记录。
  • 表可以看做某个实体的集合,实体之间存在的联系需要通过表与表之间的关联关系体现。

1、准备工作

pip3 install pymysql

2、连接数据库

import pymysql

db = pymysql.connect(host='127.0.0.1', user='root', password='password', port=3306)
cursor = db.cursor()
cursor.execute('SELECT VERSION()')
data = cursor.fetchone()
print('Database version:', data)

# 创建数据库
cursor.execute("CREATE DATABASE spiders DEFAULT CHARACTER SET utf8mb4")
db.close()

# 通过pymysql的connect方法声明了一个MySQL对象db,传入MySQL运行的host、user(用户名)、password(密码)、port(端口号)。
# 连接成功后,调用cursor方法获得MySQL的操作游标,利用游标可以执行MySQL语句。
# 第一个SQL语句用于获得MySQL的当前版本,然后调用fetchone方法得到了第一条数据,即版本号
# 第二个SQL语句用于创建数据库spiders,默认编码为UTF-8。

3、创建表

db = pymysql.connect(host='127.0.0.1', user='root', password='password', port=3306,db= 'spiders')
cursor = db.cursor()
# 创建一个名为students的数据表
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()

4、插入数据

data = {
    'id': '20120001',
    'name': 'Bob',
    'age': 20
}
table = 'students'
keys = ','.join(data.keys())		# id,name,age
values = ','.join(['%s'] * len(data))	# %s,%s,%s
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:
    print('Failed')
    db.rollback()
db.close()

# 首先构造需要插入的字段:id,name和age。

5、更新数据

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(["{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()

6、删除数据

table = 'students'
condition = 'age > 20'
keys = ','.join(data.keys())
values = ','.join(['%s'] * len(data))
# 删除数据
sql = 'DELETE FROM {table} WHERE {condition}'.format(table=table,condition=condition)
try:
    cursor.execute(sql)
    print('Successful')
    db.commit()
except:
    print('Failed')
    db.rollback()
db.close()

7、查询数据

sql = 'SELECT * FROM students WHERE age >= 20'
try:
    cursor.execute(sql)
    print('Count:',cursor.rowcount)
    row = cursor.fetchone()
    while row:
        print('Row:',row)
        row = cursor.fetchone()
except:
    print('Error')

五、MongoDB存储

NoSQL,全称Not Only SQL,意为不仅仅是SQL,泛指非关系型数据库。NoSQL是基于键值对的,而且不需要经过SQL层的解析,数据之间没有耦合性,性能非常高。

  • 非关系型数据库又可以分为:
    • 键值存储数据库:代表有Redis、Voldemort、Oracle BDB等。
    • 列存储数据库:代表有Cassandra、HBase和Riak等。
    • 文档型数据库:代表有CouchDB和MongDB等。
    • 图形数据库:代表有NEO4J。infoGrid和Infinite Graph等。

因此,对于爬虫的数据存储来说,一条数据可能存在因某些字段提取失败而缺失的情况,而且数据可能随时调整。另外,数据之间还存在嵌套关系。如果使用关系型数据库,一是要提前建表,二是如果数据存在嵌套关系,还需要进行序列化操作才可以实现存储,这不方便。

MongDB是由C++语言编写的非关系型数据库,是一个基于分布式分拣存储的开源数据库系统,其内容的存储形式类似JSON对象。它的字段值可以包含其他文档、数组及文档数组,灵活。

六、Redis缓存存储

Redis是一个基于内存的高效的键值型非关系型数据库,存取效率极高,而且支持多种数据存储结构,使用起来也简单。

七、Elasticserach搜索引擎存储

这是一个全文搜索引擎,可以快速存储。搜索和分析海量数据。

八、RabbitMQ的使用

在爬取数据的过程中,可能需要一些进程间的通信机制:

  • 一个进程负责构造爬取请求,另一个进程负责执行爬取请求。
  • 某个数据爬取进程执行完毕,通知另一个负责数据处理的进程开始处理数据。
  • 某个进程新建了一个爬取任务,通知另一个负责数据爬取的进程开始爬取数据。

为了降低这些进程的耦合度,需要一个类似消息列队的中间件来存储和转发消息,实现进程间的通信。有了消息列队,以上各机制中的两个进程就可以独立执行,他们之间的通信则由消息列队实现。

  • 一个进程根据需要爬取的任务,构造请求对象并放入消息列队,另一个进程从列队中取出请求对象并执行爬取。
  • 某个数据爬取进程执行完毕,就向消息列队发送消息,当另一个负责数据处理的进程监听到这类消息时,就开始处理数据。
  • 某个进程新建了一个爬取任务后,就向消息列队发送消息,当另一个负责数据爬取的进程监听到这类消息时,就开始爬取数据。

RabbitMQ就是实现消息列队的消息列队中间件之一。

相关推荐

  1. Python爬虫数据存储

    2024-03-30 08:22:02       15 阅读
  2. Python爬虫关系型数据库存储#5

    2024-03-30 08:22:02       26 阅读
  3. Python爬虫非关系型数据库存储#5

    2024-03-30 08:22:02       41 阅读
  4. Pyhon爬虫Ajax数据爬取

    2024-03-30 08:22:02       21 阅读
  5. Python爬虫存储库安装

    2024-03-30 08:22:02       33 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-03-30 08:22:02       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-03-30 08:22:02       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-03-30 08:22:02       19 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-03-30 08:22:02       20 阅读

热门阅读

  1. C++ 让类只在堆或栈上分配

    2024-03-30 08:22:02       21 阅读
  2. 搭建vite+vue3项目时遇到的问题

    2024-03-30 08:22:02       19 阅读
  3. DG库怎样释放bigfile类型临时数据文件的空间

    2024-03-30 08:22:02       16 阅读
  4. flutter 保存一堆多语言翻译词条,由key和value组成

    2024-03-30 08:22:02       18 阅读
  5. Tomcat

    Tomcat

    2024-03-30 08:22:02      17 阅读
  6. MacOS安装Homebrew教程

    2024-03-30 08:22:02       16 阅读