python爬虫之数据存储

1.文本存储

文件打开模式

python中所有open()打开一个文件,文件的打开有很多模式:

  • r:以只读方式打开文件,文件的指针将会放在文件的开头,这是默认模式。

  • rb:以二进制只读方式打开一个文件,文件指针将会放在文件的开头。

  • r+:以读写方式打开一个文件,文件指针将会放在文件的开头。

  • rb+: 以二进制读写方式打开一个文件,文件指针将会放在文件的开头。

  • w:以写入方式打开一个文件。如果该文件已存在,则将其瞿盖;如果该文件不存在,则创建新文件。

  • wb:以二进制写入方式打开一个文件。如果该文件已存在,则将其覆盖;如果该文件不存在,则创建新文件。

  • w+:以读写方式打开一个文件。如果该文件已存在,则将其覆盖;如果该文件不存在,则创建新文件。

  • wb+:以二进制读写格式打开一个文件。如果该文件已存在,则将其覆盖;如果该文件不存在, 则创建新文件。

  • a:以追加方式打开一个文件。如果该文件已存在,文件指针将会放在文件结尾。也就是说,新的内容将会被写入到已有内容之后;如果该文件不存在, 则创建新文件来写入。

  • ab:以二进制追加方式打开一个文件。如果该文件已存在,则文件指针将会放在文件结尾。也就是说,新的内容将会被写入到己有内容之后;如果该文件不存在,则创建新文件来写入。

  • a+:以读写方式打开一个文件。如果该文件已存在,文件指针将会放在文件的结尾。文件打开时会是追加模式;如果眩文件不存在,则创建新文件来读写。

  • ab+:以二进制追加方式打开一个文件。如果该文件已存在,则文件指针将会放在文件结尾;如果该文件不存在,则创建新文件用于读写。TXT 文本的操作非常简单,且其几乎兼容任何平台,但是它有个缺点,那就是不利于检索。

TXT 文本存储

以这个网站为例

第一章我要成为"龙骑士" _《诸天:从神雕开始长生不死!》小说在线阅读 - 起点中文网

一个简单的反调式例子,注入代码即可解决

经调试数据在网页上

有cookie效验,cookie会过期

python 复制代码
import requests
from scrapy import Selector

headers = {
    "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
    "accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
    "referer": "https://www.qidian.com/book/1044888053/",
    "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36 Edg/136.0.0.0"
}
cookies = {
    "_csrfToken": "p2zf6E8KXIBiku6iReLy5rOCBpdpNYOcVw2Dv9I9",
    "e1": "%7B%22l6%22%3A%22%22%2C%22l7%22%3A%22%22%2C%22l1%22%3A3%2C%22l3%22%3A%22%22%2C%22pid%22%3A%22qd_p_qidian%22%2C%22eid%22%3A%22qd_A73%22%7D",
    "e2": "%7B%22l6%22%3A%22%22%2C%22l7%22%3A%22%22%2C%22l1%22%3A8%2C%22l3%22%3A%22%22%2C%22pid%22%3A%22qd_p_qidian%22%2C%22eid%22%3A%22qd_A103%22%7D",
    "w_tsfp": "ltvuV0MF2utBvS0Q7aPtkU6mHjolfTA4h0wpEaR0f5thQLErU5mB2IJ/u8P/MnLX6sxnvd7DsZoyJTLYCJI3dwNGRZ6Wcd8Z2AXBxokj1NodAxFgF5/YXgEfJ7JxvjkTL3hCNxS00jA8eIUd379yilkMsyN1zap3TO14fstJ019E6KDQmI5uDW3HlFWQRzaLbjcMcuqPr6g18L5a5W7Ztg+teFNzUbJD2BCT1isfXS4n4RK8IOBUPUqscMarSqA="
}
url = "https://www.qidian.com/chapter/1044888053/842546862/"
response = requests.get(url, headers=headers, cookies=cookies)
print(response.text)

把cookie和请求头一起拿过来请求,请求成功

