如何创建正则表达式以从字符串中提取所有锚标记或链接?

时间:2011-11-01 16:56:15

标签: python regex

我已经看到了其他问题,这些问题将解析所有普通链接或字符串中的所有锚标记,但没有任何内容同时解析。

理想情况下,正则表达式将能够解析这样的字符串(我正在使用Python):

>>> import re
>>> content = '
    <a href="http://www.google.com">http://www.google.com</a> Some other text.
    And even more text! http://stackoverflow.com
    '
>>> links = re.findall('some-regular-expression', content)
>>> print links
[u'http://www.google.com', u'http://stackoverflow.com']

是否可以生成一个不会导致返回重复链接的正则表达式?有更好的方法吗?

5 个答案:

答案 0 :(得分:1)

通常为you should never parse HTML with regular expressions,因为HTML不是常规语言。在这里,你似乎只想获得它们在A元素或文本中的所有http链接。如何获取所有内容然后删除重复项?

尝试类似

的内容
set(re.findall("(http:\/\/.*?)[\"' <]", content))

并查看它是否符合您的目的。

答案 1 :(得分:1)

无论你做什么,它都会变得凌乱。然而,90%的解决方案可能类似于:

r'<a\s[^>]*>([^<]*)</a>|\b(\w+://[^<>\'"\t\r\n\xc2\xa0]*[^<>\'"\t\r\n\xc2\xa0 .,()])'

由于该模式有两个组,它将返回一个2元组的列表;加入他们,你可以使用列表理解甚至地图:

map(''.join, re.findall(pattern, content))

如果你想要锚点的src属性而不是链接文本,那么模式会变得更加混乱:

r'<a\s[^>]*src=[\'"]([^"\']*)[\'"][^>]*>[^<]*</a>|\b(\w+://[^<>\'"\t\r\n\xc2\xa0]*[^<>\'"\t\r\n\xc2\xa0 .,()])'

或者,你可以让模式的后半部分选择src属性,这也减少了字符串连接的需要:

r'\b\w+://[^<>\'"\t\r\n\xc2\xa0]*[^<>\'"\t\r\n\xc2\xa0 .,()]'

一旦你有了这么多,你可以用看起来像链接的东西替换任何找到的链接,搜索'://',并更新模式以收集错过的内容。您可能还需要清理误报,特别是最后的垃圾。 (这种模式必须找到包含空格的链接,以纯文本形式显示,因此特别容易出现过度贪婪。)

警告:不要依赖于此以用于将来的用户输入,尤其是当安全性在线时。它最好仅用于从现有数据手动收集链接。

答案 2 :(得分:0)

编写与所有有效网址匹配的正则表达式模式为tricky business

如果您要查找的只是在任意字符串中检测简单的http / https网址,我可以为您提供此解决方案:

>>> import re
>>> content = '<a href="http://www.google.com">http://www.google.com</a> Some other text. And even more text! http://stackoverflow.com'
>>> re.findall(r"https?://[\w\-.~/?:#\[\]@!$&'()*+,;=]+", content)
['http://www.google.com', 'http://www.google.com', 'http://stackoverflow.com']

查找以http://或https://开头的字符串,后跟一个或多个有效字符。

为避免重复输入,请使用set()

>>> list(set(re.findall(r"https?://[\w\-.~/?:#\[\]@!$&'()*+,;=]+", content)))
['http://www.google.com', 'http://stackoverflow.com']

答案 3 :(得分:0)

您不应该使用正则表达式从HTML中提取内容。您应该使用HTML解析器。

如果您还想从页面文本中提取内容,那么您应该单独执行此操作。

以下是使用lxml

执行此操作的方法
# -*- coding: utf8 -*-

import lxml.html as lh
import re

html = """
is.gd/test<a href="http://www.google.com">http://www.google.com</a> Some other text.
And even more text! http://stackoverflow.com

here's a url bit.ly/test


"""

tree = lh.fromstring(html)

urls = set([])

for a in tree.xpath('//a'):
    urls.add(a.text)

for text in tree.xpath('//text()'):
    for url in re.findall(r'(?i)\b((?:https?://|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:\'".,<>?«»“”‘’]))', text):
        urls.add(url[0])

print urls

<强>结果:

set(['http://www.google.com', 'bit.ly/test', 'http://stackoverflow.com', 'is.gd/test'])

此处的网址匹配正则表达式:http://daringfireball.net/2010/07/improved_regex_for_matching_urls

答案 4 :(得分:-1)

不,它无法像这样解析字符串。 Regexp能够进行简单的匹配,你只能使用一个或两个正则表达式来解析复杂的语法为html。