Facility: 004533

Store More 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
004533
Name
Store More Self Storage
URL
https://www.bagbytransfer.com/storage-locations
Address
117 Huffaker Rd NW, Rome, GA 30165, USA, Rome, Georgia 30165
Platform
custom_facility_004533
Parser File
src/parsers/custom/facility_004533_parser.py
Last Scraped
2026-03-27 13:58:55.454235
Created
2026-03-14 16:21:53.706708
Updated
2026-03-27 13:58:55.486877
Parser & Healing Diagnosis working
Parser Status
✓ Working
Status Reason
N/A
Last Healing Attempt
Not attempted
Parser Source (src/parsers/custom/facility_004533_parser.py)
"""Parser for Store More Self Storage (Bagby Transfer & Storage).

StorEdge-powered site with unit data embedded as JSON-LD Product entries.
URL: https://www.bagbytransfer.com/storage-locations

This is a multi-location site with 5+ "Sites" distinguished by the product
``category`` field (e.g. "Site 5 WEST ROME-HUFFAKER - CC"). We filter to
only the site matching the target facility's address.
"""

from __future__ import annotations

import json

from bs4 import BeautifulSoup

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


class Facility004533Parser(BaseParser):
    """Extract storage units from Bagby Transfer & Storage JSON-LD.

    Filters to the target facility location based on address keywords
    matched against the product category field.
    """

    platform = "custom_facility_004533"

    # The target facility is at 117 Huffaker Rd NW, Rome, GA 30165.
    # Products for this location have "HUFFAKER" or "Huff" in their category.
    _LOCATION_KEYWORDS = ["huffaker", "huff"]

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

        all_products = self._extract_products(soup)
        if not all_products:
            result.warnings.append("No units found in JSON-LD Product entries")
            return result

        # Group products by category to detect multi-location pages
        categories: dict[str, list[dict]] = {}
        for product in all_products:
            cat = (
                product.get("category", "")
                or product.get("offers", {}).get("category", "")
                or ""
            )
            categories.setdefault(cat, []).append(product)

        is_multi_location = len(categories) > 1

        if is_multi_location:
            # Filter to categories matching our target location
            matched_cats = [
                cat
                for cat in categories
                if any(kw in cat.lower() for kw in self._LOCATION_KEYWORDS)
            ]

            if not matched_cats:
                result.warnings.append(
                    f"Multi-location page with {len(categories)} site categories "
                    f"({', '.join(sorted(categories.keys())[:5])}...) but could not "
                    f"identify target facility (Huffaker Rd). "
                    f"Returning 0 units to avoid data contamination."
                )
                return result

            target_products = []
            for cat in matched_cats:
                target_products.extend(categories[cat])

            result.warnings.append(
                f"Multi-location page with {len(categories)} site categories; "
                f"filtered to {len(matched_cats)} matching categories "
                f"({', '.join(matched_cats)}) with {len(target_products)} units "
                f"(excluded {len(all_products) - len(target_products)} units "
                f"from other locations)"
            )
        else:
            target_products = all_products

        # Build UnitResult objects from filtered products
        for product in target_products:
            size_text = product.get("description", "")
            if not size_text:
                continue

            offers = product.get("offers", {})
            if isinstance(offers, list):
                offers = offers[0] if offers else {}

            price_raw = offers.get("price")
            category = product.get("category", "") or offers.get("category", "")

            unit = UnitResult()
            unit.size = size_text
            w, ln, sq = self.normalize_size(size_text)
            if w is not None:
                unit.metadata = {"width": w, "length": ln, "sqft": sq}
            if price_raw is not None:
                unit.price = self.normalize_price(str(price_raw))
            if category:
                unit.description = f"{size_text} - {category}"
            else:
                unit.description = size_text

            if unit.size or unit.price:
                result.units.append(unit)

        if not result.units:
            result.warnings.append("No units found after filtering to target facility")

        return result

    def _extract_products(self, soup: BeautifulSoup) -> list[dict]:
        """Collect all JSON-LD Product entries from the page."""
        products: list[dict] = []
        for script in soup.find_all("script", type="application/ld+json"):
            try:
                data = json.loads(script.string or "")
            except (json.JSONDecodeError, TypeError):
                continue

            if isinstance(data, dict) and "@graph" in data:
                products.extend(
                    item
                    for item in data["@graph"]
                    if isinstance(item, dict) and item.get("@type") == "Product"
                )
            elif isinstance(data, dict) and data.get("@type") == "Product":
                products.append(data)
            elif isinstance(data, list):
                products.extend(
                    item
                    for item in data
                    if isinstance(item, dict) and item.get("@type") == "Product"
                )

        return products

