Python3网络爬虫实战-3一、数据存储:文件存储

咱们用解析器解析出数据以后,接下来的一步就是对数据进行存储了,保存的形式能够多种多样,最简单的形式能够直接保存为文本文件,如 TXT、Json、CSV 等等,另外还能够保存到数据库中,如关系型数据库 MySQL,非关系型数据库 MongoDB、Redis 等等。那么本章咱们就来统一了解一下数据的保存方式。javascript

文本存储

文件存储形式能够是多种多样的,好比能够保存成 TXT 纯文本形式,也能够保存为 Json 格式、CSV 格式等,本节咱们来了解下文本文件的存储方式。html

一、TXT文本存储

将数据保存到 TXT 文本的操做很是简单,并且 TXT 文本几乎兼容任何平台,可是有个缺点就是不利于检索,因此若是对检索和数据结构要求不高,追求方便第一的话,能够采用 TXT 文本存储,本节咱们来看下利用 Python 保存 TXT 文本文件的方法。java

1. 本节目标

本节咱们要保存知乎发现页面的热门问题部分,将其问题和答案统一保存成文本形式。数据库

2. 基本实例

首先能够用 Requests 将网页源代码获取下来,而后使用 PyQuery 解析库进行解析,接下来将提取的标题、回答者、回答保存到文本,代码以下:json

import requests
from pyquery import PyQuery as pq

