Facility: 079766

Payette County Storage

Stale Data Warning: This facility has not been successfully scraped in 30 days (threshold: 3 days). Data may be outdated.
Facility Information active
Facility ID
079766
Name
Payette County Storage
URL
http://www.payettecountystorage.com/
Address
N/A
Platform
custom_facility_079766
Parser File
src/parsers/custom/facility_079766_parser.py
Last Scraped
2026-03-23 03:16:46.937176
Created
2026-03-06 23:45:35.865957
Updated
2026-03-23 03:16:46.945490
Parser & Healing Diagnosis working
Parser Status
✓ Working
Status Reason
N/A
Last Healing Attempt
Not attempted
Parser Source (src/parsers/custom/facility_079766_parser.py)
"""Parser for Payette County Storage facility.

This is a WordPress/Avada (Fusion Builder) site that lists storage units
as styled content boxes. Each box contains an h2 with the size (e.g. "5x10"),
an h1 with the monthly price (e.g. "$50"), and a FontAwesome icon that
indicates whether the unit is climate-controlled (fa-umbrella with circle-yes).
"""

from __future__ import annotations

import re

from bs4 import BeautifulSoup

from src.parsers.base import BaseParser, ParseResult, UnitResult


class Facility079766Parser(BaseParser):
    """Extract storage units from Payette County Storage.

    Units are rendered as Avada content boxes with:
      - h2.content-box-heading: size string (e.g. "5x10")
      - h1: monthly price (e.g. "$50")
      - i.fontawesome-icon: optional amenity icon;
        fa-umbrella with circle-yes indicates climate control
    """

    platform = "custom_facility_079766"

    _SIZE_RE = re.compile(r"^\d+[xX]\d+$", re.IGNORECASE)
    _PRICE_RE = re.compile(r"\$\s*(\d[\d,]*(?:\.\d+)?)")

    def parse(self, html: str, url: str = "") -> ParseResult:
        soup = BeautifulSoup(html, "lxml")
        result = ParseResult(platform=self.platform, parser_name=self.__class__.__name__)

        boxes = soup.find_all("div", class_="content-box-wrapper")
        if not boxes:
            result.warnings.append("No content-box-wrapper divs found on page")
            return result

        for box in boxes:
            # Extract size from h2.content-box-heading
            h2 = box.find("h2", class_="content-box-heading")
            if not h2:
                continue
            size_text = h2.get_text(strip=True)
            if not self._SIZE_RE.match(size_text):
                continue

            width, length, sqft = self.normalize_size(size_text)
            if width is None or length is None:
                continue

            normalized_size = f"{int(width)}x{int(length)}"

            # Extract price from h1
            h1 = box.find("h1")
            price: float | None = None
            if h1:
                price_match = self._PRICE_RE.search(h1.get_text(strip=True))
                if price_match:
                    price = self.normalize_price(price_match.group(0))

            # Detect climate control from icon class
            icon = box.find("i", class_="fontawesome-icon")
            climate_controlled = False
            if icon:
                icon_classes = " ".join(icon.get("class", []))
                if "fa-umbrella" in icon_classes and "circle-yes" in icon_classes:
                    climate_controlled = True

            description_parts = [normalized_size]
            if climate_controlled:
                description_parts.append("Climate Controlled")

            unit = UnitResult(
                size=normalized_size,
                price=price,
                description=", ".join(description_parts),
                url=url,
                metadata={
                    "width": width,
                    "length": length,
                    "sqft": sqft,
                    "climate_controlled": climate_controlled,
                },
            )
            result.units.append(unit)

        if not result.units:
            result.warnings.append("Content boxes found but no unit data could be extracted")

        return result

Scrape Runs (4)

Run #106 Details

Status
exported
Parser Used
Facility079766Parser
Platform Detected
table_layout
Units Found
3
Stage Reached
exported
Timestamp
2026-03-14 01:03:42.181571
Timing
Stage Duration
Fetch5015ms
Detect21ms
Parse11ms
Export14ms

Snapshot: 079766_20260314T010347Z.html · Show Snapshot · Open in New Tab

Parsed Units (3)

5x10

$50.00/mo

10x12

$75.00/mo

12x25

$115.00/mo

← Back to dashboard