html文本中链接的正则表达式
Posted
技术标签:
【中文标题】html文本中链接的正则表达式【英文标题】:Regex for links in html text 【发布时间】:2010-09-30 15:58:54 【问题描述】:我希望这个问题不是 RTFM 问题。
我正在尝试编写一个从标准 html 网页(<link href...
标签)中提取链接的 Python 脚本。
我在网上搜索了匹配的正则表达式,发现了许多不同的模式。是否有任何公认的标准正则表达式来匹配链接?
亚当
更新: 我实际上正在寻找两个不同的答案:
-
什么是解析 HTML 链接的库解决方案。 Beautiful Soup 似乎是一个很好的解决方案(感谢
Igal Serban
和 cletus
!)
可以使用正则表达式定义链接吗?
【问题讨论】:
【参考方案1】:正如其他人所建议的,如果不需要类似实时的性能,BeautifulSoup 是一个很好的解决方案:
import urllib2
from BeautifulSoup import BeautifulSoup
html = urllib2.urlopen("http://www.google.com").read()
soup = BeautifulSoup(html)
all_links = soup.findAll("a")
至于第二个问题,是的,HTML 链接应该是明确定义的,但您实际遇到的 HTML 不太可能是标准的。 BeautifulSoup 的美妙之处在于它使用类似浏览器的启发式方法来尝试解析您可能实际遇到的非标准、格式错误的 HTML。
如果您确定要使用标准 XHTML,则可以使用(快得多)像 expat 这样的 XML 解析器。
正则表达式,由于上述原因(解析器必须保持状态,而正则表达式不能做到这一点)永远不会是一个通用的解决方案。
【讨论】:
【参考方案2】:链接不应该是定义明确的正则表达式吗?这是一个相当理论的问题,
我第二个PEZ的回答:
我认为 HTML 不适合“定义明确”的正则表达式,因为它不是常规语言。
据我所知,任何 HTML 标签都可能包含任意数量的嵌套标签。例如:
<a href="http://***.com">***</a>
<a href="http://***.com"><i>***</i></a>
<a href="http://***.com"><b><i>***</i></b></a>
...
因此,原则上,要正确匹配标签,您至少必须能够匹配以下形式的字符串:
BE
BBEE
BBBEEE
...
BBBBBBBBBBEEEEEEEEEE
...
其中 B 表示标签的开始,E 表示结束。也就是说,您必须能够匹配由任意数量的 B 后跟 相同 数量的 E 组成的字符串。为此,您的匹配器必须能够“计数”,而正则表达式(即有限状态自动机)根本无法做到这一点(为了计数,自动机至少需要一个堆栈)。参考 PEZ 的回答,HTML 是上下文无关语法,而不是常规语言。
【讨论】:
不,您实际上不需要任何这些。在 HTML 中,A 标签不能嵌套,其中的内容超出了您获取链接所需的内容。【参考方案3】:在回答问题 #2(链接不应该是定义明确的正则表达式)时,答案是……不。
HTML 链接结构是递归的,很像编程语言中的括号和大括号。必须有相同数量的 start 和 end 构造,并且“link”表达式可以嵌套在其自身中。
要正确匹配“链接”表达式,需要正则表达式来计算开始和结束标签。正则表达式是有限自动机的一类。根据定义,有限自动机不能“计数”模式中的构造。需要语法来描述这样的递归数据结构。正则表达式无法“计数”这就是为什么您会看到用语法描述的编程语言而不是正则表达式。
因此,不可能创建一个 100% 正则匹配所有“链接”表达式的正则表达式。当然,有一些正则表达式可以高精度地匹配大量“链接”,但它们永远不会完美。
我最近写了一篇关于这个问题的博客文章。 Regular Expression Limitations
【讨论】:
既有趣又有帮助 - 谢谢。顺便说一句,这个问题可以通过下推堆栈自动机解决,它比正则表达式具有更多的计算能力 - 这可以使用泵引理 (en.wikipedia.org/wiki/Pumping_lemma) 轻松证明 不正确。 HTML 中的递归结构(如表格中的表格和许多其他结构)肯定不能被 RE 解析,但 LINK 和 As 在 HTML 中是递归的,因此您无需关心获取链接的递归结构。 @jpalecek,你不正确。一个 A 标记肯定是递归的,因为 A 标记的内容可以包含另一个 A 标记。它可能看起来很奇怪,但它肯定是可解析的 HTML 否,A 标记不能包含 A 标记。在 HTML 4.01 DTD 中:“w3.org/TR/xhtml1/#prohibitions 禁止它。 @jpalecek,很有趣。我通常更多地从“它是否可解析”而不是“它是否合法 html”来处理这些问题,因为网站往往站在前者的一边。即使通过嵌入 CDATA 或文字字符串,您仍然可以在其中包含字面上的 。【参考方案4】:链接不应该是定义明确的正则表达式吗?
不,[X]HTML 在一般情况下不能用正则表达式解析。考虑以下示例:
<link title='hello">world' href="x">link</link>
<!-- <link href="x">not a link</link> -->
<![CDATA[ ><link href="x">not a link</link> ]]>
<script>document.write('<link href="x">not a link</link>')</script>
这只是一些随机的有效示例;如果您必须处理现实世界的标签汤 HTML,那么存在一百万种格式错误的可能性。
如果您知道并且可以依赖目标页面的确切输出格式,则可以使用正则表达式。否则就是完全错误的网页抓取选择。
【讨论】:
您的所有示例实际上都可以通过正则表达式解析(并不是说最后一个无效)。 XML SAX 解析器(这是 OP 需要的)只不过是 RE 定义的语言的词法分析器。 “畸形的可能性”对此没有任何改变。【参考方案5】:在那里回答你的两个子问题。
-
我有时将 SGMLParser 子类化(包含在核心 Python 发行版中)并且必须说它是直截了当的。
我认为 HTML 不适合“定义明确的”正则表达式,因为它不是常规语言。
【讨论】:
可能是这样。在我工作的地方,事情并不总是最前沿的。 =) :-) 有什么合适的 py3 替换建议吗? 并非如此。也许这篇文章可以提供一些线索:boddie.org.uk/python/HTML.html【参考方案6】:这在一定程度上取决于 HTML 的生成方式。如果它受到一定程度的控制,您可以逃脱:
re.findall(r'''<link\s+.*?href=['"](.*?)['"].*?(?:</link|/)>''', html, re.I)
【讨论】:
【参考方案7】:没有。
您可以考虑使用Beautiful Soup。可以称它为解析html文件的标准。
【讨论】:
【参考方案8】:带有 HTML 的正则表达式变得混乱。只需使用 Beautiful Soup 之类的 DOM 解析器。
【讨论】:
+1:不,HTML 不能用正则表达式描述。它更复杂。而且,更糟糕的是,浏览器被允许接受无效的 HTML,因此网站会发送无效的 HTML。 我发誓这个问题的出现足以保证在常见问题上的粘性以上是关于html文本中链接的正则表达式的主要内容,如果未能解决你的问题,请参考以下文章
使用正则表达式重新字符串匹配提取 URL 链接 - Python