首页 » Python编程快速上手 » Python编程快速上手全文在线阅读

《Python编程快速上手》第14章 处理CSV文件和JSON数据

关灯直达底部

在第13章中,你学习了如何从PDF和Word文档中提取文本。这些文件是二进制格式,需要特殊的Python模块来访问它们的数据。CSV和JSON文件则不同,它们是纯文本文件。可以用文本编辑器察看它们,诸如IDLE的文件编辑器。但Python也有专门的csv和json模块,每个模块都提供了一些函数,帮助你处理这些文件格式。

CSV表示“Comma-Separated Values(逗号分隔的值)”,CSV文件是简化的电子表格,保存为纯文本文件。Python的csv模块让解析CSV文件变得容易。

JSON(发音为“JAY-sawn”或“Jason”,但如何发音并不重要。因为无论如何发音,都会有人说你发音错误)是一种格式,它以JavaScript源代码的形式,将信息保存在纯文本文件中。

JSON是JavaScript Object Notation的缩写不需要知道JavaScript编程语言,就可以使用JSON文件,但了解JSON格式是有用的,因为它用于许多Web应用程序中。

14.1 csv模块

CSV文件中的每行代表电子表格中的一行,逗号分割了该行中的单元格。例如,来自http://nostarch.com/automatestuff/的电子表格example.xlsx,在一个CSV文件中,看起来像这样:

4/5/2015 13:34,Apples,734/5/2015 3:41,Cherries,854/6/2015 12:46,Pears,144/8/2015 8:59,Oranges,524/10/2015 2:07,Apples,1524/10/2015 18:10,Bananas,234/10/2015 2:40,Strawberries,98  

我将使用这个文件作为本章的交互式环境的例子。可以从http://nostarch.com/ automatestuff/下载example.csv,或在文本编辑器中输入文本,并保存为example.csv。

CSV文件是简单的,缺少Excel电子表格的许多功能。例如,CSV文件中:

  • 值没有类型,所有东西都是字符串;
  • 没有字体大小或颜色的设置;
  • 没有多个工作表;
  • 不能指定单元格的宽度和高度;
  • 不能合并单元格;
  • 不能嵌入图像或图表。

CSV的文件的优势是简单。CSV文件被许多种类的程序广泛地支持,可以在文本编辑器中查看(包括IDLE的文件编辑器),它是表示电子表格数据的直接方式。CSV格式和它声称的完全一致:它就是一个文本文件,具有逗号分隔的值。

因为CSV文件就是文本文件,所以你可能会尝试将它们读入一个字符串,然后用第8章中学到的技术处理这个字符串。例如,因为CSV文件中的每个单元格有逗号分割,也许你可以只是对每行文本调用split方法,来取得这些值。但并非CSV文件中的每个逗号,都表示两个单元格之间的分界。CSV文件也有自己的转义字符,允许逗号和其他字符作为值的一部分。split方法不能处理这些转义字符。因为这些潜在的缺陷,所以总是应该使用csv模块来读写CSV文件。

14.1.1 Reader对象

要用csv模块从CSV文件中读取数据,需要创建一个Reader对象。Reader对象让你迭代遍历CSV文件中的每一行。在交互式环境中输入以下代码,同时将example.csv放在当前工作目录中:

❶ >>> import csv❷ >>> exampleFile = open('example.csv')❸ >>> exampleReader = csv.reader(exampleFile)❹ >>> exampleData = list(exampleReader)❺ >>> exampleData [['4/5/2015 13:34', 'Apples', '73'], ['4/5/2015 3:41', 'Cherries', '85'], ['4/6/2015 12:46', 'Pears', '14'], ['4/8/2015 8:59', 'Oranges', '52'], ['4/10/2015 2:07', 'Apples', '152'], ['4/10/2015 18:10', 'Bananas', '23'], ['4/10/2015 2:40', 'Strawberries', '98']]  

csv模块是Python自带的,所以不需要安装就可以导入它❶。

