爬虫文件存储:txt文档,json文件,csv文件
- 5.1 文件存储
- 文件存储形式可以是多种多样的,比如可以保存成 TXT 纯文本形式,也可以保存为 Json 格式、CSV 格式等,本节我们来了解下文本文件的存储方式。
- 5.1.1 TXT文本存储
- 将数据保存到 TXT 文本的操作非常简单,而且 TXT 文本几乎兼容任何平台,但是有个缺点就是不利于检索,所以如果对检索和数据结构要求不高,追求方便第一的话,可以采用 TXT 文本存储,本节我们来看下利用 Python 保存 TXT 文本文件的方法。
- 1. 本节目标
- 本节我们要保存知乎发现页面的热门问题部分,将其问题和答案统一保存成文本形式。
- 2. 基本实例
- 首先可以用 Requests 将网页源代码获取下来,然后使用 PyQuery 解析库进行解析,接下来将提取的标题、回答者、回答保存到文本,代码如下:
- 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()
- 在这里主要是为了演示文件保存的方式,因此 Requests 异常处理部分在此省去,我们首先用 Requests 提取了知乎发现页面,然后将热门问题的问题、回答者、答案全文提取出来,然后利用了Python提供的 open() 方法打开一个文本文件,获取一个文件操作对象,这里赋值为 file,然后利用 file 对象的 write() 方法将提取的内容写入文件,最后记得调用一下 close() 方法将其关闭,这样抓取的内容即可成功写入到文本中了。
- 运行程序,可以发现在本地生成了一个 explore.txt 文件,这样热门问答的内容就被保存文文本形式了。
- 在这里 open() 方法的第一个参数即为要保存的目标文件名称,第二个参数为 a,代表以追加方式写入到文本,另外我们还指定了文件的编码为utf-8,最后写入完成之后,我们还需要调用 close() 方法来关闭文件对象。
- 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 文件的方法,此种方法简单易用,操作高效,是一种最基本的保存数据的方法。
- 5.1.2 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 in double 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() 方法即可写入到文本
- 另外如果我们想保存 Json 的格式,可以再加一个参数 indent,代表缩进字符个数。
- with open('data.json', 'w') as file:
- file.write(json.dumps(data, indent=2))
- 这样得到的内容会自动带有缩进,格式会更加清晰。
- 另外如果 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 所示:
- 图 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))
- 这样我们就可以输出 Json 为中文了,所以如果字典中带有中文的内容我们需要设置 ensure_ascii 参数为 False 才可正常写入中文。
- 4. 结语
- 本节我们了解了用 Python 进行 Json 文件读写的方法,在后面做数据解析时经常会用到,建议熟练掌握。
- 5.1.3 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
- 可以看到写入的文本默认是以逗号分隔的,调用一次 writerow() 方法即可写入一行数据
- 实际执行结果:每隔一行都有一个空行,改写成如下形式则没有空行了:
- with open('data.csv', 'w',newline='') as csvfile:
- 如果我们想修改列与列之间的分隔符可以传入 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() 函数指定编码,否则可能会发生编码错误。
- 注意:
- 1.指定编码的话,使用文本文档打开csv文件,中文可以显示,但是使用表格打开csv文件中文会乱码
- 2.不指定编码的话,使用文本文档打开csv文件,中文显示乱码,但是使用表格打开csv文件中文会显示
- 以上便是 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
- 在做数据分析的时候此种方法用的比较多,也是一种比较方便的读取 CSV 文件的方法。
- 3. 结语
- 本节我们了解了 CSV 文件的写入和读取方式,它也是一种常用的数据存储方式,需要熟练掌握。
爬虫文件存储:txt文档,json文件,csv文件的更多相关文章
- 怎样把txt文档转换成csv文件?
其实csv就是逗号隔开的一行一行的数据, 如果每行数据中都是用逗号分隔的,直接把文件后缀txt改成csv就行了. 用python搞定: import numpy as np import pandas ...
- java使用正则从爬虫爬的txt文档中提取QQ邮箱
我的需求是从一堆文档中提取出qq邮箱,写了这篇帖子,希望能帮助和我有一样需求的人,谢谢!...... import java.io.BufferedReader; import java.io.Fil ...
- java简单实现用语音读txt文档
最近比较无聊,随便翻着博客,无意中看到了有的人用VBS读文本内容,也就是读几句中文,emmm,挺有趣的,实现也很简单,都不需要安装什么环境,直接新建txt文件,输入一些简单的vbs读文本的代码,然后将 ...
- PDF文件可以转换成txt文档吗
PDF是一种便携式的文件格式,传送和阅读都非常方便,是Adobe公司开发的跨平台文件格式,它无论在哪种打印机上都可以保证精确的颜色和准确的打印效果.可是有点遗憾的是PDF格式一般不能在手机上打开,或者 ...
- 20130317 如何批量把文件名称写入txt文档
1.如何批量把文件名称写入txt文档 COMMAND 窗口例:存放图片的文件夹是 D:\123\就用下面一名命令就OKdir d:\123\*.jpg /b > A.TXT 那么你所以JPG格式 ...
- 将mat文件中的数据按要求保存到txt文档中(批处理)
之前有个老朋友,让帮忙将一个mat中的数据重新保存到txt中,由于数据比较多需要用到批处理,之前弄过很多次,但每次一到要用的时候总是忘记怎么写了,现在记录一下,免得后面老是需要上网搜.这里先说一个比较 ...
- Java 读取txt文件生成Word文档
本文将以Java程序代码为例介绍如何读取txt文件中的内容,生成Word文档.在编辑代码前,可参考如下代码环境进行配置: IntelliJ IDEA Free Spire.Doc for Java T ...
- C# 读取txt文件生成Word文档
本文将以C#程序代码为例介绍如何来读取txt文件中的内容,生成Word文档.在编辑代码前,可参考如下代码环境进行配置: Visual Studio 2017 .Net Framework 4.6.1 ...
- 一个简易的Python爬虫,将爬取到的数据写入txt文档中
代码如下: import requests import re import os #url url = "http://wiki.akbfun48.com/index.php?title= ...
随机推荐
- 创业公司十分钟简单搭建GIT私有库
欢迎关注老码农的微信公共账号,与CSDN博客同步 一.背景 小公司.协同开发的人不多,建gitlab比較麻烦,仅仅须要在Server端建立一个简单的git共享库就OK. 二.建立仓库 Server端: ...
- LeetCode 819. Most Common Word (最常见的单词)
Given a paragraph and a list of banned words, return the most frequent word that is not in the list ...
- MongoDB使用初步
我很快就要离开现在这个使用nodejs + mongodb + redis的项目,转而去搞 塞特ID 之类的别的项目了.可惜这些技术对我来说浅尝辄止,半生不熟,胎死腹中.业余时间自学当然也可以,但哪有 ...
- Baum–Welch algorithm
Baum–Welch algorithm 世界上只有一个巴菲特,也只有一家文艺复兴科技公司_搜狐财经_搜狐网 http://www.sohu.com/a/157018893_649112
- UVALive 4212 - Candy
Little Charlie is a nice boy addicted to candies. He is even a subscriber to All Candies Magazine an ...
- c3p0-config.xml文件简单说明与备忘
<?xml version="1.0" encoding="UTF-8"?> <c3p0-config> <named-confi ...
- 设计模式 | 适配器模式(adapter)
定义: 将一个类的接口转换成客户希望的另外一个接口.Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作. 书中说到Gof的设计模式中,讲了两种类型的适配器模式: 1.类适配 ...
- vuejs {{}},v-text 和 v-html的区别
<div id="app"> <p>{{message}}</p> <!-- 输出:<span>通过双括号绑定</spa ...
- $P2299 Mzc和体委的争夺战$
\(problem\) #ifdef Dubug #endif #include <bits/stdc++.h> using namespace std; typedef long lon ...
- 动态规划DP入门
百度百科↓ 动态规划(dynamic programming)是运筹学的一个分支,是求解决策过程(decision process)最优化的数学方法.20世纪50年代初美国数学家R.E.Bellman ...