url = 'https://www.zhihu.com/explore'
headers = {
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 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')
    file.write('\n'.join([question, author, answer]))
    file.write('\n' + '=' * 50 + '\n')
    file.close()
Python资源分享qun 784758214 ,内有安装包,PDF,学习视频,这里是Python学习者的汇集地,零基础,进阶,都欢迎

在这里主要是为了演示文件保存的方式,所以 Requests 异常处理部分在此省去,咱们首先用 Requests 提取了知乎发现页面,而后将热门问题的问题、回答者、答案全文提取出来,而后利用了Python提供的 open() 方法打开一个文本文件,获取一个文件操做对象,这里赋值为 file,而后利用 file 对象的 write() 方法将提取的内容写入文件,最后记得调用一下 close() 方法将其关闭,这样抓取的内容便可成功写入到文本中了。数组

运行程序,能够发如今本地生成了一个 explore.txt 文件.网络

这样热门问答的内容就被保存文文本形式了。数据结构

在这里 open() 方法的第一个参数即为要保存的目标文件名称,第二个参数为 a,表明以追加方式写入到文本,另外咱们还指定了文件的编码为utf-8,最后写入完成以后,咱们还须要调用 close() 方法来关闭文件对象。ide

3. 打开方式

在刚才的实例中,第二个参数咱们设置成了 a,这样在每次写入文本时不会清空源文件,而是在文件末尾写入新的内容,这是一种文件打开方式。关于文件打开方式,其实还有另外的几种,在此列举以下:函数

  • r,以只读方式打开文件。文件的指针将会放在文件的开头。这是默认模式。
  • rb,以二进制格式打开一个文件用于只读。文件指针将会放在文件的开头。这是默认模式。
  • r+,打开一个文件用于读写。文件指针将会放在文件的开头。
  • rb+,以二进制格式打开一个文件用于读写。文件指针将会放在文件的开头。
  • w,打开一个文件只用于写入。若是该文件已存在则将其覆盖。若是该文件不存在,建立新文件。
  • wb ,以二进制格式打开一个文件只用于写入。若是该文件已存在则将其覆盖。若是该文件不存在,建立新文件。
  • w+, 打开一个文件用于读写。若是该文件已存在则将其覆盖。若是该文件不存在,建立新文件。
  • wb+,以二进制格式打开一个文件用于读写。若是该文件已存在则将其覆盖。若是该文件不存在,建立新文件。
  • a,打开一个文件用于追加。若是该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容以后。若是该文件不存在,建立新文件进行写入。
  • ab 以二进制格式打开一个文件用于追加。若是该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容以后。若是该文件不存在,建立新文件进行写入。
  • a+,打开一个文件用于读写。若是该文件已存在,文件指针将会放在文件的结尾。文件打开时会是追加模式。若是该文件不存在,建立新文件用于读写。
  • ab+,以二进制格式打开一个文件用于追加。若是该文件已存在,文件指针将会放在文件的结尾。若是该文件不存在,建立新文件用于读写。

4. 简化写法

另外文件写入还有一种简写方法,那就是使用 with as 语法,在 with 控制块结束时,文件会自动关闭,因此就不须要再调用 close() 方法了。
因此上面的保存方式咱们能够简写以下:

with open('explore.txt', 'a', encoding='utf-8') as file:
    file.write('\n'.join([question, author, answer]))
    file.write('\n' + '=' * 50 + '\n')

若是想保存时将原文清空,那么能够将第二个参数改写为 w,代码以下:

with open('explore.txt', 'w', encoding='utf-8') as file:
    file.write('\n'.join([question, author, answer]))
    file.write('\n' + '=' * 50 + '\n')

5. 结语

以上即是利用 Python 将结果保存为 TXT 文件的方法,此种方法简单易用,操做高效,是一种最基本的保存数据的方法。

二、Json文件存储

Json,全称为 JavaScript Object Notation, 也就是 JavaScript 对象标记,经过对象和数组的组合来表示数据,构造简洁可是结构化程度很是高,它是一种轻量级的数据交换格式,本节咱们来了解一下利用 Python 保存数据到 Json 文件的方法。

1. 对象和数组

在 JavaScript 语言中,一切都是对象。所以,任何支持的类型均可以经过 Json 来表示,例如字符串、数字、对象、数组等。可是对象和数组是比较特殊且经常使用的两种类型。
对象,对象在 JavaScript 中是使用花括号 {} 包裹起来的内容,数据结构为 {key1:value1, key2:value2, ...} 的键值对结构。在面向对象的语言中,key 为对象的属性,value 为对应的值。键名可使用整数和字符串来表示。值的类型能够是任意类型。数组,数组在 JavaScript 中是方括号 [] 包裹起来的内容,数据结构为 ["java", "javascript", "vb", ...] 的索引结构。在 JavaScript 中,数组是一种比较特殊的数据类型,它也能够像对象那样使用键值对,但仍是索引使用得多。一样,值的类型能够是任意类型。因此一个 Json 对象能够写为以下形式:

[{
    "name": "Bob",
    "gender": "male",
    "birthday": "1992-10-18"
}, {
     "name": "Selina",
    "gender": "female",
    "birthday": "1995-10-18"
}]

由中括号包围的就至关于列表类型,列表的每一个元素能够是任意类型,在示例中它是字典类型,由大括号包围。
Json 能够由以上两种形式自由组合而成,能够无限次嵌套,结构清晰,是数据交换的极佳方式。

2. 读取Json

Python 为咱们提供了简单易用的 json 库来供咱们实现 Json 文件的读写操做,咱们能够调用 json 库的 loads() 方法将 Json 文本字符串转为 Json 对象,能够经过 dumps()方法将 Json 对象转为文本字符串。
例如在这里有一段 Json 形式的字符串,它是 str 类型,咱们用 Python 将可其转换为可操做的数据结构,如列表或字典。

import json

str = '''
[{
    "name": "Bob",
    "gender": "male",
    "birthday": "1992-10-18"
}, {
    "name": "Selina",
    "gender": "female",
    "birthday": "1995-10-18"
}]
'''
print(type(str))
data = json.loads(str)
print(data)
print(type(data))

运行结果:

<class 'str'>
[{'name': 'Bob', 'gender': 'male', 'birthday': '1992-10-18'}, {'name': 'Selina', 'gender': 'female', 'birthday': '1995-10-18'}]
<class 'list'>

在这里咱们使用了 loads() 方法将字符串转为 Json 对象,因为最外层是中括号,因此最终的类型是列表类型。
这样一来咱们就能够用索引来取到对应的内容了,例如咱们想取第一个元素里的 name 属性,就可使用以下方式获取:

data[0]['name']
data[0].get('name')

获得的结果都是:

Bob

经过中括号加 0 索引咱们能够拿到第一个字典元素,而后再调用其键名便可获得相应的键值。在获取键值的时候有两种方式,一种是中括号加键名,另外一种是 get() 方法传入键名。推荐使用 get() 方法来获取内容,这样若是键名不存在的话不会报错,会返回None。另外 get() 方法还能够传入第二个参数即默认值,咱们用一个示例感觉一下:

data[0].get('age')
data[0].get('age', 25)

运行结果:

None
25

在这里咱们尝试获取年龄 age,其实在原字典中是不存在该键名的,若是不存在,默认会返回 None,若是传入第二个参数即默认值,那么在不存在的状况下则返回该默认值。
值得注意的是 Json 的数据须要用双引号来包围,不能使用单引号。例如若使用以下形式表示则会出现错误:

import json

str = '''
[{
    'name': 'Bob',
    'gender': 'male',
    'birthday': '1992-10-18'
}]
'''
data = json.loads(str)

运行结果:

json.decoder.JSONDecodeError: Expecting property name enclosed indouble quotes: line 3 column 5 (char 8)

在这里会出现 Json 解析错误的提示,是由于在这里数据用了单括号来包围,请千万注意 Json 字符串的表示须要用双引号,不然 loads() 方法会解析失败。
若是咱们是从 Json 文本中读取内容,例如在这里有一个data.json 文本文件,其内容是刚才咱们所定义的 Json 字符串。
咱们能够先将文本文件内容读出,而后再利用 loads() 方法转化。

import json

with open('data.json', 'r') as file:
    str = file.read()
    data = json.loads(str)
    print(data)

运行结果:

[{'name': 'Bob', 'gender': 'male', 'birthday': '1992-10-18'}, {'name': 'Selina', 'gender': 'female', 'birthday': '1995-10-18'}]

以上是读取 Json 文件的方法。

3. 输出Json

另外咱们还能够调用 dumps() 方法来将 Json 对象转化为字符串。
例如咱们将刚上例中的列表从新写入到文本。

import json

data = [{
    'name': 'Bob',
    'gender': 'male',
    'birthday': '1992-10-18'
}]
with open('data.json', 'w') as file:
    file.write(json.dumps(data))

利用 dumps() 方法咱们能够将 Json 对象转为字符串,而后再调用文件的 write() 方法便可写入到文本,结果如图 5-2 所示:

Python3网络爬虫实战-3一、数据存储:文件存储

图 5-2 写入结果
另外若是咱们想保存 Json 的格式,能够再加一个参数 indent,表明缩进字符个数。

with open('data.json', 'w') as file:
    file.write(json.dumps(data, indent=2))

写入结果如图 5-3 所示:

[图片上传失败...(image-12c649-1564235008434)]

图 5-3 写入结果
这样获得的内容会自动带有缩进,格式会更加清晰。
另外若是 Json 中包含中文字符,例如咱们将以前的 Json 的部分值改成中文,再用以前的方法写入到文本。

import json

data = [{
    'name': '王伟',
    'gender': '男',
    'birthday': '1992-10-18'
}]
with open('data.json', 'w') as file:
    file.write(json.dumps(data, indent=2))

写入结果如图 5-4 所示:

[图片上传失败...(image-42cd95-1564235008433)]

图 5-4 写入结果
能够看到中文字符都变成了 Unicode 字符,这并非咱们想要的结果。
为了输出中文,咱们还须要指定一个参数 ensure_ascii 为 False,另外规定文件输出的编码。

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

写入结果如图 5-5 所示:

[图片上传失败...(image-e8aeec-1564235008433)]

图 5-5 写入结果
这样咱们就能够输出 Json 为中文了,因此若是字典中带有中文的内容咱们须要设置 ensure_ascii 参数为 False 才可正常写入中文。

4. 结语

本节咱们了解了用 Python 进行 Json 文件读写的方法,在后面作数据解析时常常会用到,建议熟练掌握。

三、CSV文件存储

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

1. 写入

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

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])

