# IP Geo Visitor Analysis Toolkit A set of three Python scripts to process large-scale web visitor logs from MySQL, enrich them with geographic data, detect bots, and generate monthly analytics reports. --- ## Overview | Script | Purpose | |---|---| | `ip_geo_report.py` | Read visitor records from MySQL, resolve IPs to countries, export daily visit counts per country | | `analyze.py` | Read the CSV output from `ip_geo_report.py` and generate monthly visit stats with MoM changes and charts | | `bot_analyzer.py` | Select records from a date range and score each visit to classify as human, bot, or suspicious | --- ## Requirements - Python 3.8+ - MySQL database with visitor records - ipinfo `bundle_location_lite.mmdb` (free, download from [ipinfo.io](https://ipinfo.io/account/data-downloads)) --- ## Installation ```bash # Clone or copy scripts to your project folder mkdir visitor-analysis && cd visitor-analysis # Create virtual environment python3 -m venv venv source venv/bin/activate # Linux / macOS # venv\Scripts\activate # Windows # Install dependencies pip install mysql-connector-python maxminddb matplotlib ``` --- ## Project Structure ``` visitor-analysis/ ├── venv/ ← virtual environment (do not commit) ├── bundle_location_lite.mmdb ← ipinfo offline GeoIP database ├── ip_geo_report.py ← Script 1: IP → Country report ├── analyze.py ← Script 2: Monthly analytics + charts ├── bot_analyzer.py ← Script 3: Bot detection ├── requirements.txt ├── README.md ├── cache/ ← Auto-created: LRU disk cache + checkpoints └── report/ ← Auto-created: CSV output from Script 1 ``` --- ## Script 1 — `ip_geo_report.py` Reads all visitor records from MySQL in batches, resolves each IP address to a country using the ipinfo mmdb database, and produces a CSV report of daily visit counts per country. ### Features - Batch processing with cursor-based pagination (handles 100M+ rows) - Two-level cache: LRU memory (100k IPs) + disk shelve spillover - Resume from checkpoint on crash or interruption - ipinfo mmdb offline lookup → ipinfo API fallback - Bot/attack filtering before GeoIP lookup ### Configuration Edit the top section of `ip_geo_report.py`: ```python DB_CONFIG = { "host": "localhost", "user": "your_user", "password": "your_password", "database": "your_database", } TABLE_NAME = "visitors" # your table name IP_COLUMN = "ip" # IP address column DATE_COLUMN = "visit_date" # DATE or DATETIME column UA_COLUMN = "user_agent" # set None if not available PATH_COLUMN = "path" # set None if not available GEOIP_DB_PATH = "./bundle_location_lite.mmdb" IPINFO_TOKEN = "" # optional API fallback token BATCH_SIZE = 50_000 LRU_MAX_SIZE = 100_000 ``` ### Usage ```bash source venv/bin/activate python3 ip_geo_report.py ``` If interrupted, simply re-run — it resumes from the last checkpoint automatically. ### Output ``` report/ ├── report_YYYY-MM-DD.csv ← Country, Date, Visit Count └── summary_YYYY-MM-DD.csv ← Country, Total Visits (sorted) ``` --- ## Script 2 — `analyze.py` Reads the CSV output from `ip_geo_report.py` and generates monthly analytics including MoM (Month-over-Month) percentage changes and a 4-panel visualization chart. ### Features - Auto-detects latest `report_*.csv` in `./report/` - Handles multiple date formats (`YYYY-MM-DD`, `YYYYMMDD`, `YYYY/MM/DD`) - Monthly visit totals with MoM % change - Monthly unique country counts with MoM % change - Top N countries per month - 4-panel PNG chart (bar charts + MoM line + stacked country chart) ### Usage ```bash # Auto-detect latest report python3 analyze.py # Specify input file python3 analyze.py --input ./report/report_2026-09-27.csv # Custom output dir and top N countries python3 analyze.py \ --input ./report/report_2026-09-27.csv \ --output ./analysis \ --top 10 ``` ### Arguments | Argument | Default | Description | |---|---|---| | `--input`, `-i` | latest in `./report/` | Path to input CSV | | `--output`, `-o` | `./analysis/` | Output directory | | `--top`, `-n` | `10` | Top N countries per month | ### Output ``` analysis/ ├── monthly_summary_YYYYMMDD.csv ← Month, Visits, MoM%, Countries, MoM% ├── top_countries_YYYYMMDD.csv ← Month, Rank, Country, Visits, % └── analysis_chart_YYYYMMDD.png ← 4-panel visualization chart ``` ### Chart Panels | Panel | Content | |---|---| | Top-left | Monthly total visits bar + MoM % line | | Top-right | Monthly unique countries bar + MoM % line | | Bottom-left | MoM % comparison line chart with +/- shading | | Bottom-right | Stacked bar — top 5 countries (last 6 months) | --- ## Script 3 — `bot_analyzer.py` Selects visitor records from a MySQL date range and scores each visit across multiple signals to classify it as human, bot, or suspicious. ### Features - Two-pass processing: frequency counting then per-record scoring - Windowed frequency detection (per day, per hour, traffic ratio) - Pattern-based signals: user agent, request path, IP range - Outputs three separate CSVs: human / bot / suspicious - Detailed summary with top high-frequency IPs ### Scoring Rules | Signal | Score | Trigger | |---|---|---| | Invalid / Private IP | +10 | Reserved IP ranges (RFC 1918 etc.) | | Bot User Agent | +8 | googlebot, scrapers, crawlers | | High Freq Per Hour | +8 | IP hits > threshold in single hour | | Attack Path | +9 | SQLi, shells, scanner paths | | Tool User Agent | +7 | curl, wget, python, selenium | | No User Agent | +7 | Empty or missing UA | | High Freq Per Day | +7 | IP hits > threshold in single day | | Old IE Browser | +5 | IE 6/7/8 (commonly spoofed) | | High Traffic Ratio | +5 | IP > 1% of all traffic in range | | Suspicious Combo | +4 | Old UA + attack path together | | Empty Path | +3 | Request path is blank or just `/` | **Classification thresholds:** | Score | Classification | |---|---| | 0 – 2 | ✅ Human | | 3 – 4 | ⚠️ Suspicious | | 5+ | 🤖 Bot | ### Configuration ```python HIGH_FREQ_PER_DAY = 100 # flag if IP hits > N times in a single day HIGH_FREQ_PER_HOUR = 30 # flag if IP hits > N times in a single hour HIGH_FREQ_TOTAL_RATIO = 0.01 # flag if IP > 1% of total traffic in range BOT_SCORE_THRESHOLD = 5 # score >= this = bot SUSPICIOUS_THRESHOLD = 3 # score >= this = suspicious ``` ### Usage ```bash # Basic usage python3 bot_analyzer.py --start 2026-01-01 --end 2026-09-30 # Custom thresholds python3 bot_analyzer.py \ --start 2026-01-01 \ --end 2026-09-30 \ --bot-threshold 5 \ --freq-per-day 100 \ --freq-per-hour 30 \ --freq-ratio 0.01 \ --output ./bot_analysis ``` ### Arguments | Argument | Default | Description | |---|---|---| | `--start`, `-s` | required | Start date `YYYY-MM-DD` | | `--end`, `-e` | required | End date `YYYY-MM-DD` | | `--output`, `-o` | `./bot_analysis/` | Output directory | | `--bot-threshold` | `5` | Minimum score to classify as bot | | `--freq-per-day` | `100` | Max hits per day before flagging | | `--freq-per-hour` | `30` | Max hits per hour before flagging | | `--freq-ratio` | `0.01` | Max fraction of total traffic per IP | ### Output ``` bot_analysis/ ├── human_DATERANGE_TIMESTAMP.csv ← Confirmed human visits ├── bot_DATERANGE_TIMESTAMP.csv ← Confirmed bot visits + score + reasons ├── suspicious_DATERANGE_TIMESTAMP.csv ← Borderline visits for manual review └── summary_DATERANGE_TIMESTAMP.csv ← Stats, reason counts, top IPs ``` --- ## Recommended Workflow ``` 1. Run ip_geo_report.py → Processes all historical data → Outputs report/report_YYYY-MM-DD.csv 2. Run analyze.py → Reads the report CSV → Outputs monthly stats + chart 3. Run bot_analyzer.py --start YYYY-MM-DD --end YYYY-MM-DD → Focuses on a specific time window → Outputs human / bot / suspicious CSVs ``` --- ## GeoIP Database Setup 1. Register for a free account at [https://ipinfo.io/signup](https://ipinfo.io/signup) 2. Go to [https://ipinfo.io/account/data-downloads](https://ipinfo.io/account/data-downloads) 3. Download **`bundle_location_lite.mmdb`** 4. Place it in the project root directory The database provides: `country`, `country_code`, `continent`, `asn`, `as_name`, `as_domain` --- ## Database Table Requirements Your MySQL visitor table should have at minimum: | Column | Type | Required | Description | |---|---|---|---| | `id` | INT | ✅ Yes | Primary key for cursor pagination | | `ip` | VARCHAR | ✅ Yes | Visitor IP address | | `visit_date` | DATE / DATETIME | ✅ Yes | Visit timestamp | | `user_agent` | VARCHAR | ⚠️ Optional | Browser user agent string | | `path` | VARCHAR | ⚠️ Optional | Request path / URL | > Set `UA_COLUMN = None` and `PATH_COLUMN = None` in scripts if those columns do not exist. --- ## requirements.txt ``` mysql-connector-python maxminddb matplotlib ``` Install with: ```bash pip install -r requirements.txt ``` --- ## Notes - All scripts support resuming interrupted runs (Script 1 via checkpoint file, Script 3 via re-running with same date range) - Cache files in `./cache/` persist between runs to avoid redundant GeoIP lookups - Partial report data is saved every 10 batches to survive crashes - Scripts are designed for Python 3.8+ and tested on Ubuntu 20.04