要用csv模块读取CSV文件,首先用open函数打开它❷,就像打开任何其他文本文件一样。但是,不用在open返回的File对象上调用read或readlines方法,而是将它传递给csv.reader函数❸。这将返回一个Reader对象,供你使用。请注意,不能直接将文件名字符串传递给csv.reader函数。

要访问Reader对象中的值,最直接的方法,就是将它转换成一个普通Python列表,即将它传递给list❹。在这个Reader对象上应用list函数,将返回一个列表的列表。可以将它保存在变量exampleData中。在交互式环境中输入exampleData,将显示列表的列表❺。

既然已经将CSV文件表示为列表的列表,就可以用表达式exampleData [row][col]来访问特定行和列的值。其中,row是exampleData中一个列表的下标,col是该列表中你想访问的项的下标。在交互式环境中输入以下代码:

>>> exampleData[0][0]'4/5/2015 13:34'>>> exampleData[0][1]'Apples'>>> exampleData[0][2]'73'>>> exampleData[1][1]'Cherries'>>> exampleData[6][1]'Strawberries'  

exampleData[0][0]进入第一个列表,并给出第一个字符串。exampleData[0][2]进入第一个列表,并给出第三个字符串,以此类推。

14.1.2 在for循环中,从Reader对象读取数据

对于大型的CSV文件,你需要在一个for循环中使用Reader对象。这样避免将整个文件一次性装入内存。例如,在交互式环境中输入以下代码:

>>> import csv>>> exampleFile = open('example.csv')>>> exampleReader = csv.reader(exampleFile)>>> for row in exampleReader:print('Row #' + str(exampleReader.line_num) + ' ' + str(row))Row #1 ['4/5/2015 13:34', 'Apples', '73']Row #2 ['4/5/2015 3:41', 'Cherries', '85']Row #3 ['4/6/2015 12:46', 'Pears', '14']Row #4 ['4/8/2015 8:59', 'Oranges', '52']Row #5 ['4/10/2015 2:07', 'Apples', '152']Row #6 ['4/10/2015 18:10', 'Bananas', '23']Row #7 ['4/10/2015 2:40', 'Strawberries', '98']  

在导入csv模块,并从CSV文件得到Reader对象之后,可以循环遍历Reader对象中的行。每一行是一个值的列表,每个值表示一个单元格。

print函数将打印出当前行的编号以及该行的内容。要取得行号,就使用Reader对象的line_num变量,它包含了当前行的编号。

Reader对象只能循环遍历一次。要再次读取CSV文件,必须调用csv.reader,创建一个对象。

14.1.3 Writer对象

Writer 对象让你将数据写入 CSV 文件。要创建一个 Writer 对象,就使用csv.writer函数。在交互式环境中输入以下代码。

 >>> import csv❶ >>> outputFile = open('output.csv', 'w', newline='')❷ >>> outputWriter = csv.writer(outputFile) >>> outputWriter.writerow(['spam', 'eggs', 'bacon', 'ham']) 21 >>> outputWriter.writerow(['Hello, world!', 'eggs', 'bacon', 'ham']) 32 >>> outputWriter.writerow([1, 2, 3.141592, 4]) 16 >>> outputFile.close  

首先,调用open并传入'w',以写模式打开一个文件❶。这将创建对象。然后将它传递给csv.writer❷,创建一个Writer对象。

在Windows上,需要为open函数的newline关键字参数传入一个空字符串。这样做的技术原因超出了本书的范围。如果忘记设置newline关键字参数,output.csv中的行距将有两倍,如图14-1所示。

图14-1 如果你在open中忘记了newline=''关键字参数,CSV文件将有两倍行距

Writer对象的writerow方法接受一个列表参数。列表中的每个词,放在输出的CSV文件中的一个单元格中。writerow函数的返回值,是写入文件中这一行的字符数(包括换行字符)。

这段代码生成的文件像下面这样:

spam,eggs,bacon,ham"Hello, world!",eggs,bacon,ham1,2,3.141592,4  