Scrape Runs (4)

Run #316 Details

Status
exported
Parser Used
Facility004533Parser
Platform Detected
storageunitsoftware
Units Found
126
Stage Reached
exported
Timestamp
2026-03-14 16:32:53.451360
Timing
Stage Duration
Fetch4230ms
Detect22ms
Parse12ms
Export29ms

Snapshot: 004533_20260314T163257Z.html · Show Snapshot · Open in New Tab

Parsed Units (126)

10x15

$0.00/mo

15x15

$225.00/mo

10x15

$145.00/mo

10x20

$185.00/mo

10x15

$145.00/mo

10x30

$280.00/mo

10x12

$115.00/mo

10x15

$145.00/mo

35x15

$450.00/mo

35x15

$480.00/mo

20x15

$260.00/mo

10x15

$155.00/mo

10x15

$145.00/mo

5x15

$65.00/mo

5x15

$90.00/mo

20x35

$525.00/mo

10x15

$85.00/mo

5x15

$70.00/mo

10x15

$90.00/mo

20x35

$570.00/mo

10x15

$145.00/mo

20x20

$345.00/mo

5x15

$90.00/mo

10x15

$145.00/mo

10x15

$155.00/mo

10x10

$105.00/mo

10x25

$225.00/mo

10x20

$185.00/mo

10x25

$245.00/mo

10x20

$166.50/mo

10x15

$0.00/mo

15x15

$210.00/mo

10x20

$145.00/mo

10x20

$185.00/mo

20x15

$260.00/mo

10x20

$200.00/mo

15x20

$280.00/mo

10x20

$0.00/mo

15x20

$260.00/mo

200x25

$1250.00/mo

200x25

$1250.00/mo

10x15

$90.00/mo

10x15

$90.00/mo

10x15

$90.00/mo

10x15

$155.00/mo

5x10

$0.00/mo

9x15

$85.00/mo

5x15

$65.00/mo

10x15

$155.00/mo

10x15

$90.00/mo

5x10

$90.00/mo

10x15

$145.00/mo

10x30

$260.00/mo

15x15

$225.00/mo

10x15

$90.00/mo

10x15

$90.00/mo

10x10

$115.00/mo

10x15

$90.00/mo

10x15

$90.00/mo

15x15

$225.00/mo

10x15

$155.00/mo

10x15

$90.00/mo

8x15

$75.00/mo

10x15

$90.00/mo

10x15

$155.00/mo

10x12

$125.00/mo

10x15

$90.00/mo

10x15

$155.00/mo

5x15

$70.00/mo

21x19

$210.00/mo

10x15

$85.00/mo

10x15

$90.00/mo

10x30

$165.00/mo

8x15

$75.00/mo

10x15

$90.00/mo

10x15

$90.00/mo

9x15

$85.00/mo

12x50

$0.00/mo

5x15

$70.00/mo

5x15

$70.00/mo

12x40

$115.00/mo

21x19

$200.00/mo

10x15

$85.00/mo

15x41

$120.00/mo

10x15

$90.00/mo

10x15

$90.00/mo

10x15

$0.00/mo

10x15

$85.00/mo

10x30

$280.00/mo

10x10

$115.00/mo

20x25

$425.00/mo

5x10

$90.00/mo

5x10

$90.00/mo

5x10

$0.00/mo

20x25

$700.00/mo

20x25

$455.00/mo

20x50

$615.00/mo

10x15

$155.00/mo

10x15

$155.00/mo

10x15

$145.00/mo

15x20

$260.00/mo

10x7.5

$100.00/mo

15x20

$280.00/mo

10x15

$145.00/mo

10x10

$115.00/mo

20x20

$345.00/mo

15x15

$210.00/mo

15x15

$260.00/mo

10x15

$155.00/mo

10x12

$115.00/mo

20x20

$370.00/mo

7.5x10

$100.00/mo

10x15

$150.00/mo

10x12.5

$125.00/mo

10x20

$185.00/mo

5x10

$85.00/mo

10x12

$125.00/mo

10x10

$105.00/mo

10x10

$109.25/mo

10x12

$120.00/mo

10x10

$115.00/mo

15x15

$260.00/mo

10x15

$155.00/mo

10x15

$155.00/mo

10x10

$115.00/mo

15x15

$210.00/mo

← Back to dashboard