接下来提取数据

我用scrapy的Css选择去提取,如果你想用xpath或者beautifulsoup也行

python 复制代码
selector = Selector(text=response.text)
text_list = selector.css('[data-type = "cjk"]>p::text')
for txt in text_list:
    print(txt.get())

得出结果

接下来读入文本,模式采用a模式。以追加方式打开一个文件。如果该文件已存在,文件指针将会放在文件结尾。也就是说,新的内容将会被写入到已有内容之后;如果该文件不存在, 则创建新文件来写入。

发现好像没分行,所以读入前加一个换行符·

中文编码为utf-8

python 复制代码
response = requests.get(url, headers=headers, cookies=cookies)
selector = Selector(text=response.text)
text_list = selector.css('[data-type = "cjk"]>p::text')
for txt in text_list:
    with open('小说.txt', 'a', encoding='utf-8') as f:
        f.write(txt.get()+'\n')

结果如下:

2.json文件存储

JSON,全称为 JavaScript Object Notation, 也就是 JavaScript 对象标记,它通过对象和数组的组合来表示数据,构造简洁但是结构化程度非常高,是一种轻量级的数据交换格式。本节中,我们就来了解如何利用 Python 保存数据到 JSON 文件。

json模块方法

方法 作用
json.dumps() 把python对象转换成json对象的一个过程,生成的是字符串。
json.dump() 用于将dict类型的数据转成str,并写入到json文件中
json.loads() 将json字符串解码成python对象
json.load() 用于从json文件中读取数据。

以这个网站为例影片总票房排行榜

影片总票房排行榜,这网站很好爬的

python 复制代码
import requests
from scrapy import Selector
import json
headers = {
    "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36 Edg/136.0.0.0"
}
cookies = {
}
url = "https://piaofang.maoyan.com/rankings/year"
response = requests.get(url, headers=headers, cookies=cookies)
# print(response.text)
selector = Selector(text=response.text)
json_list = selector.css('#ranks-list>ul')
json_arr =[]
for json_str in json_list:
    json_obj = {}
    json_obj['movie_name'] = json_str.css('.first-line::text').get()
    json_obj['create_time'] = json_str.css('.second-line::text').get()
    json_obj['box_office'] = json_str.css('.col2.tr::text').get()
    print(json_obj)

运行成功

正常读入的话,中文字符都变成了 Unicode 字符,而且没换行非常不美观

为了让他美观可以指定参数 ensure_ascii 为 False,indent设为2

python 复制代码
json_arr =[]
for json_str in json_list:
    json_obj = {}
    json_obj['movie_name'] = json_str.css('.first-line::text').get()
    json_obj['create_time'] = json_str.css('.second-line::text').get()
    json_obj['box_office'] = json_str.css('.col2.tr::text').get()
    print(json_obj)
    json_arr.append(json_obj)
with open('data.json', 'a', encoding='utf-8') as file:
    file.write(json.dumps(json_arr,indent=2, ensure_ascii=False),)

结果如下:

3.表格文件数据存储

CSV,全称为 Comma-Separated Values,中文可以叫作逗号分隔值或字符分隔值,其文件以纯文本形式存储表格数据。该文件是一个字符序列,可以由任意数目的记录组成,记录间以某种换行符分隔。每条记录由字段组成,字段间的分隔符是其他字符或字符串,最常见的是逗号或制表符。不过所有记录都有完全相同的字段序列,相当于一个结构化表的纯文本形式。它比 Excel 文件更加简洁,XLS 文本是电子表格,它包含了文本、数值、公式和格式等内容,而 CSV 中不包含这些内容,就是特定字符分隔的纯文本,结构简单清晰。所以,有时候用 CSV 来保存数据是比较方便的。本节中,我们来讲解Python 读取和写入 CSV 文件的过程。

这里先看一个最简单的例子:

