Techniques 8 min read

Scraping HTML Graphic Elements: Possibilities and Limits

What graphics can you scrape from HTML pages? Images, SVG, canvas, and chart data explained: what is possible, what is not, and which techniques work.

ST
Scraping.Pro Team
Data collection for business needs
Published: 2 September 2025

Most scraping tutorials deal with text and tables. But a lot of the value on a page is drawn: product photos, logos, icons, and — most importantly — charts and graphs full of numbers you actually want. The obvious question is how much of that graphical content you can extract, and the honest answer is "it depends entirely on how the graphic was built." Some graphics are just as scrapable as text; others are effectively a locked image with the data thrown away.

This guide breaks HTML graphics into four types — images, SVG, canvas, and the data behind charts — and, for each, explains what is realistically scrapable, what isn't, and which technique to use.

The one question that decides everything: static or dynamic

Before touching any specific element type, determine how the graphic gets onto the page.

  • Static graphics are present in the raw HTML the server sends. A tool that reads only the initial markup — Google Sheets' IMPORTXML, Python requests, curl — can see them.
  • Dynamic graphics are created after load by JavaScript (often inside an <iframe>, or fetched from an API). Static tools see nothing; you need something that runs the page's JavaScript.

This is the trap behind a question we get often — "How do I scrape the chart on a site like pollen.com into a spreadsheet daily?" Those forecast charts are rendered dynamically by JavaScript embedded in an iframe, so IMPORTXML returns empty. The fix isn't a better XPath; it's a headless browser that executes the script, or finding the data feed underneath (covered below). If you are new to this distinction, the primer on what web scraping is covers static vs dynamic pages in more depth.

Images: the easy case

Ordinary raster images (<img> tags, JP/PNG/WebP/AVIF) are the most scrapable graphic of all. The src attribute is a URL; grab it, resolve it against the page's base URL if it's relative, and download the file.

python
import requests
from urllib.parse import urljoin
from bs4 import BeautifulSoup

page_url = "https://example.com/products"
html = requests.get(page_url).text
soup = BeautifulSoup(html, "html.parser")

for img in soup.select("img"):
    src = img.get("src") or img.get("data-src")   # data-src for lazy loading
    if src:
        url = urljoin(page_url, src)
        print(url)

A few real-world wrinkles:

  • Lazy loading. Images below the fold often keep the real URL in data-src, data-original, or a srcset until you scroll. Check those attributes, or scroll the page in a headless browser to trigger loading.
  • srcset / <picture>. Responsive images list several resolutions; parse srcset and pick the size you want.
  • CSS backgrounds. Images set via background-image: url(...) are not in any <img> tag — you have to read the computed style or the stylesheet.
  • Data URIs. Small images may be inlined as data:image/png;base64,... — decode the base64 instead of downloading.
  • Etiquette and rights. Downloading images can carry bandwidth and copyright implications; respect the site's terms and rate-limit your requests.

SVG: scrapable, because it's really XML

SVG describes 2D graphics in XML, and that is great news for scrapers. Every shape, path, and text label is a DOM node with its own attributes — you can target it with XPath or CSS selectors and read its contents, exactly like HTML. Contrary to a common assumption, SVG is scrapable: you can get an element's XPath, its child nodes, and any embedded text.

Two flavors exist:

  • Inline SVG — the <svg> markup sits directly in the page. If it's in the static HTML, IMPORTXML and requests can read it; the axis labels, data-point coordinates, and <title>/<text> values are all there to extract.
  • External SVG — referenced via <img src="chart.svg"> or an <object>. Download the .svg file directly and parse it as XML.

The catch: an SVG chart built dynamically by a library like D3 only exists after the JavaScript runs. Static tools won't see it — render the page first, then read the SVG DOM. Once rendered, a data-bound SVG chart is a goldmine, because the numbers are usually encoded right in element attributes (cx, cy, height, d, or data-*).

Canvas: the hard limit

Canvas is where scrapability falls off a cliff. Unlike SVG, a <canvas> element is drawn pixel by pixel with JavaScript, and once a shape is painted the browser forgets it — there is no DOM object for each bar, line, or point. Reading the <canvas> tag gives you an empty container, not the picture inside, and definitely not the underlying numbers.

So you cannot "select" a data point on a canvas chart the way you can with SVG. Your realistic options are:

  1. Find the data source instead (best). A canvas chart had to get its numbers from somewhere — usually a JSON payload from an API or embedded in the page. Skip the pixels entirely and grab that. (See the next section.)
  2. Export the canvas as an image. In a headless browser you can call canvas.toDataURL() to pull the rendered picture out, then run OCR or computer vision on it. This recovers a picture, and maybe some labels, but it is lossy and fiddly.
  3. Screenshot + OCR. A last resort for numbers baked into an image with no accessible source. Expect errors and manual cleanup.

If a site deliberately renders data as canvas to discourage scraping, treat it as a signal to look harder for the API rather than fighting the pixels.

The real prize: the data behind the chart

Here is the shift in mindset that solves most "scrape this graph" problems: don't scrape the graphic — scrape its data feed. Charts (whether SVG, canvas, or WebGL) are just a visualization of numbers that arrived as structured data. Getting those numbers is usually easier and cleaner than parsing the drawing.

How to find the feed:

  • Watch the network tab. Open your browser's developer tools → Network, filter to Fetch/XHR, and reload. Charting libraries almost always pull their series from a JSON (or CSV) endpoint. Hit that URL directly and you get clean, structured data — no rendering required.
  • Look in the HTML/JS. Sometimes the data is embedded in a <script> block as a JSON variable, a data-* attribute, or a JSON-LD tag. Extract and parse it.
  • Check for an official API. The chart may be a public API you can call in your own API-based scraper with proper parameters.

Automating the network-capture approach means driving a real browser and reading its requests — a headless browser automation setup can intercept the exact XHR call the chart makes and hand you the JSON.

Quick reference: what's scrapable

Graphic type Data recoverable? How
<img> raster (JPG/PNG/WebP) Yes (the image file) Read src/srcset/data-src, download
Inline SVG Yes (shapes, text, coordinates) Parse the SVG DOM; render first if dynamic
External SVG file Yes Download the .svg and parse as XML
Canvas chart Not directly Find the data feed; or toDataURL + OCR
WebGL / map tiles Rarely, directly Find the tile/data API
Any chart with a JSON feed Yes (cleanest) Capture the XHR/API response

The takeaway

Scrapability tracks the technology: raster images and SVG expose their content and are straightforward to extract, while canvas and WebGL discard theirs and force you to work around the rendering. For anything data-driven, the winning move is almost always to bypass the visual and go for the underlying feed. Identify static vs dynamic first, choose the tool that matches, and prefer the data source over the drawing.

When the target hides its numbers behind canvas, iframes, or aggressive anti-bot layers, scraping.pro handles the reverse-engineering and delivers the structured data as a done-for-you service — you get the CSV, not the pixels.