请注意,Writer对象自动转义了'Hello, world!'中的逗号,在CSV文件中使用了双引号。模块csv让你不必自己处理这些特殊情况。

14.1.4 delimiter和lineterminator关键字参数

假定你希望用制表符代替逗号来分隔单元格,并希望有两倍行距。可以在交互式环境中输入下面这样的代码:

 >>> import csv >>> csvFile = open('example.tsv', 'w', newline='')❶ >>> csvWriter = csv.writer(csvFile, delimiter='/t', lineterminator='/n/n') >>> csvWriter.writerow(['apples', 'oranges', 'grapes']) 24 >>> csvWriter.writerow(['eggs', 'bacon', 'ham']) 17 >>> csvWriter.writerow(['spam', 'spam', 'spam', 'spam', 'spam', 'spam']) 32 >>> csvFile.close  

这改变了文件中的分隔符和行终止字符。分隔符是一行中单元格之间出现的字符。默认情况下,CSV文件的分隔符是逗号。行终止字符是出现在行末的字符。默认情况下,行终止字符是换行符。你可以利用csv.writer的delimiter和lineterminator关键字参数,将这些字符改成不同的值。

传入delimeter='/t'和lineterminator='/n/n'❶,这将单元格之间的字符改变为制表符,将行之间的字符改变为两个换行符。然后我们调用writerow三次,得到3行。

这产生了文件example.tsv,包含以下内容:

apples  oranges grapeseggs    bacon    hamspam    spam     spam     spam     spam     spam  

既然单元格是由制表符分隔的,我们就使用文件扩展名.tsv,表示制表符分隔的值。

14.2 项目:从CSV文件中删除表头

假设你有一个枯燥的任务,要删除几百CSV文件的第一行。也许你会将它们送入一个自动化的过程,只需要数据,不需要每列顶部的表头。可以在Excel中打开每个文件,删除第一行,并重新保存该文件,但这需要几个小时。让我们写一个程序来做这件事。

该程序需要打开当前工作目录中所有扩展名为.csv的文件,读取CSV文件的内容,并除掉第一行的内容重新写入同名的文件。这将用新的、无表头的内容替换CSV文件的旧内容。

警告

与往常一样,当你写程序修改文件时,一定要先备份这些文件,以防万一你的程序没有按期望的方式工作。你不希望意外地删除原始文件。

总的来说,该程序必须做到以下几点:

  • 找出当前工作目录中的所有CSV文件。
  • 读取每个文件的全部内容。
  • 跳过第一行,将内容写入一个新的CSV文件。

在代码层面上,这意味着该程序需要做到以下几点:

  • 循环遍历从os.listdir得到的文件列表,跳过非CSV文件。
  • 创建一个CSV Reader对象,读取该文件的内容,利用line_num属性确定要跳过哪一行。
  • 创建一个CSV Writer对象,将读入的数据写入新文件。

针对这个项目,打开一个新的文件编辑器窗口,并保存为removeCsvHeader.py。

第1步:循环遍历每个CSV文件

程序需要做的第一件事情,就是循环遍历当前工作目录中所有CSV文件名的列表。让removeCsvHeader.py看起来像这样:

 #! python3 # removeCsvHeader.py - Removes the header from all CSV files in the current # working directory. import csv, os os.makedirs('headerRemoved', exist_ok=True) # Loop through every file in the current working directory. for csvFilename in os.listdir('.'):     if not csvFilename.endswith('.csv'):❶ continue     # skip non-csv files     print('Removing header from ' + csvFilename + '...')     # TODO: Read the CSV file in (skipping first row).     # TODO: Write out the CSV file.  

os.makedirs调用将创建headerRemoved文件夹,所有的无表头的CSV文件将写入该文件夹。针对os.listdir('.')进行for循环完成了一部分任务,但这会遍历工作目录中的所有文件,所以需要在循环开始处添加一些代码,跳过扩展名不是.csv的文件。如果遇到非CSV文件,continue语句❶让循环转向下一个文件名。

