Irmu
Free tool

Image URL extractor

Paste HTML, Markdown, CSS, JSON or plain text and pull out every image URL — including lazy-loaded, srcset and CSS background images. Preview them, then export as TXT, CSV or JSON.

Formats
HTML, Markdown, code or text input
0 image URLs
0 images · 0 domains · deduplicatedRuns entirely in your browser — nothing is uploaded.
Code examples

Do the same thing in your own pipeline

The tool above parses in the browser. Here is the equivalent image extraction with the standard HTML parser in each language.

# pip install beautifulsoup4

import re
from urllib.parse import urljoin
from bs4 import BeautifulSoup

IMAGE_EXT = re.compile(r"\.(jpe?g|png|gif|webp|avif|svg|bmp|ico|tiff?)($|\?)", re.I)

def extract_image_urls(html: str, base: str) -> list[str]:
    soup = BeautifulSoup(html, "html.parser")
    found: list[str] = []

    for img in soup.find_all("img"):
        for attr in ("src", "data-src", "data-original", "data-lazy-src"):
            if img.get(attr):
                found.append(img[attr])
        for srcset in (img.get("srcset"), img.get("data-srcset")):
            if srcset:
                found += [part.strip().split(" ")[0] for part in srcset.split(",") if part.strip()]

    for source in soup.select("picture source[srcset]"):
        found += [part.strip().split(" ")[0] for part in source["srcset"].split(",") if part.strip()]

    for meta in soup.select('meta[property*="image"], meta[name*="image"]'):
        if meta.get("content"):
            found.append(meta["content"])

    for el in soup.select("[style]"):
        found += re.findall(r"url\(\s*['\"]?([^'\")]+)", el["style"])

    seen, out = set(), []
    for value in found:
        url = urljoin(base, value.strip())
        if not url.startswith("http") or not IMAGE_EXT.search(url):
            continue
        if url not in seen:
            seen.add(url)
            out.append(url)
    return out

html = '<img src="/assets/hero.png" alt="Hero"><img data-src="https://cdn.example.com/a.webp">'
for url in extract_image_urls(html, "https://example.com/"):
    print(url)
How it works

Where image URLs actually hide

  • img src plus the lazy-loading attributes real sites use — data-src, data-original, data-lazy-src.
  • Every candidate inside srcset, data-srcset and picture sources, with its width or density descriptor kept.
  • CSS backgrounds: url() values in style attributes and inline style blocks.
  • Social and structured data: Open Graph and Twitter image tags, favicons, apple-touch icons and image fields in JSON-LD.
  • Anything else: quoted image paths in JSON, JS or CSS, Markdown image syntax and bare URLs in plain text.
  • Relative paths resolved against your base URL, deduplicated, filtered by format and domain, then exported.
With Irmu

When you also need to fetch the page

Most product galleries only appear after JavaScript runs. Irmu renders the page and returns the final HTML — extract the images from that.

crawl_to_images.py
# pip install requests beautifulsoup4

import csv, os, requests
from urllib.parse import urljoin
from bs4 import BeautifulSoup

target = "https://example.com/products/widget"

# Irmu fetches the page: rendering, proxies, retries and anti-bot handling included.
resp = requests.get(
    "https://app.irmu.com/api/crawl",
    headers={"Authorization": f"Bearer {os.environ['IRMU_API_KEY']}"},
    params={"url": target, "js": "true", "premium": "true", "wait_until": "networkidle2"},
    timeout=90,
)
resp.raise_for_status()

soup = BeautifulSoup(resp.text, "html.parser")

images = []
for img in soup.find_all("img"):
    src = img.get("src") or img.get("data-src")
    if src:
        images.append({"url": urljoin(target, src), "alt": img.get("alt", "")})

with open("images.csv", "w", newline="") as f:
    writer = csv.DictWriter(f, fieldnames=["url", "alt"])
    writer.writeheader()
    writer.writerows(images)

print(f"{len(images)} images from {target}")
download_images.mjs
// Node 18+ — download every image URL you extracted
import { writeFile, mkdir } from "node:fs/promises";
import { basename } from "node:path";

const urls = JSON.parse(await (await import("node:fs/promises")).readFile("image-urls.json", "utf8"))
  .map((row) => row.url);

await mkdir("images", { recursive: true });

for (const url of urls) {
  const res = await fetch(url, { headers: { "User-Agent": "Mozilla/5.0" } });
  if (!res.ok) {
    console.warn("skip", url, res.status);
    continue;
  }
  const buffer = Buffer.from(await res.arrayBuffer());
  await writeFile(`images/${basename(new URL(url).pathname) || "image"}`, buffer);
}
FAQ

Questions about this tool

Turn any URL into clean image data

Fetch, render and extract with one API. 200 free credits every month, no card required.