Facility: 061274
Extra Storage Mills
- Facility ID
- 061274
- Name
- Extra Storage Mills
- URL
- https://www.extrastoragemills.com/222-pendell-blvd-mills-wy-82604
- Address
- N/A
- Platform
- custom_facility_061274
- Parser File
- src/parsers/custom/facility_061274_parser.py
- Last Scraped
- 2026-03-23 03:19:46.407488
- Created
- 2026-03-06 23:45:35.865957
- Updated
- 2026-03-23 03:19:46.415346
- Parser Status
- ✓ Working
- Status Reason
- N/A
- Last Healing Attempt
- Not attempted
Parser Source (src/parsers/custom/facility_061274_parser.py)
"""Parser for Extra Storage Mills, WY facility (061274).
This site is built on Wix with obfuscated CSS class names. Units are displayed
in two row types within a table-like layout:
- Standard rows: class 'OMl9pPN1h6gEVHf3-Pyw3 row' — contain price, size, description
- Featured/compact rows: class '_3ea1Xmp6wkmi39zHaaXfUa row' — price and size only
"""
from __future__ import annotations
import re
from bs4 import BeautifulSoup
from src.parsers.base import BaseParser, ParseResult, UnitResult
class Facility061274Parser(BaseParser):
"""Extract storage units from Extra Storage Mills, WY (Wix-based site).
Unit rows use obfuscated Wix class names. Two row variants are handled:
- Standard rows with price, size, and description (class 'OMl9pPN1h6gEVHf3-Pyw3')
- Compact rows with price and size only (class '_3ea1Xmp6wkmi39zHaaXfUa')
"""
platform = "custom_facility_061274"
# Matches sizes like "8'x10'", "10X20", "10' x 15'"
_SIZE_RE = re.compile(
r"(\d+(?:\.\d+)?)\s*['\u2019]?\s*[xX\u00d7]\s*(\d+(?:\.\d+)?)\s*['\u2019]?",
)
def parse(self, html: str, url: str = "") -> ParseResult:
soup = BeautifulSoup(html, "lxml")
result = ParseResult(platform=self.platform, parser_name=self.__class__.__name__)
# Parse standard unit rows (price + size + description)
standard_rows = soup.find_all("div", class_="OMl9pPN1h6gEVHf3-Pyw3")
for row in standard_rows:
unit = self._parse_standard_row(row, url)
if unit:
result.units.append(unit)
# Parse compact rows (price + size only, no description)
compact_rows = soup.find_all("div", class_="_3ea1Xmp6wkmi39zHaaXfUa")
for row in compact_rows:
unit = self._parse_compact_row(row, url)
if unit:
result.units.append(unit)
if not result.units:
result.warnings.append("No units found on page")
return result
def _parse_standard_row(self, row: BeautifulSoup, url: str) -> UnitResult | None:
"""Parse a standard unit row with price, size, and description."""
unit = UnitResult(url=url)
# Price: div with class '_1w_9K-RT7ovDwHPRzUGIzt'
price_el = row.find("div", class_="_1w_9K-RT7ovDwHPRzUGIzt")
if price_el:
unit.price = self.normalize_price(price_el.get_text(strip=True))
# Size: div with class '_1duec5zuiRUo83p89oK8jC'
size_el = row.find("div", class_="_1duec5zuiRUo83p89oK8jC")
if size_el:
size_text = size_el.get_text(strip=True)
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}
# Description: div with class '_2YTbZYDJKWW023QoDpsunD'
desc_el = row.find("div", class_="_2YTbZYDJKWW023QoDpsunD")
if desc_el:
unit.description = desc_el.get_text(strip=True)
if unit.size or unit.price:
return unit
return None
def _parse_compact_row(self, row: BeautifulSoup, url: str) -> UnitResult | None:
"""Parse a compact unit row with price and size only (no description)."""
unit = UnitResult(url=url)
# All text in compact rows uses span class '_2zX9LAmLV_HITMCldbRQ08'
spans = row.find_all("span", class_="_2zX9LAmLV_HITMCldbRQ08")
for span in spans:
text = span.get_text(strip=True)
# Try to determine if it's a price or a size
if text.startswith("$"):
unit.price = self.normalize_price(text)
elif self._SIZE_RE.search(text):
unit.size = text
w, ln, sq = self.normalize_size(text)
if w is not None:
unit.metadata = {"width": w, "length": ln, "sqft": sq}
if unit.size or unit.price:
return unit
return None
Scrape Runs (5)
-
exported Run #14852026-03-23 03:19:41.416652 | 6 units | Facility061274Parser | View Data →
-
exported Run #9922026-03-21 19:12:49.629624 | 6 units | Facility061274Parser | View Data →
-
exported Run #5452026-03-14 16:55:03.933725 | 6 units | Facility061274Parser | View Data →
-
exported Run #1472026-03-14 04:58:26.050323 | 6 units | Facility061274Parser | View Data →
-
exported Run #702026-03-14 01:00:11.025179 | 6 units | Facility061274Parser | View Data →
Run #70 Details
- Status
- exported
- Parser Used
- Facility061274Parser
- Platform Detected
- storageunitsoftware
- Units Found
- 6
- Stage Reached
- exported
- Timestamp
- 2026-03-14 01:00:11.025179
Timing
| Stage | Duration |
|---|---|
| Fetch | 6196ms |
| Detect | 24ms |
| Parse | 12ms |
| Export | 16ms |
Snapshot: 061274_20260314T010017Z.html · Show Snapshot · Open in New Tab
Parsed Units (6)
8'x10'
$80.00/mo
10'x15'
$100.00/mo
10'x14'
$100.00/mo
10'x20'
$110.00/mo
10'x40'
$220.00/mo
10X20
$90.00/mo