python 复制代码
import csv 
with open('data.csv', 'w') as csvfile: 
    writer = csv.writer(csvfile) 
    writer.writerow(['id', 'name', 'age']) 
    writer.writerow(['10001', 'Mike', 20]) 
    writer.writerow(['10002', 'Bob', 22]) 
    writer.writerow(['10003', 'Jordan', 21])

writer = csv.writer(csvfile)为定义csv写入对象

首先,打开 data.csv 文件,然后指定打开的模式为 w(即写入),获得文件句柄,随后调用 csv 库的writer 方法初始化写入对象,传入该句柄,然后调用 writerow 方法传入每行的数据即可完成写入。效果如下:

如果想修改列与列之间的分隔符,可以传入 delimiter 参数,其代码如下:

python 复制代码
import csv 
with open('data.csv', 'w') as csvfile: 
	writer = csv.writer(csvfile, delimiter=' ') 
	writer.writerow(['id', 'name', 'age']) 
	writer.writerow(['10001', 'Mike', 20]) 
	writer.writerow(['10002', 'Bob', 22]) 
	writer.writerow(['10003', 'Jordan', 21])

效果如下:

多行写入

python 复制代码
import csv 
with open('data.csv', 'w') as csvfile: 
	writer = csv.writer(csvfile) 
	writer.writerow(['id', 'name', 'age']) 
	writer.writerows([['10001', 'Mike', 20], ['10002', 'Bob', 22], ['10003', 'Jordan', 21]])

字典写入

python 复制代码
import 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})

fieldnames = ['id', 'name', 'age'] 写入表格

writer = csv.DictWriter(csvfile, fieldnames=fieldnames) ,定义写入对象,为字典写入

用以上网站为例子

python 复制代码
import requests
from scrapy import Selector
import csv
headers = {
    "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36 Edg/136.0.0.0"
}
cookies = {
}
url = "https://piaofang.maoyan.com/rankings/year"
response = requests.get(url, headers=headers, cookies=cookies)
# print(response.text)
selector = Selector(text=response.text)
json_list = selector.css('#ranks-list>ul')
json_arr =[]

for json_str in json_list:
    json_obj = {}
    json_obj['movie_name'] = json_str.css('.first-line::text').get()
    json_obj['create_time'] = json_str.css('.second-line::text').get()
    json_obj['box_office'] = json_str.css('.col2.tr::text').get()
    json_arr.append(json_obj)
with open('data.csv', 'a', encoding='utf-8') as csvfile:
    fieldnames = ['movie_name', 'create_time', 'box_office']
    writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
    writer.writeheader()
    writer.writerows(json_arr)

效果如下:

注意,字典的键和表的头要一致,如果你自定义标头,可以这样做

python 复制代码
# 自定义表头
custom_headers = ['影片名称', '上映时间', '票房收入(万元)']

with open('data.csv', 'a', encoding='utf-8', newline='') as csvfile:
    writer = csv.DictWriter(csvfile, fieldnames=custom_headers)
    writer.writeheader()
    for item in json_arr:
        writer.writerow({
            '影片名称': item['movie_name'],
            '上映时间': item['create_time'],
            '票房收入(万元)': item['box_office']
        })

4. MySQL存储

首要工作,创建数据库,建表,id为主键,自增长

python 复制代码
def create_table():
    db = pymysql.connect(host="localhost", user="root", password="12345", db="spider2")
    # 使用 cursor() 方法创建一个游标对象cursor
    cursor = db.cursor()
    # 使用预处理语句创建表
    sql = '''
    CREATE TABLE IF NOT EXISTS movie_list (
        idINT NOT NULL AUTO_INCREMENT,  
        movie_name VARCHAR(255) NOT NULL, 
        create_time VARCHAR(255) NOT NULL, 
        box_office VARCHAR(255) NOT NULL, 
        PRIMARY KEY (id))
    '''
    try:
        cursor.execute(sql)
        print("CREATE TABLE SUCCESS.")
    except Exception as ex:
        print(f"CREATE TABLE FAILED,CASE:{ex}")
    finally:
        # 关闭数据库连接
        db.close()
