Facility: 090745
U-Haul Casper WY (S. 82609)
- Facility ID
- 090745
- Name
- U-Haul Casper WY (S. 82609)
- URL
- https://www.uhaul.com/Locations/Self-Storage-near-Casper-WY-82609/792076/
- Address
- N/A
- Platform
- custom_facility_090745
- Parser File
- src/parsers/custom/facility_090745_parser.py
- Last Scraped
- 2026-03-23 03:21:16.500292
- Created
- 2026-03-06 23:45:35.865957
- Updated
- 2026-03-23 03:21:16.513125
- Parser Status
- ✓ Working
- Status Reason
- N/A
- Last Healing Attempt
- Not attempted
Parser Source (src/parsers/custom/facility_090745_parser.py)
"""Parser for U-Haul Storage of Casper, WY facility.
U-Haul location pages render storage units inside ``<ul class="uhjs-unit-list">``
elements, one per size tier (small, medium, large, etc.). Each unit is an
``<li class="divider">`` row containing:
- Size in ``<span class="nowrap">`` inside an ``<h4>`` (e.g. "10' x 10' x 8'")
- Label/tier name in the ``<h4>`` text before the ``<span>`` (e.g. "Medium")
- Monthly price in ``<b class="text-xl">`` (displayed price)
- Scarcity in ``<span class="text-callout text-bold">`` (e.g. "2 Units Left!")
- Amenities as ``<li>`` text items: "Drive Up", "No Climate", "Outside Level", etc.
"""
from __future__ import annotations
import re
from bs4 import BeautifulSoup
from src.parsers.base import BaseParser, ParseResult, UnitResult
class Facility090745Parser(BaseParser):
"""Extract storage units from U-Haul Storage of Casper (uhjs-unit-list layout)."""
platform = "custom_facility_090745"
# Matches dimensions like "10' x 10' x 8'" or "10' x 20'"
_SIZE_RE = re.compile(
r"(\d+(?:\.\d+)?)['\u2019\u2032]?\s*[xX\u00d7]\s*(\d+(?:\.\d+)?)['\u2019\u2032]?",
re.IGNORECASE,
)
def parse(self, html: str, url: str = "") -> ParseResult:
soup = BeautifulSoup(html, "lxml")
result = ParseResult(platform=self.platform, parser_name=self.__class__.__name__)
# All unit rows live inside ul.uhjs-unit-list elements
unit_lists = soup.select("ul.uhjs-unit-list")
for ul in unit_lists:
items = ul.select("li.divider")
for item in items:
unit = UnitResult()
# Size: "10' x 10' x 8'" inside span.nowrap within h4
size_el = item.select_one("h4 span.nowrap")
if size_el:
raw_size = size_el.get_text(strip=True)
unit.size = raw_size
m = self._SIZE_RE.search(raw_size)
if m:
width = float(m.group(1))
length = float(m.group(2))
unit.metadata = {"width": width, "length": length, "sqft": width * length}
# Description: tier label from h4 text (e.g. "Medium", "Large")
h4_el = item.select_one("h4")
if h4_el:
# Remove the size span text to get just the tier label
tier_text = h4_el.get_text(separator=" ", strip=True)
if size_el:
tier_text = tier_text.replace(size_el.get_text(strip=True), "").strip()
if tier_text:
unit.description = tier_text
# Price: b.text-xl contains the monthly rate
price_el = item.select_one("b.text-xl")
if price_el:
unit.price = self.normalize_price(price_el.get_text(strip=True))
# Scarcity: span.text-callout.text-bold (e.g. "2 Units Left!")
scarcity_el = item.select_one("span.text-callout.text-bold")
if scarcity_el:
unit.scarcity = scarcity_el.get_text(strip=True)
# Amenities: collect short bare <li> text items (Drive Up, No Climate, etc.)
amenities: list[str] = []
for li in item.find_all("li"):
li_text = li.get_text(strip=True)
# Exclude tab titles and long benefit descriptions
if li_text and len(li_text) < 40 and not li.get("class"):
amenities.append(li_text)
if amenities and unit.metadata is not None:
unit.metadata["amenities"] = amenities
elif amenities:
unit.metadata = {"amenities": amenities}
if unit.size or unit.price:
result.units.append(unit)
if not result.units:
result.warnings.append("No unit rows found in uhjs-unit-list elements")
return result
Scrape Runs (5)
-
exported Run #14952026-03-23 03:21:08.462329 | 1 units | Facility090745Parser | View Data →
-
exported Run #10022026-03-21 19:14:25.312315 | Facility090745Parser
-
exported Run #5552026-03-14 16:56:08.527655 | 1 units | Facility090745Parser | View Data →
-
exported Run #1602026-03-14 04:59:59.765763 | 1 units | Facility090745Parser | View Data →
-
exported Run #832026-03-14 01:01:42.467179 | 1 units | Facility090745Parser | View Data →
Run #1495 Details
- Status
- exported
- Parser Used
- Facility090745Parser
- Platform Detected
- storageunitsoftware
- Units Found
- 1
- Stage Reached
- exported
- Timestamp
- 2026-03-23 03:21:08.462329
Timing
| Stage | Duration |
|---|---|
| Fetch | 7764ms |
| Detect | 159ms |
| Parse | 95ms |
| Export | 6ms |
Snapshot: 090745_20260323T032116Z.html · Show Snapshot · Open in New Tab
Parsed Units (1)
15' x 20' x 8'
$179.95/mo
1 Unit Left!
All Failures for this Facility (1)
parse
_WarningAsException
scraper
no_units_extracted
warning
Run #N/A | 2026-03-21 19:14:33.933891
No units extracted for 090745
Stack trace
src.reporting.failure_reporter._WarningAsException: No units extracted for 090745