Facility: 002009
Regal Storage
- Facility ID
- 002009
- Name
- Regal Storage
- URL
- https://www.regalstorage.net/storage-units
- Address
- 1053 Fm 2004, Lake Jackson, TX 77566, USA, Lake Jackson, Texas 77566
- Platform
- custom_facility_002009
- Parser File
- src/parsers/custom/facility_002009_parser.py
- Last Scraped
- 2026-03-27 13:39:33.371632
- Created
- 2026-03-23 02:35:08.816820
- Updated
- 2026-03-27 13:39:33.408384
- Parser Status
- ✓ Working
- Status Reason
- N/A
- Last Healing Attempt
- Not attempted
Parser Source (src/parsers/custom/facility_002009_parser.py)
"""Parser for Regal Storage (Wix site, Lake Jackson TX)."""
from __future__ import annotations
import re
from bs4 import BeautifulSoup
from src.parsers.base import BaseParser, ParseResult, UnitResult
class Facility002009Parser(BaseParser):
"""Extract storage units from Regal Storage.
This is a Wix-built site that lists unit sizes on the /storage-units page
but does NOT display prices online (visitors must call for pricing).
Units are rendered as <h1 class="font_0"> elements with dimensions like
5' x 10'.
"""
platform = "custom_facility_002009"
_SIZE_RE = re.compile(
r"(\d+)\s*['\u2032\u2019]?\s*[xX×]\s*(\d+)\s*['\u2032\u2019]?"
)
def parse(self, html: str, url: str = "") -> ParseResult:
soup = BeautifulSoup(html, "lxml")
result = ParseResult(platform=self.platform, parser_name=self.__class__.__name__)
for tag in soup.find_all("script"):
tag.decompose()
for tag in soup.find_all("style"):
tag.decompose()
seen: set[tuple[int, int]] = set()
# Unit sizes are in <h1 class="font_0 wixui-rich-text__text"> elements
# inside wixui-rich-text containers.
for h1 in soup.find_all("h1", class_="font_0"):
text = h1.get_text(strip=True)
m = self._SIZE_RE.search(text)
if not m:
continue
width = int(m.group(1))
length = int(m.group(2))
# Skip implausible dimensions (e.g. from descriptive text)
if width < 3 or length < 3:
continue
key = (width, length)
if key in seen:
continue
seen.add(key)
size_str = f"{width}' x {length}'"
w, ln, sq = self.normalize_size(size_str)
unit = UnitResult()
unit.size = size_str
unit.price = None # Prices not listed on site
unit.description = f"Regal Storage - {size_str}"
if w is not None:
unit.metadata = {"width": w, "length": ln, "sqft": sq}
result.units.append(unit)
# Fallback: scan all text nodes for dimension patterns if no h1 matches
if not result.units:
body_text = soup.get_text(separator="\n")
for m in self._SIZE_RE.finditer(body_text):
width = int(m.group(1))
length = int(m.group(2))
if width < 3 or length < 3:
continue
key = (width, length)
if key in seen:
continue
seen.add(key)
size_str = f"{width}' x {length}'"
w, ln, sq = self.normalize_size(size_str)
unit = UnitResult()
unit.size = size_str
unit.price = None
unit.description = f"Regal Storage - {size_str}"
if w is not None:
unit.metadata = {"width": w, "length": ln, "sqft": sq}
result.units.append(unit)
if not result.units:
result.warnings.append("No units found")
else:
result.warnings.append(
"Prices not listed on site; call 979-299-3300 for pricing"
)
return result
Scrape Runs (3)
Run #1521 Details
- Status
- exported
- Parser Used
- Facility002009Parser
- Platform Detected
- table_layout
- Units Found
- 8
- Stage Reached
- exported
- Timestamp
- 2026-03-27 13:39:31.457705
Timing
| Stage | Duration |
|---|---|
| Fetch | 1834ms |
| Detect | 18ms |
| Parse | 9ms |
| Export | 22ms |
Snapshot: 002009_20260327T133933Z.html · Show Snapshot · Open in New Tab
Parsed Units (8)
5' x 5'
No price
5' x 10'
No price
5' x 15'
No price
10' x 30'
No price
10' x 25'
No price
10' x 15'
No price
10' x 10'
No price
10' x 20'
No price