Facility: 37
Access Storage TN
- 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 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 #481 Details
- Status
- exported
- Parser Used
- Facility37Parser
- Platform Detected
- table_layout
- Units Found
- 5
- Stage Reached
- exported
- Timestamp
- 2026-03-14 16:46:55.316186
Timing
| Stage | Duration |
|---|---|
| Fetch | 2522ms |
| Detect | 3ms |
| Parse | 2ms |
| Export | 14ms |
Snapshot: 37_20260314T164657Z.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