首先打开了一个 data.csv 文件,而后指定了打开的模式为 w,即写入,得到文件句柄,随后调用 csv 库的 writer() 方法初始化一个写入对象,传入该句柄,而后调用 writerow() 方法传入每行的数据便可完成写入。
运行结束后会生成一个名为 data.csv 的文件,数据就成功写入了,直接文本形式打开的话内容以下:

id,name,age
10001,Mike,20
10002,Bob,22
10003,Jordan,21
Python资源分享qun 784758214 ,内有安装包,PDF,学习视频,这里是Python学习者的汇集地,零基础,进阶,都欢迎

能够看到写入的文本默认是以逗号分隔的,调用一次 writerow() 方法便可写入一行数据,咱们用 Excel 打开的结果如图 5-6 所示:

[图片上传失败...(image-2ad0f7-1564235008433)]

图 5-6 打开结果
若是咱们想修改列与列之间的分隔符能够传入 delimiter 参数,代码以下:

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])

例如这里在初始化写入对象的时候传入 delimiter 为空格,这样输出的结果的每一列就是以空格分隔的了,内容以下:

id name age
10001 Mike 20
10002 Bob 22
10003 Jordan 21

另外咱们也能够调用 writerows() 方法同时写入多行,此时参数就须要为二维列表,例如:

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]])