为了让程序运行时有一些输出,打印出一条消息说明程序在处理哪个CSV文件。然后,添加一些TODO注释,说明程序的其余部分应该做什么。

第2步:读入CSV文件

该程序不会从原来的CSV文件删除第一行。但是,它会创建新的CSV文件副本,不包含第一行。因为副本的文件名与原来的文件名一样,所以副本会覆盖原来的文件。

该程序需要一种方法,来知道它的循环当前是否在处理第一行。为removeCsvHeader.py添加以下代码。

#! python3# removeCsvHeader.py - Removes the header from all CSV files in the current# working directory.--snip--# Read the CSV file in (skipping first row).csvRows = csvFileObj = open(csvFilename)readerObj = csv.reader(csvFileObj)for row in readerObj:    if readerObj.line_num == 1:continue     # skip first row    csvRows.append(row)csvFileObj.close# TODO: Write out the CSV file.  

Reader对象的line_num属性可以用来确定当前读入的是CSV文件的哪一行。另一个for循环会遍历CSV Reader对象返回所有行,除了第一行,所有行都会添加到csvRows。

在for循环遍历每一行时,代码检查reader.line_num是否设为1。如果是这样,它执行continue,转向下一行,不将它添加到csvRows中。对于之后的每一行,条件永远是False,该行将添加到csvRows中。

第3步:写入CSV文件,没有第一行

现在csvRows包含了除第一行的所有行,该列表需要写入headerRemoved文件夹中的一个CSV文件。将以下代码添加到removeCsvHeader.py:

 #! python3 # removeCsvHeader.py - Removes the header from all CSV files in the current # working directory. --snip-- # Loop through every file in the current working directory.❶ for csvFilename in os.listdir('.'):     if not csvFilename.endswith('.csv'): continue # skip non-CSV files     --snip--     # Write out the CSV file.     csvFileObj = open(os.path.join('headerRemoved', csvFilename), 'w',  newline='')     csvWriter = csv.writer(csvFileObj)     for row in csvRows: csvWriter.writerow(row)     csvFileObj.close  

CSV Writer对象利用csvFilename(这也是我们在CSV Reader中使用的文件名),将列表写入headerRemoved中的一个CSV文件。这将覆盖原来的文件。

创建Writer对象后,我们循环遍历存储在csvRows中的子列表,将每个子列表写入该文件。

这段代码执行后,外层for循环❶将循环到os.listdir('.')中的下一个文件名。循环结束时,程序就结束了。

为了测试你的程序,从http://nostarch.com/automatestuff/下载removeCsvHeader.zip,将它解压缩到一个文件夹。在该文件夹中运行removeCsvHeader.py程序。输出将是这样的:

Removing header from NAICS_data_1048.csv...Removing header from NAICS_data_1218.csv...--snip--Removing header from NAICS_data_9834.csv...Removing header from NAICS_data_9986.csv...  

这个程序应该在每次从CSV文件中删除第一行时,打印一个文件名。

第4步:类似程序的想法

针对CSV文件写的程序类似于针对Excel文件写的程序,因为它们都是电子表格文件。你可以编程完成以下任务:

  • 在一个CSV文件的不同行,或多个CSV文件之间比较数据。
  • 从CSV文件拷贝特定的数据到Excel文件,或反过来。
  • 检查CSV文件中无效的数据或格式错误,并向用户提醒这些错误。
  • 从CSV文件读取数据,作为Python程序的输入。

14.3 JSON和API

JavaScript对象表示法是一种流行的方式,将数据格式化,成为人可读的字符串。JSON是JavaScript程序编写数据结构的原生方式,通常类似于Python的pprint函数产生的结果。不需要了解JavaScript,也能处理JSON格式的数据。

下面是JSON格式数据的一个例子:

{"name": "Zophie", "isCat": true, "miceCaught": 0, "napsTaken": 37.5, "felineIQ": null}  

了解JSON是很有用,因为很多网站都提供JSON格式的内容,作为程序与网站交互的方式。这就是所谓的提供“应用程序编程接口(API)”。访问API和通过URL访问任何其他网页是一样的。不同的是,API返回的数据是针对机器格式化的(例如用JSON),API不是人容易阅读的。

