Enabling the auto_save and auto_match features so selectors adjust themselves when a website's DOM structure changes. Understanding the self-healing mechanism based on element similarity scoring, SQLite storage, and the identifier and automatch_domain parameters for cross-domain management.

Over the last seven episodes you built scrapers that are fast and able to bypass anti-bot defenses. But there's one enemy we haven't covered: changes to website structure. Classes change, markup gets reworked, elements move — and a scraper that was perfect yesterday returns an empty list tomorrow morning without an error. This is the problem that frustrates many engineers, and in this episode 9 Scrapling answers it with auto-match and adaptive selectors.
In this episode you'll learn: what DOM drift is and why conventional selectors are fragile, the auto_save then auto_match workflow, how to enable the feature properly along with its limits, the self-healing mechanism based on element similarity scoring and storage, and the identifier and automatch_domain parameters. The key point: all of this works without AI — just a clever similarity engine and local storage.
DOM drift is the condition when a page's HTML structure changes while your selectors stay the same. The simplest example: the .product-card selector suddenly stops producing data because its class was renamed to .product-item or because the element was moved into a new container. On large websites, this kind of change happens constantly — redesigns, framework migrations, or A/B testing.
The impact goes beyond empty data. A scraper running at night might store incomplete datasets for days before anyone notices. This is where the conventional approach stops: you open DevTools, inspect the element, write a new selector, and hope there are no more changes. Auto-match automates that process.
The concept is simple: on the first day you save a fingerprint of the target element, and on the following days match that element to its new location. Usage has two stages. First, while the structure is still normal, enable auto_save on the selector to record the element's unique characteristics.
from scrapling import Fetcher
page = Fetcher.get("https://example.com/products")
produk = page.css(".product-card", auto_save=True)
print(len(produk))After auto_save=True{python} runs, Scrapling saves the element's profile to local storage. One day the website changes structure — the product-card class no longer exists. You simply flip the selector call flag to auto_match=True, and Scrapling will find the equivalent element on the new page.
from scrapling import Fetcher
page = Fetcher.get("https://example.com/products")
produk = page.css(".product-card", auto_match=True)
print(len(produk))Technically, you can make both a fallback path: try the regular selector, and if the result is empty, only then enable auto_match. This pattern keeps your scraper producing data when changes happen, without rewriting code.
This feature has several rules you must understand so you don't run in place. First, auto-match must be activated at the object level, not just on the selector call. Enable it via the auto_match=True argument when creating an Adaptor or fetcher, or via a class attribute.
from scrapling import Fetcher
Fetcher.auto_match = True
page = Fetcher.get("https://example.com/products")
produk = page.css(".product-card", auto_save=True)Second, auto_match and auto_save only work on a single element (Adaptor), not on a collection of elements. Calling page.css("body").css(".product-card", auto_match=True) will error because what receives the call is a list, not a single element. Use css_first to grab the first element and then select again.
Third, storage is only created if the feature is actually used. This is intentional for performance — the SQLite database isn't opened until you use auto_save or auto_match, so enabling auto_match=True without a flag-bearing selector won't create wasteful storage.
Warning
Auto-match isn't magic for elements that are genuinely gone. If an element is completely removed from a page, there's nothing to match. This feature handles elements that change or move — not elements that no longer exist.
How does Scrapling find the same element without AI? The answer is a similarity scoring system. When auto_save runs, Scrapling extracts the element's characteristics: the tag name, text content, attributes (names and values), sibling tag names, and the path from the document root. These characteristics are stored in an SQLite database keyed by the website's domain.
When auto_match runs, Scrapling takes the saved profile and compares it against all elements on the new page. The comparison isn't exact — every element gets a score based on how similar its characteristics are, including the order of class declarations. The element with the highest score above a threshold is the one chosen. This is why a product-card class that changed to product-item is still recognized: its attributes, text, and structural position are still similar.
from scrapling import Fetcher
page = Fetcher.get("https://example.com/products")
first = page.css_first(".product-card")
if first:
first.css(".title", auto_save=True)
page_baru = Fetcher.get("https://example.com/products")
judul = page_baru.css_first(".product-card").css(".title", auto_match=True)
print(judul.text)The scheme above illustrates a two-visit flow: the first visit saves the title element's profile, and the next visit matches it via auto_match even if the structure has changed. Because storage is keyed per domain, different pages on the same domain can still match each other.
These two parameters control how element profiles are stored and looked up. identifier is the key name used to save the profile. Its default is the selector string itself, but you can replace it — useful when the selector changes but you want to reuse the same profile.
automatch_domain forces which domain is considered the same. It's useful when you're testing with two URLs with different hosts but the same website (for example, www versus non-www), or when using sample data from one domain to be used on another.
from scrapling import Adaptor
html = open("salinan_halaman.html", encoding="utf-8").read()
page = Adaptor(html, url="https://example.com/products")
page.css(".product-card", identifier="kartu-produk", auto_save=True)
page_baru = Adaptor(html, url="https://example.com/products")
hasil = page_baru.css(".product-card", identifier="kartu-produk", auto_match=True)
print(len(hasil))Notice the use of Adaptor directly from an HTML string — a handy technique when you save page copies for offline testing. With the same identifier, auto_match finds the stored profile even if the selector changes. The url and identifier pair is the key that determines which profile is pulled from the database.
Episode 9 gives your scraper the ability to heal itself. You now understand DOM drift and why static selectors are fragile, the auto_save then auto_match flow, how to activate it along with its limits (object level, single element, lazily created storage), the similarity scoring mechanism based on tags, text, attributes, and siblings that works without AI, and identifier and automatch_domain for storage control. From now on, website redesigns are no longer a nightmare.
The key takeaways:
auto_save=True records an element's fingerprint while the structure is still normal.auto_match=True re-finds the element when the structure changes, without AI.Adaptor/fetcher level and only for a single element.identifier and automatch_domain control the storage key for element profiles.In episode 10 we tidy up your haul: data extraction and serialization — turning elements into dictionaries and JSON, cleaning text, handling pagination, and assembling structured datasets. See you there!