Facility: 011591

ACMS Storage - Sheridan

Stale Data Warning: This facility has not been successfully scraped in 30 days (threshold: 3 days). Data may be outdated.
Facility Information active
Facility ID
011591
Name
ACMS Storage - Sheridan
URL
https://www.acmsstorage.com/1651-kristi-ln-sheridan-wy-82801
Address
N/A
Platform
custom_facility_011591
Parser File
src/parsers/custom/facility_011591_parser.py
Last Scraped
2026-03-23 03:20:52.340277
Created
2026-03-06 23:45:35.865957
Updated
2026-03-23 03:20:52.348935
Parser & Healing Diagnosis working
Parser Status
✓ Working
Status Reason
N/A
Last Healing Attempt
Not attempted
Parser Source (src/parsers/custom/facility_011591_parser.py)
"""Parser for ACMS Storage (Sheridan, WY).

The site uses the Storedge platform with a React/MUI frontend.
Unit data is embedded in a JSON-LD @graph script tag as Product items.
Each Product has:
  - description: "WxLxH - $sale_price - facilityId - [unit_range]"
  - offers.price: regular monthly rate (integer)
  - offers.category: unit category (e.g. "Self Storage")
"""

from __future__ import annotations

import json
import re

from bs4 import BeautifulSoup

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


class Facility011591Parser(BaseParser):
    """Extract storage units from ACMS Storage (Storedge platform).

    Parses unit data from JSON-LD @graph Product structured data.
    """

    platform = "custom_facility_011591"

    # Matches "10x10x0 - $60.00 - ..." — captures WxL and sale price
    _DESC_RE = re.compile(
        r"(\d+)x(\d+)x\d+\s*-\s*\$([\d,]+(?:\.\d+)?)",
        re.IGNORECASE,
    )

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

        # Find JSON-LD script with @graph containing Product items
        products = []
        for script in soup.find_all("script", type="application/ld+json"):
            try:
                data = json.loads(script.string or "")
                if isinstance(data, dict) and "@graph" in data:
                    products = [i for i in data["@graph"] if i.get("@type") == "Product"]
                    if products:
                        break
            except (json.JSONDecodeError, AttributeError):
                continue

        if not products:
            result.warnings.append("No JSON-LD Product data found on page")
            return result

        seen: set[tuple] = set()

        for product in products:
            desc = product.get("description", "")
            offers = product.get("offers", {})
            regular_price = offers.get("price")
            category = offers.get("category", "")

            m = self._DESC_RE.match(desc)
            if not m:
                continue

            width = float(m.group(1))
            length = float(m.group(2))
            sale_price_str = m.group(3).replace(",", "")
            sale_price = float(sale_price_str)

            key = (width, length, regular_price)
            if key in seen:
                continue
            seen.add(key)

            size = f"{int(width)}' x {int(length)}'"
            metadata: dict = {
                "width": width,
                "length": length,
                "sqft": width * length,
                "category": category,
            }

            unit = UnitResult(
                size=size,
                price=float(regular_price) if regular_price is not None else None,
                sale_price=sale_price if sale_price != regular_price else None,
                description=desc,
                metadata=metadata,
            )
            result.units.append(unit)

        if not result.units:
            result.warnings.append("No valid product units found in JSON-LD data")

        return result

Scrape Runs (5)

Run #156 Details

Status
exported
Parser Used
Facility011591Parser
Platform Detected
storageunitsoftware
Units Found
9
Stage Reached
exported
Timestamp
2026-03-14 04:59:35.966344
Timing
Stage Duration
Fetch4387ms
Detect74ms
Parse45ms
Export4ms

Snapshot: 011591_20260314T045940Z.html · Show Snapshot · Open in New Tab

Parsed Units (9)

10' x 20'

$115.00/mo

5' x 5'

$40.00/mo
Street: $50.00

5' x 10'

$70.00/mo
Street: $75.00

6' x 10'

$30.00/mo
Street: $40.00

10' x 15'

$95.00/mo
Street: $115.00

10' x 30'

$175.00/mo
Street: $205.00

10' x 10'

$100.00/mo

10' x 24'

$90.00/mo

10' x 10'

$60.00/mo
Street: $75.00

← Back to dashboard