从HTML文件获取纯文本
通过BeautifulSoup获取纯文本
之前是通过BeautifulSoup (bs4)获取纯文本的,简单演示如下:
from bs4 import BeautifulSoup
htmfile = 'myweb.htm'
html = open(htmfile, 'r', encoding='utf-8')
htmlpage = html.read()
soup = BeautifulSoup(htmlpage.strip(), 'html.parser')
print(soup.text)
但是这样做的问题在于,其控制文本的格式或许与浏览器端显示的不一样
浏览器端显示的格式:
bs4抓取的文本格式如下:
为什么会这样呢?
因为在html源码中,存在这样的换行:
可以理解为bs4仅仅将html中的tag什么的去除了,但是并没有考虑格式与浏览器显示一致。
经过一番搜索,终于找到相应的方案
通过HTMLParser获取纯文本
HTMLParser是可以无视tag中的换行符的,如同浏览器一样,只要在tag中的文本,如<p>等,无论是否换行,在浏览器都是显示为一行。
安装:
pip install HTMLParser
但是安装之后运行,或许会提示找不到markupbase module的错误。
可以去如下地址下载:markupbase
然后将_markupbase.py更名为markupbase.py,并拷贝到python安装路径的:Lib\site-packages目录下,如: D:\python36\Lib\site-packages
具体的代码如下,我是将其单独写在一个python代码文件中,方便重用:
from re import sub
from sys import stderr
#need download https://pypi.org/project/micropython-_markupbase/3.3.3-1/#files,
# and copy _markupbase.py to \Lib\site-packages, then rename it to markupbase.py
# this library make html content to be right format
# 不能直接使用HTMLParser,而是用html.parser,
# 否则如果环境是python3.x,会遇到兼容问题
# from HTMLParser import HTMLParser
from html.parser import HTMLParser
from traceback import print_exc
from bs4 import BeautifulSoup
class _DeHTMLParser(HTMLParser):
def __init__(self):
HTMLParser.__init__(self)
self.__text = []
def handle_data(self, data):
text = data.strip()
if len(text) > 0:
text = sub('[ \t\r\n]+', ' ', text)
self.__text.append(text + ' ')
def handle_starttag(self, tag, attrs):
if tag == 'p':
self.__text.append('\n\n')
elif tag == 'br':
self.__text.append('\n')
elif tag == 'div':
self.__text.append('\n')
def handle_startendtag(self, tag, attrs):
if tag == 'br':
self.__text.append('\n\n')
def text(self):
return ''.join(self.__text).strip()
def dehtml(text):
try:
parser = _DeHTMLParser()
parser.feed(text)
parser.close()
return parser.text()
except:
print_exc(file=stderr)
#If invoke exception, then return text by beautifulsoup
soup = BeautifulSoup(text, 'html.parser')
return soup.text
之后提取的文本就是符合我们格式要求的:
主程序代码
包括:解压htm压缩包,提取纯文本,拆分文本文件
拆分文本文件,我是每500行就拆为一个小的文本文件
但是,考虑到避免将一个完整的段落文字拆到几个文本文件中,加入了最后一行必须以句号:.为结尾(相对英文文件文本)如果是汉语,可以加入结尾是否是汉字句号:。的判断。
压缩文件相对于程序代码路径:./htmzip
解压的htm文件相对于程序代码路径:./htm
txt文件相对于程序代码路径:./txt
完整主程序代码:
import os
import parsehtmltext
import zipfile
def startjob():
zipfilelist = getfilelist('./htmzip', '.zip')
count = 1
for filepath in zipfilelist:
(filefolder, zipfilename) = os.path.split(filepath)
print('handle the %d file: %s start' % (count, zipfilename))
unzipfolder = './htm/%s' % (zipfilename)
unzip(filepath, unzipfolder)
htmlfilelist = getfilelist(unzipfolder, '.htm')
if len(htmlfilelist) > 0:
txtfilelist = splithtmltotxt(htmlfilelist[0],
'./txt/%s' % (zipfilename))
print(txtfilelist)
count += 1
def getfilelist(folderpath, extension):
filelist = []
for (root, dirs, files) in os.walk(folderpath):
for filename in files:
if filename.lower().endswith(extension.lower()):
filepath = os.path.join(root, filename).replace('\\','/')
filelist.append(filepath)
return filelist
def splithtmltotxt(htmfile, txtfolder):
html = open(htmfile, 'r', encoding='utf-8')
htmlpage = html.read()
wholetextlines = parsehtmltext.dehtml(htmlpage).split('\n')
if len(wholetextlines) == 1 and len(wholetextlines[0].strip()) > 100:
wholetextlines = wholetextlines[0].split('.')
testblock = []
if os.path.isdir(txtfolder):
pass
else:
os.mkdir(txtfolder)
txtfilelist = []
#整体计数器
count = 1
#用于单文本文件行数的计数器
eachcount = 0
#文本文件数量的计数器
txtfilecount = 1
totalcount = len(wholetextlines)
# print(wholetextlines)
# print(totalcount)
for line in wholetextlines:
if line.split():
testblock.append(line.strip() + '\n')
eachcount += 1
# print('each count is %d, count is %d, total count is %d' % (eachcount, count, totalcount))
if (eachcount >= 500
and (line.endswith('\n') or line.strip().endswith('.')))\
or count == totalcount:
txtfilename = '%s/%d.txt' % (txtfolder, txtfilecount)
with open(txtfilename, 'w', encoding='utf-8') as f:
f.writelines(testblock)
# print('save txt file: %s'% txtfilename)
txtfilelist.append(txtfilename)
#reset single counter
testblock = []
eachcount = 0
txtfilecount += 1
count += 1
return txtfilelist
def unzip(sourcefile, unzipfolder):
with zipfile.ZipFile(sourcefile) as zip_file:
if os.path.isdir(unzipfolder):
pass
else:
os.mkdir(unzipfolder)
for names in zip_file.namelist():
zip_file.extract(names, unzipfolder)
if __name__ == '__main__':
startjob()