create_table()

创建成功

第二步准备插入数据

python 复制代码
def save_data(movie_name, create_time, box_office):
    db = pymysql.connect(host="localhost", user="root", password="12345", db="spider2")
    # 使用 cursor() 方法创建一个游标对象cursor
    cursor = db.cursor()
    # SQL 插入语句
    sql = 'INSERT INTO movie_list(id, movie_name, create_time, box_office) values(%s, %s, %s, %s)'
    # 执行 SQL 语句
    try:
        cursor.execute(sql, (0, movie_name, create_time, box_office))
        # 提交到数据库执行
        db.commit()
        print('数据插入成功...')
    except Exception as e:
        print(f'数据插入失败: {e}')
        # 如果发生错误就回滚
        db.rollback()

结果如下:

不过在插入数据我发现了一个问题 ,插入数据太慢了,最后发现,再插入数据的时候,还要链接一次,可以单独把连接数据库功能拿出来,这样优化。

python 复制代码
def save_data(cursor,db,movie_name, create_time, box_office):

    # SQL 插入语句
    sql = 'INSERT INTO movie_list(id, movie_name, create_time, box_office) values(%s, %s, %s, %s)'
    # 执行 SQL 语句
    try:
        cursor.execute(sql, (0, movie_name, create_time, box_office))
        # 提交到数据库执行
        db.commit()
        print('数据插入成功...')
    except Exception as e:
        print(f'数据插入失败: {e}')
        # 如果发生错误就回滚
        db.rollback()
python 复制代码
db = pymysql.connect(host="localhost", user="root", password="12345", db="spider2")
# 使用 cursor() 方法创建一个游标对象cursor
cursor = db.cursor()
for json_str in json_list:
    json_obj = {}
    json_obj['movie_name'] = json_str.css('.first-line::text').get()
    json_obj['create_time'] = json_str.css('.second-line::text').get()
    json_obj['box_office'] = json_str.css('.col2.tr::text').get()
    save_data(cursor,db,json_obj['movie_name'],json_obj['create_time'],json_obj['box_office'])

在面向对象里会比较方便,直接设置公有属性就好了

python 复制代码
self.db = pymysql.connect(host="localhost", user="root", password="12345", db="spider2")
# 使用 cursor() 方法创建一个游标对象cursor
self.cursor = db.cursor()

完整案例:

python 复制代码
import requests
from scrapy import Selector
import pymysql
#准备工作

def create_table():
    db = pymysql.connect(host="localhost", user="root", password="12345", db="spider2")
    # 使用 cursor() 方法创建一个游标对象cursor
    cursor = db.cursor()
    # 使用预处理语句创建表
    sql = '''
    CREATE TABLE IF NOT EXISTS movie_list (
        id INT AUTO_INCREMENT  NOT NULL,  
        movie_name VARCHAR(255) NOT NULL, 
        create_time VARCHAR(255) NOT NULL, 
        box_office VARCHAR(255) NOT NULL, 
        PRIMARY KEY (id))
    '''
    try:
        cursor.execute(sql)
        print("CREATE TABLE SUCCESS.")
    except Exception as ex:
        print(f"CREATE TABLE FAILED,CASE:{ex}")
    finally:
        # 关闭数据库连接
        db.close()



def save_data(cursor,db,movie_name, create_time, box_office):

    # SQL 插入语句
    sql = 'INSERT INTO movie_list(id, movie_name, create_time, box_office) values(%s, %s, %s, %s)'
    # 执行 SQL 语句
    try:
        cursor.execute(sql, (0, movie_name, create_time, box_office))
        # 提交到数据库执行
        db.commit()
        print('数据插入成功...')
    except Exception as e:
        print(f'数据插入失败: {e}')
        # 如果发生错误就回滚
        db.rollback()
