Facility: 37

Access Storage TN

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
37
Name
Access Storage TN
URL
https://www.accessstoragetn.com/units.html
Address
N/A
Platform
custom_facility_37
Parser File
src/parsers/custom/facility_37_parser.py
Last Scraped
2026-03-23 03:15:24.777831
Created
2026-03-14 16:21:53.706708
Updated
2026-03-23 03:15:24.784281
Parser & Healing Diagnosis working
Parser Status
✓ Working
Status Reason
N/A
Last Healing Attempt
Not attempted
Parser Source (src/parsers/custom/facility_37_parser.py)
"""Parser for Access Storage TN."""
from __future__ import annotations

import re

from bs4 import BeautifulSoup

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


class Facility37Parser(BaseParser):
    """Extract storage units from accessstoragetn.com.

    Units are shown as alternating headings: one with dimensions like
    ``10' x 10' (100 sq ft)`` and another with ``Rent = $80``.
    """

    platform = "custom_facility_37"

    _SIZE_RE = re.compile(
        r"(\d+)['\u2032]?\s*x\s*(\d+)['\u2032]?\s*\((\d+)\s*sq\s*ft\)",
        re.IGNORECASE,
    )
    _RENT_RE = re.compile(r"Rent\s*=\s*\$?([\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__)

        content = soup.select_one(".content")
        if not content:
            result.warnings.append("No content section found")
            return result

        headings = content.find_all("h3")

        current_unit: UnitResult | None = None
        for h3 in headings:
            text = h3.get_text(strip=True)

            size_match = self._SIZE_RE.search(text)
            if size_match:
                width = float(size_match.group(1))
                length = float(size_match.group(2))
                sqft = float(size_match.group(3))
                current_unit = UnitResult()
                current_unit.metadata = {"width": width, "length": length, "sqft": sqft}
                current_unit.size = f"{int(width)}' x {int(length)}'"
                current_unit.description = text
                continue

            rent_match = self._RENT_RE.search(text)
            if rent_match and current_unit is not None:
                current_unit.sale_price = self.normalize_price(rent_match.group(1))
                result.units.append(current_unit)
                current_unit = None
                continue

            # "Rent = Call for Availability" case
            if "rent" in text.lower() and current_unit is not None:
                current_unit.scarcity = "call"
                result.units.append(current_unit)
                current_unit = None

        if not result.units:
            result.warnings.append("No units extracted from headings")

        return result

Scrape Runs (3)

Run #1425 Details

Status
exported
Parser Used
Facility37Parser
Platform Detected
table_layout
Units Found
5
Stage Reached
exported
Timestamp
2026-03-23 03:15:22.542787
Timing
Stage Duration
Fetch2204ms
Detect7ms
Parse4ms
Export5ms

Snapshot: 37_20260323T031524Z.html · Show Snapshot · Open in New Tab

Parsed Units (5)

10' x 10'

$80.00/mo

10' x 15'

$120.00/mo

10' x 20'

$160.00/mo

10' x 30'

No price
call

10' x 40'

No price
call

← Back to dashboard