输出效果是相同的,内容以下:

id,name,age
10001,Mike,20
10002,Bob,22
10003,Jordan,21

可是通常状况下爬虫爬取的都是结构化数据,咱们通常会用字典来表示,在 csv 库中也提供了字典的写入方式,实例以下:

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 表示,而后传给 DictWriter 初始化一个字典写入对象,而后能够先调用 writeheader() 方法先写入头信息,而后再调用 writerow() 方法传入相应字典便可,最终写入的结果是彻底相同的,内容以下:

id,name,age
10001,Mike,20
10002,Bob,22
10003,Jordan,21

这样咱们就能够完成字典到 CSV 文件的写入了。
另外若是咱们想追加写入的话能够修改文件的打开模式,如将 open() 函数的第二个参数改为 a 就能够变成追加写入,代码以下:

import csv

with open('data.csv', 'a') as csvfile:
    fieldnames = ['id', 'name', 'age']
    writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
    writer.writerow({'id': '10004', 'name': 'Durant', 'age': 22})

这样在上面的基础上再执行这段代码,文件内容便会变成:

id,name,age
10001,Mike,20
10002,Bob,22
10003,Jordan,21
10004,Durant,22

可见数据被追加写入到了文件中。
若是咱们要写入中文内容的话可能会遇到字符编码的问题,此时咱们须要给 open() 参数指定一个编码格式,好比这里再写入一行包含中文的数据,代码须要改写以下:

import csv

with open('data.csv', 'a', encoding='utf-8') as csvfile:
    fieldnames = ['id', 'name', 'age']
    writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
    writer.writerow({'id': '10005', 'name': '王伟', 'age': 22})

在这里须要给 open() 函数指定编码,不然可能会发生编码错误。
以上即是 CSV 文件的写入方法。
另外若是咱们接触过 Pandas 等库的话,能够调用 DataFrame 对象的 to_csv() 方法也能够很是方便地将数据写入到 CSV 文件中。

2. 读取

咱们一样可使用 csv 库来读取 CSV 文件,例如咱们如今将刚才写入的文件内容读取出来,代码以下:

import csv

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

运行结果:

['id', 'name', 'age']
['10001', 'Mike', '20']
['10002', 'Bob', '22']
['10003', 'Jordan', '21']
['10004', 'Durant', '22']
['10005', '王伟', '22']

在这里咱们构造的是 Reader 对象,经过遍历输出了每行的内容,每一行都是一个列表形式,注意在这里若是 CSV 文件中包含中文的话须要指定文件编码。
另外若是咱们接触过 Pandas 的话,能够利用 read_csv() 方法将数据从 CSV 中读取出来,例如:

import pandas  as pd
df = pd.read_csv('data.csv')
print(df)

运行结果:

      id    name  age
0  10001    Mike   20
1  10002     Bob   22
2  10003  Jordan   21
3  10004  Durant   22
4  10005      王伟   22
Python资源分享qun 784758214 ,内有安装包,PDF,学习视频,这里是Python学习者的汇集地,零基础,进阶,都欢迎

在作数据分析的时候此种方法用的比较多,也是一种比较方便的读取 CSV 文件的方法。

3. 结语

本节咱们了解了 CSV 文件的写入和读取方式,它也是一种经常使用的数据存储方式,须要熟练掌握。

相关文章
相关标签/搜索