许多网站用JSON格式提供数据。Facebook、Twitter、Yahoo、Google、Tumblr、Wikipedia、Flickr、Data.gov、Reddit、IMDb、Rotten Tomatoes、LinkedIn和许多其他流行的网站,都提供API让程序使用。有些网站需要注册,这几乎都是免费的。你必须找到文档,了解程序需要请求什么 URL 才能获得想要的数据,以及返回的JSON数据结构的一般格式。这些文档应在提供API的网站上提供,如果它们有“开发者”页面,就去那里找找。

利用API,可以编程完成下列任务:

  • 从网站抓取原始数据(访问API通常比下载网页并用Beautiful Soup解析HTML更方便)。
  • 自动从一个社交网络账户下载新的帖子,并发布到另一个账户。例如,可以把tumblr的帖子上传到Facebook。
  • 从IMDb、Rotten Tomatoes和维基百科提取数据,放到计算机的一个文本文件中,为你个人的电影收藏创建一个“电影百科全书”。

可以在http://nostarch.com/automatestuff/的资源中看到JSON API的一些例子。

14.4 json模块

Python的json模块处理了JSON数据字符串和Python值之间转换的所有细节,得到了json.loads和json.dumps函数。JSON不能存储每一种Python值,它只能包含以下数据类型的值:字符串、整型、浮点型、布尔型、列表、字典和NoneType。JSON不能表示Python特有的对象,如File对象、CSV Reader或Writer对象、Regex对象或Selenium WebElement对象。

14.4.1 用loads函数读取JSON

要将包含JSON数据的字符串转换为Python的值,就将它传递给json.loads函数(这个名字的意思是“load string”,而不是“loads”)。在交互式环境中输入以下代码:

>>> stringOfJsonData = '{"name": "Zophie", "isCat": true, "miceCaught": 0,"felineIQ": null}'>>> import json>>> jsonDataAsPythonValue = json.loads(stringOfJsonData)>>> jsonDataAsPythonValue{'isCat': True, 'miceCaught': 0, 'name': 'Zophie', 'felineIQ': None}  

导入json模块后,就可以调用loads,向它传入一个JSON数据字符串。请注意,JSON字符串总是用双引号。它将该数据返回为一个Python字典。Python字典是没有顺序的,所以如果打印jsonDataAsPythonValue,键-值对可能以不同的顺序出现。

14.4.2 用dumps函数写出JSON

json.dumps函数(它表示“dump string”,而不是“dumps”)将一个Python值转换成JSON格式的数据字符串。在交互式环境中输入以下代码:

>>> pythonValue = {'isCat': True, 'miceCaught': 0, 'name': 'Zophie','felineIQ': None}>>> import json>>> stringOfJsonData = json.dumps(pythonValue)>>> stringOfJsonData'{"isCat": true, "felineIQ": null, "miceCaught": 0, "name": "Zophie" }'  

该值只能是以下基本Python数据类型之一:字典、列表、整型、浮点型、字符串、布尔型或None。

14.5 项目:取得当前的天气数据

检查天气似乎相当简单:打开Web浏览器,点击地址栏,输入天气网站的URL(或搜索一个,然后点击链接),等待页面加载,跳过所有的广告等。

其实,如果有一个程序,下载今后几天的天气预报,并以纯文本打印出来,就可以跳过很多无聊的步骤。该程序利用第11章介绍的requests模块,从网站下载数据。

总的来说,该程序将执行以下操作:

  • 从命令行读取请求的位置。
  • 从OpenWeatherMap.org下载JSON天气数据。
  • 将JSON数据字符串转换成Python的数据结构。
  • 打印今天和未来两天的天气。

因此,代码需要完成以下任务:

  • 连接sys.argv中的字符串,得到位置。
  • 调用requests.get,下载天气数据。
  • 调用json.loads,将JSON数据转换为Python数据结构。
  • 打印天气预报。

