The Problem
Real‑estate analysts in Nairobi spend hours manually downloading listings, cleaning price strings, and inferring bedroom counts from noisy titles. The lack of a repeatable pipeline makes cross‑sectional market analysis slow and error‑prone.
What This Does
The repository implements a full ETL chain for Nairobi property data.
- Scraping –
nairobi_property_scraper_v2.pyandscrape_listings.pydrive HTTP calls to sites (e.g., Jiji, Pigiame) and write raw rows toall_raw_listings.csv. - Cleaning & Enrichment –
clean_properties.py,prepare_properties.py, andparser.pynormalize price fields, extract bedroom numbers, and compute per‑bedroom affordability. The cleaned output lands incleaned_properties.csvandlocation_summary_clean.csv. - Analysis & Visualization –
eda.pyproduces summary tables and charts undercharts/;map_nairobi.pybuilds the interactive HTML mapnairobi_affordability_map.html.
All scripts are pure Python, managed with requirements.txt.
How It Is Wired
Execution starts at the only explicit entry point: the main function in audit_data.py (line 151).
mainorchestrates the pipeline, calling:audit– validates raw data.clean– invokesclean_properties.clean_properties(the sole function in that module). *detect_unit_scale– determines price units.auditreaches out to the filesystem viasave_csv, which creates the target directory (Path(filepath).parent.mkdir). This is the only external write path observed.- The most heavily used internal helpers are in
scrape_listings.pyandnairobi_property_scraper_v2.py:make_record→clean(7 calls) prepares each scraped row.delay,sleep,asleepintroduce throttling; they are invoked from 11, 4, and 3 distinct places respectively, giving them the widest “blast radius”. * Network calls occur insidenairobi_property_scraper_v2.py(functionsc,row,fetch) andscrape_listings.py(functionsscrape_jiji,scrape_pigiame, etc.). - The call graph contains 90 resolved edges but no circular imports; each module stands alone, which eases isolated testing.
File‑by‑file responsibilities (derived from the “WHAT EACH FILE IS RESPONSIBLE FOR” block):
| File | Core duties | External effect |
|---|---|---|
nairobi_property_scraper_v2.py | 16 functions, network fetch, throttling | outbound HTTP |
scrape_listings.py | 13 functions, file I/O, record creation | read/write CSV |
audit_data.py | 4 functions, orchestration, CSV write | filesystem |
eda.py | 15 functions, chart generation | writes PNG charts |
map_nairobi.py | 9 functions, geocoding, map HTML creation | outbound geocode API |
build_summary.py | 6 functions, statistical aggregation | none |
prepare_properties.py | 2 functions, bedroom extraction | none |
clean_properties.py | 1 function, data cleaning | none |
parser.py | 1 function, bathroom parsing | none |
No module imports another, so changes to one script rarely ripple through others, but the high nesting depth (up to 12 levels) and broad exception blocks increase cognitive load when modifying the scraper modules.
How To Use It
# Clone the repo
git clone https://github.com/moses-y/nairobi_property_pricing.git
cd nairobi_property_pricing
# Install dependencies
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
No configuration files or environment variables are referenced in the code; the scripts use hard‑coded URLs and default output paths.
Run the full pipeline:
python audit_data.py
The command executes main, which scrapes, cleans, and writes the final CSVs and charts. Individual stages can be invoked directly (e.g., python nairobi_property_scraper_v2.py to fetch raw listings).
Real‑World Use
A market‑research team could schedule python audit_data.py nightly via cron. The resulting location_summary_clean.csv feeds a BI dashboard, while nairobi_affordability_map.html is embedded in a client‑facing web portal for interactive exploration.
Code Health & Issues
- HIGH – Missing LICENSE – no
LICENSEfile; default “all rights reserved” blocks reuse. - HIGH – No CI/CD – repository lacks any GitHub Actions, Travis, etc.; changes are not automatically built or tested.
- HIGH – No build gate for deployable artifacts – charts (e.g.,
charts/01_top_bottom_prices.png) are produced but never validated by a pipeline. - MEDIUM – No Dependabot/Renovate – only
requirements.txtpresent; no automated dependency updates. - MEDIUM – Broad exception handling –
nairobi_property_scraper_v2.pyandscrape_listings.pyuse bareexceptclauses, swallowing errors and complicating debugging. - MEDIUM – Deep nesting –
eda.py,nairobi_property_scraper_v2.py,scrape_listings.pyreach 12‑level indentation, making the control flow hard to follow. - MEDIUM – Oversized file –
scrape_listings.pyspans 636 lines, a single change can have wide impact.
Additional observations: no test suite, no lockfile (requirements.txt only), and no Dockerfile.
The Bottom Line
The repo delivers a functional end‑to‑end pipeline for Nairobi property data, but the codebase suffers from maintainability issues (deep nesting, large monolithic scripts) and lacks the SDLC scaffolding needed for production confidence (license, CI, tests). It is suitable for internal prototyping or as a foundation to be refactored and hardened before client deployment.