如何使用正则表达式提取字符串中的所有链接或锚点标签?
我看到过其他问题,它们可以从字符串中提取所有普通链接或者所有锚标签,但没有看到能同时做到这两点的。
理想情况下,我希望这个正则表达式能够解析像这样的字符串(我在用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
如果你只是想在一个任意字符串中找出简单的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']
1
通常情况下,你不应该用正则表达式来解析HTML,因为HTML并不是一种规则语言。在这里,看起来你只是想获取所有的http链接,无论它们是在A标签里还是在文本中。那不如先把它们都找出来,然后再去掉重复的链接呢?
试试下面的代码:
set(re.findall("(http:\/\/.*?)[\"' <]", content))
看看这样是否能满足你的需求。
1
无论你怎么做,结果都会有点乱。不过,一个大概90%有效的解决方案可能看起来像这样:
r'<a\s[^>]*>([^<]*)</a>|\b(\w+://[^<>\'"\t\r\n\xc2\xa0]*[^<>\'"\t\r\n\xc2\xa0 .,()])'
因为这个模式有两个部分,所以它会返回一个包含两个元素的列表。要把它们合并在一起,你可以用列表推导式,或者直接用一个映射函数:
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 .,()]'
一旦你有了这些基础,你就可以把找到的链接替换成看起来不像链接的东西,搜索'://'
,并更新模式以收集遗漏的部分。你可能还需要清理一些错误的结果,特别是那些末尾的垃圾内容。(这个模式需要找到包含空格的链接,所以它特别容易出现过度匹配的问题。)
警告:不要依赖这个方法来处理未来的用户输入,尤其是在安全性方面。最好只用它来手动收集已有数据中的链接。