Facility: 087904
Storage Star - Laramie
- Facility ID
- 087904
- Name
- Storage Star - Laramie
- URL
- https://www.storagestar.com/self-storage/wyoming/laramie/830-boswell-dr/
- Address
- N/A
- Platform
- custom_facility_087904
- Parser File
- src/parsers/custom/facility_087904_parser.py
- Last Scraped
- 2026-03-23 03:20:06.264267
- Created
- 2026-03-06 23:45:35.865957
- Updated
- 2026-03-23 03:20:06.274604
- Parser Status
- ✓ Working
- Status Reason
- N/A
- Last Healing Attempt
- Not attempted
Parser Source (src/parsers/custom/facility_087904_parser.py)
"""Parser for StorageStar Laramie WY (Boswell Dr).
The site renders units in a table with class ``unitsTable``. Each ``<tr>``
with class ``shortableClass`` is one available unit and contains:
- ``.unit-type-listing-name`` — unit name/description (e.g. "Drive-Up B040")
- ``h2.widthHeight`` — dimensions (e.g. "5' WIDTH x 5' DEPTH")
- ``h3.actualMoPrice`` — web/sale price (e.g. "$37 /month")
- ``h3.withoutDiscntprice`` — standard/street price (e.g. "$62 /month")
- ``span.offer__content`` — promotion text (e.g. "$1 MOVE-IN")
- ``span.feature-item__title`` — amenity feature labels
"""
from __future__ import annotations
import re
from bs4 import BeautifulSoup
from src.parsers.base import BaseParser, ParseResult, UnitResult
# Matches "5' WIDTH x 5' DEPTH" or "10' WIDTH x 20' DEPTH" etc.
_SIZE_RE = re.compile(
r"(\d+(?:\.\d+)?)['\u2019\u2032]?\s*WIDTH\s*x\s*(\d+(?:\.\d+)?)['\u2019\u2032]?\s*DEPTH",
re.IGNORECASE,
)
# Extracts a dollar amount like "$37" or "$1,299.00" from a string that may contain "/month"
_PRICE_RE = re.compile(r"\$(\d[\d,]*(?:\.\d{1,2})?)")
class Facility087904Parser(BaseParser):
"""Extract storage units from StorageStar Laramie WY (Boswell Dr)."""
platform = "custom_facility_087904"
def parse(self, html: str, url: str = "") -> ParseResult:
soup = BeautifulSoup(html, "lxml")
result = ParseResult(platform=self.platform, parser_name=self.__class__.__name__)
unit_rows = soup.find_all("tr", class_=lambda c: c and "shortableClass" in c)
for row in unit_rows:
unit = UnitResult()
unit.url = url
# --- description (unit name, e.g. "Drive-Up B040") ---
name_el = row.find("div", class_="unit-type-listing-name")
if name_el:
unit.description = name_el.get_text(strip=True)
# --- size (e.g. "5' WIDTH x 5' DEPTH") ---
size_el = row.find("h2", class_="widthHeight")
if size_el:
size_text = size_el.get_text(" ", strip=True)
unit.size = size_text
m = _SIZE_RE.search(size_text)
if m:
width = float(m.group(1))
length = float(m.group(2))
unit.metadata = {"width": width, "length": length, "sqft": width * length}
# --- sale/web price (e.g. "$37 /month") ---
sale_el = row.find("h3", class_="actualMoPrice")
if sale_el:
m = _PRICE_RE.search(sale_el.get_text(strip=True))
if m:
unit.sale_price = self.normalize_price(m.group(1))
# --- standard/street price (e.g. "$62 /month") ---
std_el = row.find("h3", class_="withoutDiscntprice")
if std_el:
m = _PRICE_RE.search(std_el.get_text(strip=True))
if m:
unit.price = self.normalize_price(m.group(1))
# --- promotion text (e.g. "$1 MOVE-IN") ---
promo_el = row.find("span", class_="offer__content")
if promo_el:
unit.promotion = promo_el.get_text(strip=True)
# --- amenity features as metadata ---
feature_els = row.find_all("span", class_="feature-item__title")
if feature_els:
features = [f.get_text(strip=True) for f in feature_els if f.get_text(strip=True)]
if features:
unit.metadata = {**(unit.metadata or {}), "features": features}
if unit.size or unit.price or unit.sale_price:
result.units.append(unit)
if not result.units:
result.warnings.append("No units found on page")
return result
Scrape Runs (5)
-
exported Run #14872026-03-23 03:19:51.085925 | 12 units | Facility087904Parser | View Data →
-
exported Run #9942026-03-21 19:13:00.917068 | 12 units | Facility087904Parser | View Data →
-
exported Run #5472026-03-14 16:55:10.641107 | Facility087904Parser
-
exported Run #1502026-03-14 04:58:39.295632 | 13 units | Facility087904Parser | View Data →
-
exported Run #732026-03-14 01:00:27.973625 | Facility087904Parser
Run #73 Details
- Status
- exported
- Parser Used
- Facility087904Parser
- Platform Detected
- unknown
- Units Found
- 0
- Stage Reached
- exported
- Timestamp
- 2026-03-14 01:00:27.973625
Timing
| Stage | Duration |
|---|---|
| Fetch | 1842ms |
| Detect | 2ms |
| Parse | 0ms |
| Export | 16ms |
Snapshot: 087904_20260314T010029Z.html · Show Snapshot · Open in New Tab
No units found in this run.
All Failures for this Facility (2)
parse
_WarningAsException
scraper
no_units_extracted
warning
Run #N/A | 2026-03-14 16:55:12.999127
No units extracted for 087904
Stack trace
src.reporting.failure_reporter._WarningAsException: No units extracted for 087904
parse
_WarningAsException
scraper
no_units_extracted
warning
Run #N/A | 2026-03-14 01:00:29.876403
No units extracted for 087904
Stack trace
src.reporting.failure_reporter._WarningAsException: No units extracted for 087904