3.2 Python文件操作

Python的文件操作涉及对文件的读/写与编码的处理,是学习爬虫的必备知识。

3.2.1 使用Python读/写文本文件

使用Python来读/写文本需要用到“open”这个关键字。它的作用是打开一个文件,并创建一个文件对象。

使用Python打开文件,有两种写法。第1种方式如下:

    f = open(’文件路径’, ’文件操作方式’, encoding='utf-8')
    对文件进行操作
    f.close()

第2种方式,使用Python的上下文管理器:

    with open(’文件路径’, ’文件操作方式’, encoding='utf-8') as f:
      对文件进行操作

第1种方式需要手动关闭文件,但是在程序开发中经常会出现忘记关闭文件的情况。第二种方法不需要手动关闭文件,只要代码退出了缩进,Python就会自动关闭文件。

本书使用第二种写法。

1.使用Python读文本文件

使用Python打开一个文本文件时,首先要保证这个文件是存在的。在读文件的时候,“文件操作方式”这个参数可以省略,也可以写成“r”,也就是read的首字母。

文件路径可以是绝对路径,也可以是相对路径。如果是绝对路径,Linux和Mac OS不能直接使用“~”表示“home目录”,因为Python不认识“~”这个符号。如果非要使用这个符号,需要使用Python的“os”模块,代码如下:

    import os
    real_path = os.path.expanduser('~/project/xxx')

这样,Python就会将这种风格的路径转化为Python能认识的绝对路径。

相对路径是文本文件相对于现在的工作区而言的路径,并不总是相对于当前正在运行的这个Python文件的路径。在本章中,请读者直接将文本文件和Python文件放在一起,这样就可以直接使用文件名来打开文本文件。

文本文件的内容和它相对于.py文件的位置如图3-12所示。

图3-12 文本文件的内容和它相对于.py文件的位置

使用下面的代码来打开text.txt文件:

    with open('text.txt', encoding='utf-8') as f:
      通过f来读文件

这里有一个参数“encoding”。这个参数特别有用,它可以在打开文件的时候将文件转换为UTF-8编码格式,从而避免乱码的出现。这个参数只有Python 3有,在Python 2中使用这个参数会报错。如果文件是在Windows中创建的,并且使用UTF-8打开文件出现了乱码,可以把编码格式改为GBK。

文本文件可以按行读取,也可以直接读取里面的所有内容。

读取所有行,并以列表的形式返回结果,代码如下:

    f.readlines()

运行效果如图3-13所示。

图3-13 使用readlines()读取文本所有行并以列表形式返回结果

直接把文件里面的全部内容用一个字符串返回,代码如下:

    f.read()

运行结果如图3-14所示。

图3-14 直接把整个文本内容以一个字符串方式返回的结果

2.使用Python写文本文件

使用Python写文件也需要先打开文件,使用如下代码来打开文件:

    with open('new.txt', 'w', encoding='utf-8') as f:
      通过f来写文件

这里多出来一个参数“w”, w是英文write的首字母,意思是以写的方式打开文件。这个参数除了为“w”外,还可以为“a”。它们的区别在于,如果原来已经有一个new.txt文件了,使用“w”会覆盖原来的文件,导致原来的内容丢失;而使用“a”,则会把新的内容写到原来的文件末尾。

写文件时可以直接写一大段文本,也可以写一个列表。

直接将一大段字符串写入到文本中,可以使用下面这一行代码:

    f.write("一大段文字")

把列表里面的所有字符串写入到文本中,可以使用下面这一行代码:

    f.writelines([’第一段话’, ’第二段话’, ’第三段话’])

需要特别注意,写列表的时候,Python写到文本中的文字是不会自动换行的,需要人工输入换行符才可以。代码和运行生成的文本new.txt如图3-15和图3-16所示。请注意代码第8行列表中的两个字符串,在new.txt的第3行中被拼在了一起。

图3-15 写字符串和包含字符串的列表到文本中的代码

图3-16 写文本生成的文件内容结果

3.2.2 使用Python读/写CSV文件

CSV文件可以用Excel或者Numbers打开,得到可读性很高的表格,如图3-17所示。

图3-17 使用Numbers打开CSV文件

CSV文件本质上就是文本文件,但是如果直接用文本编辑器打开,可读性并不高,如图3-18所示。

图3-18 直接用文本编辑器打开CSV文件

Python自带操作CSV的模块。使用这个模块,可以将CSV文件的内容转换为Python的字典,从而方便使用。

1.Python读CSV文件

要读取CSV文件,首先需要导入Python的CSV模块:

    import csv

由于CSV文件本质上是一个文本文件,所以需要先以文本文件的方式打开,再将文件对象传递给CSV模块:

    with open('result.csv', encoding='utf-8') as f:
      reader = csv.DictReader(f)
      for row in reader:
        print(row)

运行结果图3-19所示。

图3-19 使用CSV模块打开CSV文件

代码中,for循环得到的row是OrderedDict(有序字典),可以直接像普通字典那样使用:

    username = row['username']
    content = row['content']
    reply_time = row['reply_time']

运行结果如图3-20所示。

图3-20 像读字典一样读CSV文件

短短几行代码,已经将CSV文件转换为字典了。

特别注意:

读取文本内容的代码必须放在缩进内部进行,否则会导致报错,如图3-21所示。

图3-21 读取文本内容的代码必须放在缩进的里面

这是因为f变量里面的值是一个生成器,生成器只有在被使用(更准确的说法是被迭代)的时候才会去读文本内容。但是退出with的缩进以后,文件就被Python关闭了,这个时候当然什么都读不了。

那有没有什么办法可以绕过这个限制呢?当然是有的,那就是使用列表推导式。图3-22所示为使用列表推导式读取文本内容。请对比图3-21和图3-22第4行的不同。

图3-22 使用列表推导式读取文本内容

2.Python写CSV文件

Python可以把一个字典写成CSV文件,或者把一个包含字典的列表写成CSV文件。Python写CSV文件比读CSV文件稍微复杂一点,因为要指定列名。列名要和字典的Key一一对应。

Python写CSV文件时需要用到csv.DictWriter()这个类。它接收两个参数:第1个参数是文件对象f;第2个参数名为fieldnames,值为字典的Key列表。

写入CSV文件的列名行:

    writer.writeheader()

将包含字典的列表全部写入到CSV文件中:

    writer.writerows(包含字典的列表)

写入一个包含字典的列表,每一个字典对应CSV的一行。这些字典的Key必须和fieldnames相同。字典可以是普通的无序字典,所以不需要关心字典里面Key的顺序,但是不能存在fieldnames里面没有的Key,也不能缺少fieldnames里面已有的Key。

写入单个字典:

    writer.writerow(字典)

代码如图3-23所示,运行结果如图3-24所示。Mac OS的Numbers显示CSV文件的结果和Excel中显示的结果可能存在差异,但是表格里面的数据应该是一致的。

图3-23 将包含列表的字典写入到CSV文件中

图3-24 生成的CSV文件用Numbers打开以后的结果