针对这个项目,打开一个新的文件编辑器窗口,并保存为quickWeather.py。

第1步:从命令行参数获取位置

该程序的输入来自命令行。让quickWeather.py看起来像这样:

#! python3# quickWeather.py - Prints the weather for a location from the command line.import json, requests, sys# Compute location from command line arguments.if len(sys.argv) <  2:    print('Usage: quickWeather.py location')    sys.exitlocation = ' '.join(sys.argv[1:])# TODO: Download the JSON data from OpenWeatherMap.org's API.# TODO: Load JSON data into a Python variable.  

在Python中,命令行参数存储在sys.argv列表里。#!行和import语句之后,程序会检查是否有多个命令行参数(回想一下,sys.argv中至少有一个元素sys.argv[0],它包含了Python脚本的文件名)。如果该列表中只有一个元素,那么用户没有在命令行中提供位置,程序向用户提供“Usage(用法)”信息,然后结束。

命令行参数以空格分隔。命令行参数San Francisco, CA将使sys.argv中保存['quickWeather.py', 'San', 'Francisco,', 'CA']。因此,调用join方法,将sys.argv中除第一个字符串以外的字符串连接起来。将连接的字符串存储在变量location中。

第2步:下载JSON数据

OpenWeatherMap.org提供了JSON格式的实时天气信息。你的程序只需要下载页面http://api.openweathermap.org/data/2.5/forecast/daily?q=< Location>&cnt=3,其中< Location>是想知道天气的城市。将以下代码添加到quickWeather.py中。

#! python3# quickWeather.py - Prints the weather for a location from the command line.--snip--# Download the JSON data from OpenWeatherMap.org's API.url ='http://api.openweathermap.org/data/2.5/forecast/daily?q=%s&cnt=3' % (location)response = requests.get(url)response.raise_for_status# TODO: Load JSON data into a Python variable.  

我们从命令行参数中得到了 location。为了生成要访问的网址,我们利用%s占位符,将location中保存的字符串插入URL字符串的那个位置。结果保存在url中,并将url传入requests.get。requests.get调用返回一个Response对象,它可以通过调用raise_for_status来检查错误。如果不发生异常,下载的文本将保存在response.text中。

第3步:加载JSON数据并打印天气

response.text成员变量保存了一个JSON格式数据的大字符串。要将它转换为Python值,就调用json.loads函数。JSON数据会像这样:

