正则表达式以各种格式/标签查找图像

时间:2017-11-29 13:32:11

标签: python regex python-3.x

我需要一个在网站源代码中查找图像的正则表达式。到目前为止我有这个:

images = re.findall(r'src=[\"|\']([^\"|\']+)[\"|\']',webpage.decode())
images.sort()
print (f'[+] {len(images)} images Found:')
for image in images:
    print(image)

这是以以下格式查找图像:

<img src="2001-a-space-odyssey.JPG"/>

<img src="http://www.example.com/content/icon.gif"/>

但找不到以下格式的图片:

<form action="example.jpg">

<!-- <img src="big.jpg" /> -->

background-image:url("xine.png");

我需要一个正则表达式才能找到所有这些,但是,我不想要一个类似于png|jpeg|gif等的表达式。

3 个答案:

答案 0 :(得分:1)

正如Ôrel指出的那样,这对正则表达式来说真的不是一个工作。在这个答案中,我将尽力接近一个可接受的答案,但是当它表明正则表达式不是正确的工具时,我会避免英勇的努力,但我认为可以用正则表达式合理地解决。

考虑arbitrary whitespace(例如< i m g s r c = "foo.jpg" >)会破坏模式;你可以使用预处理器来处理这个问题(将空格不敏感的正则表达式转换为在所有可能的位置添加可选空格的表达式)。 (英雄。)

您特别不想匹配src="foo',因为单引号可以包含双引号,反之亦然(例如src="'hello'.jpg")。在这里,您可以使用捕获组((...))和反向引用(\1):

>>> s = "src='hello', src=\"world\", src='foo\"bar\"', src=\"'quotes'suck\""
>>> [ src[1] for src in re.findall(r'src=(["\'])(.*?)\1', s) ]
['hello', 'world', 'foo"bar"', "'quotes'suck"]

当属性(错误地)缺少引号时(例如src=foo.jpg),这将不起作用。您可以稍微扩展模式。由于现在有两个(互斥)捕获组,我将使用src[1] or src[2]捕获的任何一个:

>>> s = "<img src='foo.jpg'>, <img src=baz.gif>, <img src=\"bar.png\">"
>>> [ src[1] or src[2] for src in re.findall(r'src=(["\'])(.*?)\1|src=([^\s>\'"]+)', s) ]
['foo.jpg', 'baz.gif', 'bar.png']

src="..."个属性可能不属于<img>个标签(例如,它们可能属于<script>个标签)。您也可以匹配标记,但除了任意空格之外,您还必须在src="..."属性(例如<img alt="wat" src="wat.png">)之前考虑任意数量的先前属性,并且只是< / em>图片标签。 (英雄。)

您可以改为使用cssselect来提取<img src="...">代码:

from cssselect import GenericTranslator
from lxml.etree import fromstring

selector = GenericTranslator().css_to_xpath('img')
document = fromstring(...)
urls = [ e.get('src') for e in document.xpath(selector) ]

这对HTML的许多可能格式,属性的排序等都很有用。如果是tag soup,则lxml为pretty robust

你也可以试试Scrapy的运气。请参阅:Extracting Images in Scrapy(StackOverflow)

当图像位于相对地址时,您必须记住的另一件事是<base>标记。一个抓取框架或headless browser将控制它。

我将分别处理其他三个案件:

  1. 如果您想考虑<form action="some.gif">对图像的引用,并且您不想基于简单的文件扩展名进行过滤,那么您只能通过获取URL并匹配{{ 1}}标题针对Content-Type,因为表单请求的结果很可能不是直接图像。这里一个带有CSS选择器的HTML解析器同样有用,但是我不知道你是否可以安全地假设如果表单字段没有正确填写,那么表单将为你提供正确的Content-Type,这样就会出现另一个非常重要的问题。问题

  2. 由于像image/*这样的HTML注释中的图像标记不是DOM的一部分,因此使用HTML解析器不会对您有所帮助。但是,由于这里不错的解决方案并不好,使用正则表达式至少可以捕获一些微不足道的案例。或者,您可以搜索并替换<!-- <img src="big.jpg" /> --><!--的所有情况,以便将内容重新包含到DOM中,以便可以使用HTML解析器提取它,但是您可能会冒破坏格式良好的HTML文档的风险那样。不过,您可能会冒任何HTML文档从一开始就被打破的风险。

  3. 如果您还希望包含像-->这样的CSS源图像,那么在正则表达式方面你就同样深入:HTML和CSS都不是常规语言。我不确定哪些刮刀让你遍历所有网站的样式,但我猜你需要提取background-image: url(xine.png)部分,外部源样式表和<style>标签,并用CSS遍历这些块。像tinycss这样的解析器。

    请记住,style="..."标记适用于内部和外部加载的样式表。

    但是,如果你想从CSS中提取<base>,请考虑这个:

    url(...)

    这也不考虑任意空格。

  4. 此时您还没有处理在运行时以各种方式加载的图像。您可以运行headless browser并访问网站并从其缓存中提取图片,但是您无法确定CSS media queries是否排除了您高分辨率背景图片或移动专用图标。

答案 1 :(得分:0)

如果您对图像格式不太感兴趣,那么下面的表达式可以很好地完成您的工作:

pattern = "[\"|\'].*\.(?i:jpg|gif|png|bmp)[\"|\']"
images = re.findall(pattern,webpage.decode())

?我在这里我会忽略这个案例。

修改

pattern : "[\=,\(][\"|\'].[^\=\"]+\.(?i:jpg|gif|png|bmp)[\"|\']"

注意:从匹配中删除前两个字符和最后一个字符应该提供所需的输出

您可以在此处查看各种图片格式:Image file formats

希望这会有所帮助:)

答案 2 :(得分:0)

您可以使用以下regex来获取所有图片:

data = '''<form action="example.jpg">
<!-- <img src="big.jpg" /> -->
background-image:url("xine.png");
<img src="2001-a-space-odyssey.JPG"/>
<img src="http://www.example.com/content/icon.gif"/>
'''

>>> re.findall("([-\w]+\.(?:jpg|gif|png|jpeg))", data, re.IGNORECASE)

['example.jpg', 'big.jpg', 'xine.png', '2001-a-space-odyssey.JPG', 'icon.gif']