如何用Python检测字符串是否包含HTML代码?

37 投票
6 回答
36269 浏览
提问于 2025-04-18 14:03

如何判断一个字符串里是否包含HTML内容(可以是HTML4、HTML5,或者只是文本中的部分HTML)?我不需要知道HTML的版本,只想知道这个字符串是纯文本还是包含HTML。通常,文本是多行的,还可能有空行。

更新:

示例输入:

包含HTML的:

<head><title>I'm title</title></head>
Hello, <b>world</b>

不包含HTML的:

<ht fldf d><
<html><head> head <body></body> html

6 个回答

-4

检查是否有结束标签。我觉得这是最简单也是最可靠的方法。

"</html>" in possibly_html

如果有结束的HTML标签,那么它看起来就像是HTML,否则就不太像了。

1

如果你只想知道一个字符串里是否包含HTML文本,那么这里有一个没提到的简单方法,就是用一个正则表达式,像下面这样:

</?\s*[a-z-][^>]*\s*>|(\&(?:[\w\d]+|#\d+|#x[a-f\d]+);)

需要注意的是,虽然这个方法比用HTML解析器要快很多,但根据你期待的HTML标记的复杂程度,它可能会不太准确。

这里有一个测试,可以让你大概了解这个正则表达式的适用范围。

2

你可以很简单地扩展内置的 HTMLParser,这个工具已经可以处理解析工作,并且可以收集(开始/结束)标签属性数据。为了确认文档是否有效,开始标签的数量应该和结束标签的数量相匹配:

from html.parser import HTMLParser


class MyHTMLParser(HTMLParser):
    def __init__(self):
        super().__init__()
        self.start_tags = list()
        self.end_tags = list()
        self.attributes = list()
    
    def is_text_html(self):
        return len(self.start_tags) == len(self.end_tags)

    def handle_starttag(self, tag, attrs):
        self.start_tags.append(tag)
        self.attributes.append(attrs)

    def handle_endtag(self, tag):
        self.end_tags.append(tag)

    def handle_data(self, data):
        print("Encountered some data  :", data)

然后

>>> parser = MyHTMLParser()
>>> parser.feed("<head><title>I'm title</title></head>"
                "Hello, <b>world</b>")
>>> parser.is_text_html()

True

>>> parser.feed("<ht fldf d><"
                "<html><head> head <body></body> html")
>>> parser.is_text_html()

False
8

我想到的一种方法是,通过尝试把文本当作HTML来解析,找到开始标签和结束标签,然后把这些标签和一组已知的可接受的HTML元素进行交集。

举个例子:

#!/usr/bin/env python

from __future__ import print_function

from HTMLParser import HTMLParser


from html5lib.sanitizer import HTMLSanitizerMixin


class TestHTMLParser(HTMLParser):

    def __init__(self, *args, **kwargs):
        HTMLParser.__init__(self, *args, **kwargs)

        self.elements = set()

    def handle_starttag(self, tag, attrs):
        self.elements.add(tag)

    def handle_endtag(self, tag):
        self.elements.add(tag)


def is_html(text):
    elements = set(HTMLSanitizerMixin.acceptable_elements)

    parser = TestHTMLParser()
    parser.feed(text)

    return True if parser.elements.intersection(elements) else False


print(is_html("foo bar"))
print(is_html("<p>Hello World!</p>"))
print(is_html("<html><head><title>Title</title></head><body><p>Hello!</p></body></html>"))  # noqa

输出结果:

$ python foo.py
False
True
True

这个方法适用于包含部分HTML元素的文本。

注意:这个方法使用了 html5lib,所以可能不适用于其他类型的文档,但这个技巧可以很容易地进行调整。

57

你可以使用一个叫做 BeautifulSoup 的HTML解析器。这个工具非常努力地去解析HTML,即使是那些有点问题的HTML,它的宽容程度会根据所用的底层解析器而有所不同。

>>> from bs4 import BeautifulSoup
>>> html = """<html>
... <head><title>I'm title</title></head>
... </html>"""
>>> non_html = "This is not an html"
>>> bool(BeautifulSoup(html, "html.parser").find())
True
>>> bool(BeautifulSoup(non_html, "html.parser").find())
False

这个基本上是尝试在字符串中找到任何HTML元素。如果找到了,结果就是 True

这里有一个关于HTML片段的另一个例子:

>>> html = "Hello, <b>world</b>"
>>> bool(BeautifulSoup(html, "html.parser").find())
True

另外,你也可以使用 lxml.html

>>> import lxml.html
>>> html = 'Hello, <b>world</b>'
>>> non_html = "<ht fldf d><"
>>> lxml.html.fromstring(html).find('.//*') is not None
True
>>> lxml.html.fromstring(non_html).find('.//*') is not None
False

撰写回答