headers = {
    "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36 Edg/136.0.0.0"
}
cookies = {
}
url = "https://piaofang.maoyan.com/rankings/year"
response = requests.get(url, headers=headers, cookies=cookies)
# print(response.text)
selector = Selector(text=response.text)
json_list = selector.css('#ranks-list>ul')
json_arr =[]
db = pymysql.connect(host="localhost", user="root", password="12345", db="spider2")
# 使用 cursor() 方法创建一个游标对象cursor
cursor = db.cursor()
for json_str in json_list:
    json_obj = {}
    json_obj['movie_name'] = json_str.css('.first-line::text').get()
    json_obj['create_time'] = json_str.css('.second-line::text').get()
    json_obj['box_office'] = json_str.css('.col2.tr::text').get()
    save_data(cursor,db,json_obj['movie_name'],json_obj['create_time'],json_obj['box_office'])

5.Mongodb存储

准备工作,连接数据库,指定数据库和表

python 复制代码
import pymongo # 如果是云服务的数据库 用公网IP连接
client = pymongo.MongoClient(host='localhost', port=27017)
collection = client['spider']['movie_list']

在Mongodb里不需要建库和建表,直接存储,可以一次性全部插入,也可以一条一条插入

python 复制代码
import pymongo # 如果是云服务的数据库 用公网IP连接
client = pymongo.MongoClient(host='127.0.0.1', port=27017)
collection = client['spider']['movie_list']

# 插入单条数据
student = {'id': '20170101', 'name': 'Jordan', 'age': 20, 'gender': 'male' }
result = collection.insert_one(student)
print(result)

# 插入多条数据
student1 = { 'id': '20170101', 'name': 'Jordan', 'age': 20, 'gender': 'male' }
student2 = { 'id': '20170202', 'name': 'Mike', 'age': 21, 'gender': 'male' }
collection.insert_many([student1, student2])

效果如下:

案例如下:

python 复制代码
import requests
from scrapy import Selector
import pymysql
import pymongo
#准备工作
headers = {
    "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36 Edg/136.0.0.0"
}
cookies = {
}
url = "https://piaofang.maoyan.com/rankings/year"
response = requests.get(url, headers=headers, cookies=cookies)
# print(response.text)
selector = Selector(text=response.text)
json_list = selector.css('#ranks-list>ul')
json_arr =[]
import pymongo # 如果是云服务的数据库 用公网IP连接
client = pymongo.MongoClient(host='127.0.0.1', port=27017)
collection = client['spider']['movie_list']
for json_str in json_list:
    json_obj = {}
    json_obj['movie_name'] = json_str.css('.first-line::text').get()
    json_obj['create_time'] = json_str.css('.second-line::text').get()
    json_obj['box_office'] = json_str.css('.col2.tr::text').get()
    json_arr.append(json_obj)

collection.insert_many(json_arr)

结果如下:

相关推荐
持久的棒棒君3 小时前
npm安装electron下载太慢,导致报错
前端·electron·npm
why1514 小时前
微服务商城-商品微服务
数据库·后端·golang
山海不说话4 小时前
视频行为标注工具BehaviLabel(源码+使用介绍+Windows.Exe版本)
人工智能·python·计算机视觉·视觉检测
柒间4 小时前
Elasticsearch 常用操作命令整合 (cURL 版本)
大数据·数据库·elasticsearch
crary,记忆5 小时前
Angular微前端架构:Module Federation + ngx-build-plus (Webpack)
前端·webpack·angular·angular.js
漂流瓶jz5 小时前
让数据"流动"起来!Node.js实现流式渲染/流式传输与背后的HTTP原理
前端·javascript·node.js
SamHou06 小时前
手把手 CSS 盒子模型——从零开始的奶奶级 Web 开发教程2
前端·css·web
我不吃饼干6 小时前
从 Vue3 源码中了解你所不知道的 never
前端·typescript
liuzhenghua666 小时前
Python任务调度模型
java·运维·python
开航母的李大6 小时前
【中间件】Web服务、消息队列、缓存与微服务治理:Nginx、Kafka、Redis、Nacos 详解
前端·redis·nginx·缓存·微服务·kafka