Facility: 004216
Gypsum Mini Storage
- Facility ID
- 004216
- Name
- Gypsum Mini Storage
- URL
- https://www.gypsumministorage.com/115-park-street-po-box-878-gypsum-co-81637
- Address
- 115 Park St, Gypsum, CO 81637, USA, Gypsum, Colorado 81637
- Platform
- custom_facility_004216
- Parser File
- src/parsers/custom/facility_004216_parser.py
- Last Scraped
- 2026-03-27 13:58:00.288155
- Created
- 2026-03-14 16:21:53.706708
- Updated
- 2026-03-27 13:58:00.320144
- Parser Status
- ✓ Working
- Status Reason
- N/A
- Last Healing Attempt
- Not attempted
Parser Source (src/parsers/custom/facility_004216_parser.py)
"""Parser for Gypsum Mini Storage (StorEdge / Storable platform)."""
from __future__ import annotations
import re
from bs4 import BeautifulSoup, Tag
from src.parsers.base import BaseParser, ParseResult, UnitResult
class Facility004216Parser(BaseParser):
"""Extract storage units from Gypsum Mini Storage.
Site uses the Storable/StorEdge rental center with Material UI card
components. Each unit is rendered inside a ``MuiCard-root`` div with:
* An ``<h5>`` (or similar heading) containing the size, e.g. "5' x 5' Unit"
* A ``MuiTypography-h6`` element with the current/discounted monthly price
* An optional ``MuiTypography-caption`` span with the original
(struck-through) price
* A ``MuiTypography-body1`` paragraph with the unit category
"""
platform = "custom_facility_004216"
_SIZE_RE = re.compile(
r"(\d+)[′'']?\s*[xX×]\s*(\d+)[′'']?"
)
def parse(self, html: str, url: str = "") -> ParseResult:
soup = BeautifulSoup(html, "lxml")
result = ParseResult(platform=self.platform, parser_name=self.__class__.__name__)
cards = soup.find_all("div", class_="MuiCard-root")
seen: set[str] = set()
for card in cards:
if not isinstance(card, Tag):
continue
# --- size from heading ---
heading = card.find(["h3", "h4", "h5", "h6"])
if heading is None:
continue
heading_text = heading.get_text(strip=True)
m = self._SIZE_RE.search(heading_text)
if not m:
continue
size_raw = f"{m.group(1)}' x {m.group(2)}'"
if size_raw in seen:
continue
seen.add(size_raw)
# --- prices ---
# Discounted / current price lives in an h6.MuiTypography-h6
price_el = card.find(
"h6",
class_=lambda c: c and "MuiTypography-h6" in c,
)
# Fallback: subtitle1 (contains "$X /mo")
if price_el is None:
price_el = card.find(
"h6",
class_=lambda c: c and "MuiTypography-subtitle1" in c,
)
price = self.normalize_price(price_el.get_text(strip=True)) if price_el else None
# Original / strike-through price (caption)
strike_el = card.find(
"span",
class_=lambda c: c and "MuiTypography-caption" in c,
)
original_price = (
self.normalize_price(strike_el.get_text(strip=True))
if strike_el
else None
)
# --- category ---
cat_el = card.find(
"p",
class_=lambda c: c and "MuiTypography-body1" in c,
)
category = cat_el.get_text(strip=True) if cat_el else None
# --- build unit ---
unit = UnitResult()
unit.size = size_raw
w, ln, sq = self.normalize_size(size_raw)
metadata: dict[str, object] = {}
if w is not None:
metadata.update(width=w, length=ln, sqft=sq)
if original_price is not None:
metadata["original_price"] = original_price
if category:
metadata["category"] = category
if metadata:
unit.metadata = metadata
unit.price = price
unit.description = heading_text
result.units.append(unit)
if not result.units:
result.warnings.append("No MuiCard-root unit cards found")
return result
Scrape Runs (5)
-
exported Run #19732026-03-27 13:57:55.369291 | 4 units | Facility004216Parser | View Data →
-
exported Run #19722026-03-27 13:57:55.367790 | 4 units | Facility004216Parser | View Data →
-
exported Run #12492026-03-23 02:59:21.918050 | 4 units | Facility004216Parser | View Data →
-
exported Run #7562026-03-21 18:51:06.762013 | 4 units | Facility004216Parser | View Data →
-
exported Run #3052026-03-14 16:32:15.037881 | 4 units | Facility004216Parser | View Data →
Run #1249 Details
- Status
- exported
- Parser Used
- Facility004216Parser
- Platform Detected
- storageunitsoftware
- Units Found
- 4
- Stage Reached
- exported
- Timestamp
- 2026-03-23 02:59:21.918050
Timing
| Stage | Duration |
|---|---|
| Fetch | 9878ms |
| Detect | 67ms |
| Parse | 32ms |
| Export | 5ms |
Snapshot: 004216_20260323T025931Z.html · Show Snapshot · Open in New Tab
Parsed Units (4)
5' x 5'
$60.00/mo
5' x 10'
$115.00/mo
10' x 10'
$165.00/mo
10' x 20'
$275.00/mo