在stackoverflow上,似乎每一个使用正则表达式从HTML中获取信息的提问者都会不可避免地得到一个“答案”,该答案说不要使用正则表达式解析HTML。
为什么不呢?我知道有所谓的“真正”的HTML解析器,比如Beautiful Soup,我相信它们很强大和有用,但是如果你只是做一些简单、快速或粗糙的事情,那么为什么要使用这么复杂的东西,当几个正则表达式语句也可以工作得很好呢?
此外,是否有一些基本的东西我没有理解,使得正则表达式在解析中总是不好的选择?
在stackoverflow上,似乎每一个使用正则表达式从HTML中获取信息的提问者都会不可避免地得到一个“答案”,该答案说不要使用正则表达式解析HTML。
为什么不呢?我知道有所谓的“真正”的HTML解析器,比如Beautiful Soup,我相信它们很强大和有用,但是如果你只是做一些简单、快速或粗糙的事情,那么为什么要使用这么复杂的东西,当几个正则表达式语句也可以工作得很好呢?
此外,是否有一些基本的东西我没有理解,使得正则表达式在解析中总是不好的选择?
这个表达式用于提取HTML元素的属性,支持以下内容:
(?:\<\!\-\-(?:(?!\-\-\>)\r\n?|\n|.)*?-\-\>)|(?:<(\S+)\s+(?=.*>)|(?<=[=\s])\G)(?:((?:(?!\s|=).)*)\s*?=\s*?[\"']?((?:(?<=\")(?:(?<=\\)\"|[^\"])*|(?<=')(?:(?<=\\)'|[^'])*)|(?:(?!\"|')(?:(?!\/>|>|\s).)+))[\"']?\s*)
点击查看。使用“gisx”标志可以更好地运行,如演示所示。
<script>
标记内部的JavaScript代码片段中。 - tripleee有些情况下,使用正则表达式从HTML中提取信息是正确的方法 - 这取决于具体情况。
总的来说,人们普遍认为这是一个不好的主意。然而,如果已知HTML结构(且不太可能更改),那么这仍然是一种有效的方法。
(?P<content>.*?) # Content up to next tag
(?P<markup> # Entire tag
<!\[CDATA\[(?P<cdata>.+?)]]>| # <![CDATA[ ... ]]>
<!--(?P<comment>.+?)-->| # <!-- Comment -->
</\s*(?P<close_tag>\w+)\s*>| # </tag>
<(?P<tag>\w+) # <tag ...
(?P<attributes>
(?P<attribute>\s+
# <snip>: Use this part to get the attributes out of 'attributes' group.
(?P<attribute_name>\w+)
(?:\s*=\s*
(?P<attribute_value>
[\w:/.\-]+| # Unquoted
(?=(?P<_v> # Quoted
(?P<_q>['\"]).*?(?<!\\)(?P=_q)))
(?P=_v)
))?
# </snip>
)*
)\s*
(?P<is_self_closing>/?) # Self-closing indicator
>) # End of tag
这个正则表达式是为Python设计的(可能适用于其他语言,但我没有尝试过),它使用了正向先行断言、负向后顾断言和命名反向引用。支持以下内容:
<div ...>
</div>
<!-- ... -->
<![CDATA[ ... ]]>
<div .../>
<input checked>
<div style='...'>
<div style="...">
<a title='John\'s Story'>
<a href = '...'>
它还可以很好地避免触发格式不正确的标签,例如当您忘记使用<
或>
时。
如果您的正则表达式支持重复命名捕获,则很棒,但Python的re
不支持(我知道regex支持,但我需要使用原始Python)。下面是您将获得的内容:
content
- 所有标签内的内容,不包括下一个标签。可以省略。markup
- 包含全部内容的标签。comment
- 如果是注释,那么是注释的内容。cdata
- 如果是<![CDATA[...]]>
,那么是CDATA的内容。close_tag
- 如果是闭合标签(</div>
),那么是标签名。tag
- 如果是开放标签(<div>
),那么是标签名。attributes
- 标签内的所有属性。如果没有重复组,则使用此属性获取所有属性。attribute
- 重复出现的每个属性。attribute_name
- 重复出现的每个属性名称。attribute_value
- 重复出现的每个属性值。如果有引号,则包括引号。is_self_closing
- 如果是自闭合标签,则为/
;否则为空。_q
和_v
- 忽略这些;它们用于内部反向引用。如果你的正则表达式引擎不支持重复命名捕获,则有一个部分可以用来获取每个属性。只需在attributes
组上运行该正则表达式即可获取其中的每个attribute
、attribute_name
和attribute_value
。
strrpos
反向解析整个字符串,找到 <
,然后每次都使用非贪婪匹配符重复执行正则表达式来解决嵌套标签问题。这种方法不太高端,并且在处理大型内容时速度非常慢,但我在我的个人网站模板编辑器中使用了它。我实际上并没有解析HTML,而是用一些自定义标签来查询数据库条目以显示数据表格(例如我的<#if()>
标签可以这样突出显示特殊条目)。我也没有准备在少数几个自己创建的标签(其中包含非XML数据)上使用XML解析器。
所以,即使这个问题已经相当老旧,但仍然会在谷歌搜索中出现。我看到了这个问题,认为“接受挑战”,并完成了代码的修复,而无需替换所有内容。决定为搜索类似原因的任何人提供不同的意见。此外,最后一个答案是4小时前发布的,因此这仍然是一个热门话题。
<tag >
)你有考虑注释掉的闭合标签吗?(例如,<tag> <!-- </tag> -->
)你有考虑 CDATA 吗?你有考虑大小写不一致的标签吗?(例如,<Tag> </tAG>
)你也考虑了这个吗? - rmunn正则表达式对于像HTML这样的语言来说并不足够强大。当然,有一些例子可以使用正则表达式。但总体而言,它不适合用于解析。
</img>
例如。然后,为缺少单个HTML斜杠的元素添加闭合标签等。[x].getElementsByTagName()
的HTML元素检索。我只需将我在正则表达式的DEFINE部分编写的功能切割出来,并用它逐个步进到元素树中。
那么,这将是验证HTML的最终100%答案吗?不是。但这是一个开始,再多做一些工作就可以完成。然而,在一个正则表达式执行中尝试完成它并不实际,也不高效。