从格式不正确的 HTML 页面提取文本的 Python 方法

5 投票
3 回答
1992 浏览
提问于 2025-04-15 15:19

我正在尝试从一些任意的网页中提取文本。有些网页(我无法控制这些网页)存在格式错误的HTML或者包含一些脚本,这让提取变得很困难。而且我使用的是共享主机环境,所以我可以安装一些Python库,但不能随便在服务器上安装任何东西。

pyparsing和html2text.py似乎也无法处理格式错误的HTML页面。

一个示例网址是 http://apnews.myway.com/article/20091015/D9BB7CGG1.html

我现在的实现大致如下:

# Try using BeautifulSoup 3.0.7a
soup = BeautifulSoup.BeautifulSoup(s) 
comments = soup.findAll(text=lambda text:isinstance(text,Comment))
[comment.extract() for comment in comments]
c=soup.findAll('script')
for i in c:
    i.extract()    
body = bsoup.body(text=True)
text = ''.join(body) 
# if BeautifulSoup  can't handle it, 
# alter html by trying to find 1st instance of  "<body" and replace everything prior to that, with "<html><head></head>"
# try beautifulsoup again with new html 

如果beautifulsoup仍然无法工作,我就会采用一种启发式的方法,查看第一和最后一个字符(看看它们是否像是代码行的标记,比如<),然后取一部分行来检查这些词是否是英语单词或数字。如果这些词或数字太少,我就会猜测这一行是代码。

我可以使用机器学习来检查每一行,但这似乎有点复杂,而且我可能还需要训练它(因为我对无监督学习的机器了解不多),当然还得自己编写代码。

任何建议、工具或策略都非常欢迎。此外,我意识到后面提到的部分有点乱,因为如果我判断某一行包含代码,我现在会直接丢掉整行,即使这一行中有一些实际的英语文本。

3 个回答

0

BeautifulSoup在处理格式不正确的HTML时表现不好。那么用正则表达式来解决这个问题怎么样呢?

>>> import re
>>> 
>>> html = """<p>This is paragraph with a bunch of lines
... from a news story.</p>"""
>>> 
>>> pattern = re.compile('(?<=p>).+(?=</p)', re.DOTALL)
>>> pattern.search(html).group()
'This is paragraph with a bunch of lines\nfrom a news story.'

你可以先整理出一个有效标签的列表,从中提取你想要的信息。

0

这要看你需要的解决方案有多好。我之前也遇到过类似的问题,要把几百个旧的html页面导入到一个新网站里。我基本上是这样做的:

# remove all that crap around the body and let BS fix the tags
newhtml = "<html><body>%s</body></html>" % (
    u''.join( unicode( tag ) for tag in BeautifulSoup( oldhtml ).body.contents ))
# use html2text to turn it into text
text = html2text( newhtml )

结果还不错,但当然了,如果那些文档质量太差,连BS(一个工具)也帮不了你太多。

5

别笑我,但:

class TextFormatter:
    def __init__(self,lynx='/usr/bin/lynx'):
        self.lynx = lynx

    def html2text(self, unicode_html_source):
        "Expects unicode; returns unicode"
        return Popen([self.lynx, 
                      '-assume-charset=UTF-8', 
                      '-display-charset=UTF-8', 
                      '-dump', 
                      '-stdin'], 
                      stdin=PIPE, 
                      stdout=PIPE).communicate(input=unicode_html_source.encode('utf-8'))[0].decode('utf-8')

我希望你有lynx这个工具!

撰写回答