Facility: 096824

CLAYTON SELF STORAGE

Stale Data Warning: This facility has not been successfully scraped in 26 days (threshold: 3 days). Data may be outdated.
Facility Information active
Facility ID
096824
Name
CLAYTON SELF STORAGE
URL
https://www.absolutemgmt.com/storage-locations/ga/clayton/clayton-self-storage/
Address
287 US-441, Clayton, GA 30525, USA, Clayton, Georgia 30525
Platform
custom_facility_096824
Parser File
src/parsers/custom/facility_096824_parser.py
Last Scraped
2026-03-27 13:47:27.044854
Created
2026-03-20 23:33:53.011799
Updated
2026-03-27 13:47:27.044854
Parser & Healing Diagnosis needs_fix
Parser Status
⚠ Needs Fix
Status Reason
Parser returned 0 units
Last Healing Attempt
Not attempted
Parser Source (src/parsers/custom/facility_096824_parser.py)
"""Parser for Clayton Self Storage (Absolute Storage Management)."""

from __future__ import annotations

import re

from bs4 import BeautifulSoup

from src.parsers.base import BaseParser, ParseResult, UnitResult


class Facility096824Parser(BaseParser):
    """Extract storage units from Clayton Self Storage via Absolute Mgmt.

    The snapshot is the Absolute Storage Management locations listing page
    for Georgia. It lists multiple facilities with 'prices starting at'
    values. We filter to only Clayton Self Storage based on URL slug or
    facility name matching.
    """

    platform = "custom_facility_096824"

    # Target facility identifiers for matching.
    _TARGET_NAME = "clayton self storage"
    _TARGET_URL_FRAGMENT = "/clayton/clayton-self-storage"
    _TARGET_ADDRESS_FRAGMENT = "287 us-441"

    def parse(self, html: str, url: str = "") -> ParseResult:
        soup = BeautifulSoup(html, "lxml")
        result = ParseResult(platform=self.platform, parser_name=self.__class__.__name__)

        # This is a multi-facility listing page
        cards = soup.find_all("a", class_="market-location-card")

        if not cards:
            result.warnings.append("No facility cards found on page")
            return result

        # Find the matching card for Clayton Self Storage
        matched_card = None
        all_names: list[str] = []

        for card in cards:
            title_el = card.find(class_="market-fac-title-rating")
            name = title_el.get_text(strip=True) if title_el else None
            if not name:
                continue
            all_names.append(name)

            href = card.get("href", "")

            # Match by URL fragment
            if self._TARGET_URL_FRAGMENT in href.lower():
                matched_card = card
                break

            # Match by name
            if self._TARGET_NAME in name.lower():
                matched_card = card
                break

            # Match by address
            addr_el = card.find(class_="market-fac-address")
            if addr_el:
                address = addr_el.get_text(" ", strip=True).lower()
                if self._TARGET_ADDRESS_FRAGMENT in address:
                    matched_card = card
                    break

        if matched_card is None:
            result.warnings.append(
                f"Multi-facility listing page with {len(all_names)} facilities "
                f"but Clayton Self Storage not found. "
                f"Returning 0 units to avoid data contamination. "
                f"The facility URL may need updating to point directly to "
                f"the Clayton Self Storage detail page."
            )
            return result

        # Extract data from matched card only
        title_el = matched_card.find(class_="market-fac-title-rating")
        name = title_el.get_text(strip=True) if title_el else "Clayton Self Storage"

        addr_el = matched_card.find(class_="market-fac-address")
        address = addr_el.get_text(" ", strip=True) if addr_el else None

        price_el = matched_card.find(class_="market-fac-unit-prices")
        price = None
        if price_el:
            price_match = re.search(r"\$(\d+)", price_el.get_text())
            if price_match:
                price = self.normalize_price(price_match.group(1))

        unit = UnitResult()
        unit.description = name
        unit.price = price
        unit.metadata = {"facility_name": name}
        if address:
            unit.metadata["address"] = address
        result.units.append(unit)

        result.warnings.append(
            f"Multi-facility listing page with {len(all_names)} facilities; "
            f"filtered to Clayton Self Storage only. "
            f"Only 'starting at' price is available from this page."
        )

        return result

Scrape Runs (4)

Run #1710 Details

Status
exported
Parser Used
Facility096824Parser
Platform Detected
ccstorage
Units Found
0
Stage Reached
exported
Timestamp
2026-03-27 13:47:20.443314
Timing
Stage Duration
Fetch6476ms
Detect29ms
Parse22ms
Export16ms

Snapshot: 096824_20260327T134726Z.html · Show Snapshot · Open in New Tab

No units found in this run.

All Failures for this Facility (4)

parse _WarningAsException scraper no_units_extracted warning Run #N/A | 2026-03-27 13:47:27.025479

No units extracted for 096824

Stack trace
src.reporting.failure_reporter._WarningAsException: No units extracted for 096824
parse _WarningAsException scraper no_units_extracted warning Run #N/A | 2026-03-27 13:47:26.375053

No units extracted for 096824

Stack trace
src.reporting.failure_reporter._WarningAsException: No units extracted for 096824
parse _WarningAsException scraper no_units_extracted warning Run #N/A | 2026-03-23 02:49:10.445446

No units extracted for 096824

Stack trace
src.reporting.failure_reporter._WarningAsException: No units extracted for 096824
parse _WarningAsException scraper no_units_extracted warning Run #N/A | 2026-03-21 18:38:49.584670

No units extracted for 096824

Stack trace
src.reporting.failure_reporter._WarningAsException: No units extracted for 096824

← Back to dashboard