简单利用python处理文件
之前我在真·从零开始使用Requests制作简单爬虫中爬取了小说下来,本来想搭建个服务器,做一个个人的小说平台,发现爬下来的文件中,有大量的javascript以及对原地址请求的动作等,导致加载速度很慢。为了解决这个问题,需要把上述的内容处理掉,所以在此也写写,如何简单地利用python批量处理文件
一、打开文件操作
常用python打开文件有2种方式:
# 方式1
f = open('a.txt','r')
# 方式2
with open('a.txt', 'r') as f:
我推荐用的是with open。当直接使用open是打开一个文件流后,是需要后续手工写f.close()关闭文件流的。对于读的操作来说,关闭文件流与否影响不会特别大,但是对于写入的操作来说,如果不及时关闭,会导致写入丢失。而with open的方法,他是不需要后续再调用close()的方法,至于为什么?属于python 迭代器的范畴,大家可以自行百度一下,这里只要知道即可。
with open 以及 open除了一个是迭代器实现,一个不是之外,在参数使用上、取文件内容的方式上,没有什么不同。因为懒,所以下文统一用with open来讲解。
1.with open的参数讲解
# filename代表文件名,建议字符串前面带个u,例如:u'a.txt'
with open (filename, mode) as f:
mode的方法,需要带'',例如:'w'
参数 | 解释 |
---|---|
r | 以方式打开文件,从头开始读取文件内容 |
rb | 以格式打开一个文件用于,从头开始读取文件内容 |
r+ | 打开一个文件用于。若文件不存在,报错,若文件存在,从头开始原文件内容。另外,先读后写,读取内容后再写入。 |
rb+ | 以二进制格式打开一个文件用于。若文件不存在,报错,若文件存在,从头开始原文件内容。另外,先读后写,读取内容后再写入。 |
w | 打开一个文件只用于。如果该文件不存在,创建新文件。如果该文件已存在则将其。与r+不同的地方在于,r+是从内容的开头开始覆盖,w相当于把整个文件删掉,重新创建的方式覆盖。 |
wb | 以二进制格式打开一个文件只用于。如果该文件不存在,创建新文件。如果该文件已存在则将其。与rb+不同的地方在于,rb+是从内容的开头开始覆盖,wb相当于把整个文件删掉,重新创建的方式覆盖。 |
w+ | 打开一个文件用于。如果该文件不存在,创建新文件。如果该文件已存在则将其。与r+不同的地方在于,r+是从内容的开头开始覆盖,w+相当于把整个文件删掉,重新创建的方式覆盖。 |
wb+ | 以二进制格式打开一个文件用于。如果该文件已存在则将其。如果该文件不存在,创建新文件。与rb+不同的地方在于,rb+是从内容的开头开始覆盖,wb+相当于把整个文件删掉,重新创建的方式覆盖。 |
a | 打开一个文件用于。如果没有该文件,则创建该文件,在文件末尾(空文件的开头与末尾在同一个位置)插入新的内容。 |
ab | 以二进制格式打开一个文件用于。如果没有该文件,则创建该文件,在文件末尾(空文件的开头与末尾在同一个位置)插入新的内容。 |
a+ | 打开一个文件用于。如果没有该文件,则创建该文件,在文件末尾(空文件的开头与末尾在同一个位置)插入新的内容。 |
ab+ | 以二进制格式打开一个文件用于。如果没有该文件,则创建该文件,在文件末尾(空文件的开头与末尾在同一个位置)插入新的内容 |
读写的意思是,既可以读也可以写。当我们想修改原文件的内容然后覆盖的话,就会选用读写模式,可读可写,都需要用seek(0)后才可读。例如:f.seek(0)。
快速记忆法:三个模式,r,w,a。两个数据,带b和不带b。以及分别带不带+号(能不能读写)。其实我一般就直接用r,w,a~hahahah
2.文件的内容读取
文件读取有几种方式,如下
with open ('a.txt', r) as f:
# 一次性读取整个文件的内容放到s中
s = f.read()
print (s)#输出整个文本
s = ''
with open ('a.txt', r) as f:
# 一次只从文件中读一行数据,所以需要用迭代的方式取
for line in f:
#把每一行都拼接到定义好的字符串上
s += f.readline()
print (s)#输出整个文本
with open ('a.txt', r) as f:
#一次性读取整个文件,但是通过换行符,把文章分割成列表,通过操作列表来进行操作文本的数据
s2 = f.readlines()
print (type(s))#输出的是列表
根据自己的需求,或者说根据机子的性能来选择不同的方式。一般来说,不是特别大的文件,都可以直接用read或者readlines。这两者的选择是,你之后是否需要针对每一行,或者某些行处理,如果是的话,直接用readlines会比较方便。
3.提取所需的文件内容
提取步骤
a.分析原文件
打开爬虫获得的原文件,看到
txt文件
一般爬虫获得的网页文件,都是由前端各种标签,以及真正的内容组成。所以我们需要找到真正内容所在的标签并提取即可
b.寻找所需的内容以及规律
找到标题的标签 找到正文的标签c.编写对应关于规则
先去除其余一切无用的标签,两种方法,第一种方法使用split的方法
split获得的是列表,所以采用[0]、[1].....的方式提取。
简单理解:若要切割的元素在字符串中只出现一次,那么0代表的改元素的左边,1代表的是该元素的右边。
若切割的元素会在字符串中出现多次,那么split会获得多个列表元素,根据需要选择。附上split的用法
# 方法1使用split
with open ('第123章.txt', 'r') as f:
#因为单篇小说的大小其实很小,所以直接用read读到内存中
s = f.read()
# 用split的方法把title标签里的title直接切割出来
title = s.split('<title>')[1].split('</title>')[0]
# 用split的方法把content里的内容切割出来
#后面的为什么选择<br />?首先这个是一个换行的标签,在小说网站中,一般用于正文的换行。
#对此通过观察原文件可发现,<br />的确出现在正文中。
#最后的[:-1],是选取除了最后一项的所有项,为什么去掉最后一项?
#大家可以试试contentList = s.split('<div id="content">')[1].split('<br />')观察一下
contentList = s.split('<div id="content">')[1].split('<br />')[:-1]
# 因为split切出来的是一个列表,选取其中一项则为字符串。
#而我们这里选取的是除了最后一项的其他所有项,所以得到的是一个列表,可通过我设置的变量名知道
#所以我们需要用join的方法,把列表串联成字符串,并且把“ ”的空格html标签替换成空格字符“ ”。
#串联成字符串后发现,多了一个<p>,所以也去掉
content = ''.join(contentList).replace(' ',' ').split('<p>')[0]
#打印看看结果
print (title)
print (content)
结果join的作用,用来把可迭代的对象,例如列表,元组(严格意义上来说跟数组不同)等里面的元素串联成一个字符串。用法:str.join(sequence)
#!/usr/bin/python # -*- coding: UTF-8 -*- str = "-"; seq = ("a", "b", "c"); # 字符串序列,元组、列表,反正是可迭代的对象都可以 result = str.join( seq ) print (result)
输出“a-b-c”
第二种方法,使用re的方法
# 加载正则库
import re
with open ('第123章.txt', 'r') as f:
#因为单篇小说的大小其实很小,所以直接用read读到内存中
s = f.read()
# 把title标签之间的内容全部匹配
titleRe = re.compile('(?<=<title>).*?(?=</title>)')
#匹配<div id="content">以及最后一次出现的<br /><p>标签之间的全部内容
contentRe = re.compile('(?<=<div id="content">)[\s\S]*(?=<br /><p>)')
# 用findall的方式返回列表形式
title = titleRe.findall(s)
#输出title的值
print (title[0])
# 用findall的方式返回列表形式
contentList = contentRe.findall(s)
# 获取列表的元素,随后把 ;以及<br />换成字符串的形式
content = contentList[0].replace(' ',' ').replace('<br />','\n')
#输出content的值
print (content)
结果展示
会发现正则匹配出来的换行好像比split出来的多。是因为spilt的时候我们是以<br />也就是换行符切割,也就是会丢失一个换行符,而正则是匹配的方式会保留下来。可以通过对.replace('<br />','\n',2).replace('<br />', '')来处理。其中2的意思代表每遇到2个<br />才替换第二个<br />为换行符
一般我们会两种方法混合着用,这样的效率还有效果是最好的。其实,也就是怎么方便怎么来XD。附上正则语法表
最后写入到文件中
一般我会将处理过的文本保存成新的文件,源数据不会去覆盖,这样有助于之后的多次利用
#为可与读的区分,所以 as 后面用了其他变量名,随意取
with open ('newfilename.txt', 'w' ) as f_write:
#用write直接写入即可
f_write.write(s)
参考代码
import re,os
BaseFilename = u"第%d章.txt"
#输入你想从哪一章开始处理
n = 121
#当仍有文章时,while里的条件用于寻找文件,文件存在时返回True
while os.path.isfile(BaseFilename%n):
with open (BaseFilename%n, 'r') as f:
s = f.read()
titleRe = re.compile('(?<=<title>).*?(?=</title>)')
contentRe = re.compile('(?<=<div id="content">)[\s\S]*(?=<br /><p>)')
title = titleRe.findall(s)
content = contentRe.findall(s)
content = content[0].replace(' ',' ').replace('<br />','\n',2).replace('<br />','')
#在子文件夹new中放新的文本
newFileName = 'new/第%d章.txt'
with open (newFileName%n, 'w') as FWrite:
#写入标题和正文
FWrite.write(title[0] + '\n' + content)
#文章数加1,继续进行循环
n += 1