Pythonpython自学scrapy

Python从网页文件获取纯文本并拆分文本文件

2018-06-01  本文已影响49人  blade_he

从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)

但是这样做的问题在于,其控制文本的格式或许与浏览器端显示的不一样
浏览器端显示的格式:


2018-06-01 14_36_17-Document.png

bs4抓取的文本格式如下:


2018-06-01 15_06_04-.png
为什么会这样呢?
因为在html源码中,存在这样的换行:
2018-06-01 15_09_30-Document.png

可以理解为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
from HTMLParser 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

之后提取的文本就是符合我们格式要求的:


2018-06-01 15_19_08-htmltotext [D__Blade_MorningStar.Demo_github_htmltotext] - ..._txt_159343589_0cd.png

主程序代码

包括:解压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()
上一篇下一篇

猜你喜欢

热点阅读