{'city': {'coord': {'lat': 37.7771, 'lon': -122.42},  'country': 'United States of America',  'id': '5391959',  'name': 'San Francisco',  'population': 0}, 'cnt': 3, 'cod': '200', 'list': [{'clouds': 0,   'deg': 233,   'dt': 1402344000,   'humidity': 58,   'pressure': 1012.23,   'speed': 1.96,   'temp': {'day': 302.29,    'eve': 296.46,    'max': 302.29,    'min': 289.77,    'morn': 294.59,    'night': 289.77},   'weather': [{'description': 'sky is clear','icon': '01d',--snip--  

可以将weatherData传入pprint.pprint,查看这个数据。你可能要查找http:// openweathermap.org/,找到关于这些字段含义的文档。例如,在线文档会告诉你,'day'后面的302.29是白天的开尔文温度,而不是摄氏或华氏温度。

你想要的天气描述在'main'和'description'之后。为了整齐地打印出来,在quickWeather.py中添加以下代码。

 #! python3 # quickWeather.py - Prints the weather for a location from the command line. --snip-- # Load JSON data into a Python variable. weatherData = json.loads(response.text) # Print weather descriptions.❶ w = weatherData['list'] print('Current weather in %s:' % (location)) print(w[0]['weather'][0]['main'], '-', w[0]['weather'][0]['description']) print print('Tomorrow:') print(w[1]['weather'][0]['main'], '-', w[1]['weather'][0]['description']) print print('Day after tomorrow:') print(w[2]['weather'][0]['main'], '-', w[2]['weather'][0]['description'])  

请注意,代码将weatherData['list']保存在变量w中,这将节省一些打字时间❶。可以用w[0]、w[1]和w[2]来取得今天、明天和后天天气的字典。这些字典都有'weather'键,其中包含一个列表值。你感兴趣的是第一个列表项(一个嵌套的字典,包含几个键),下标是0。这里,我们打印出保存在'main'和'description'键中的值,用连字符隔开。

如果用命令行参数quickWeather.py San Francisco, CA运行这个程序,输出看起来是这样的:

Current weather in San Francisco, CA:Clear - sky is clearTomorrow:Clouds - few cloudsDay after tomorrow:Clear - sky is clear  

(天气是我喜欢住在旧金山的原因之一!)

第4步:类似程序的想法

访问气象数据可以成为多种类型程序的基础。你可以创建类似程序,完成以下任务:

  • 收集几个露营地点或远足路线的天气预报,看看哪一个天气最好。
  • 如果需要将植物移到室内,安排一个程序定期检查天气并发送霜冻警报(第15章介绍了定时调度,第16章介绍了如何发送电子邮件)。
  • 从多个站点获得气象数据,同时显示,或计算并显示多个天气预报的平均值。

14.6 小结

CSV和JSON是常见的纯文本格式,用于保存数据。它们很容易被程序解析,同时仍然让人可读,所以它们经常被用作简单的电子表格或网络应用程序的数据。csv和json模块大大简化了读取和写入CSV和JSON文件的过程。

前面几章教你如何利用Python从各种各样的文件格式的解析信息。一个常见的任务是接受多种格式的数据,解析它,并获得需要的特定信息。这些任务往往非常特别,商业软件并不是最有帮助的。通过编写自己的脚本,可以让计算机处理大量以这些格式呈现的数据。

在第15章,你将从数据格式中挣脱,学习如何让程序与你通信,发送电子邮件和文本消息。

14.7 习题

1.哪些功能是Excel电子表格有,而CSV电子表格没有?

2.向csv.reader和csv.writer传入什么,来创建Reader和Writer对象?

3.对于Reader和Writer对象,File对象需要以什么模式打开?

4.什么方法接受一个列表参数,并将其写入CSV文件?

5.delimiter和lineterminator关键字参数有什么用?

6.什么函数接受一个JSON数据的字符串,并返回一个Python数据结构?

7.什么函数接受一个Python数据结构,并返回一个JSON数据的字符串?

14.8 实践项目

作为实践,编程完成下列任务。

Excel到CSV的转换程序

Excel可以将电子表格保存为CSV文件,只要点几下鼠标,但如果有几百个Excel文件要转换为CSV,就需要点击几小时。利用第12章的openpyxl模块,编程读取当前工作目录中的所有Excel文件,并输出为CSV文件。

一个Excel文件可能包含多个工作表,必须为每个表创建一个CSV文件。CSV文件的文件名应该是< Excel文件名>_< 表标题>.csv,其中< Excel文件名>是没有扩展名的Excel文件名(例如'spam_data',而不是'spam_data.xlsx'),< 表标题>是Worksheet对象的title变量中的字符串。

该程序将包含许多嵌套的for循环。该程序的框架看起来像这样:

for excelFile in os.listdir('.'):    # Skip non-xlsx files, load the workbook object.    for sheetName in wb.get_sheet_names:# Loop through every sheet in the workbook.sheet = wb.get_sheet_by_name(sheetName)# Create the CSV filename from the Excel filename and sheet title.# Create the csv.writer object for this CSV file.# Loop through every row in the sheet.for rowNum in range(1, sheet.get_highest_row + 1):    rowData =  # append each cell to this list    # Loop through each cell in the row.    for colNum in range(1, sheet.get_highest_column + 1):# Append each cell's data to rowData.    # Write the rowData list to the CSV file.csvFile.close  

从http://nostarch.com/automatestuff/下载ZIP文件excelSpreadsheets.zip,将这些电子表格解压缩到程序所在的目录中。可以使用这些文件来测试程序。