Initial commit: Sistema Autoparts DB

- Base de datos SQLite con información de vehículos
- Dashboard web con Flask y Bootstrap
- Scripts de web scraping para RockAuto
- Interfaz CLI para consultas
- Documentación completa del proyecto

Incluye:
- 12 marcas de vehículos
- 10,923 modelos
- 10,919 especificaciones de motores
- 12,075 combinaciones modelo-año-motor
This commit is contained in:
2026-01-19 08:45:03 +00:00
commit f395d67136
59 changed files with 10881 additions and 0 deletions

53
.gitignore vendored Normal file
View File

@@ -0,0 +1,53 @@
# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
# Virtual environments
venv/
ENV/
env/
.venv/
# IDE
.vscode/
.idea/
*.swp
*.swo
*~
# OS
.DS_Store
Thumbs.db
# Logs
*.log
# Local configuration
.claude/
*.local.json
# Temporary files
*.tmp
*.temp
# Backup files
*.bak
*.backup

103
DASHBOARD_GUIDE.md Normal file
View File

@@ -0,0 +1,103 @@
# Vehicle Database Dashboard - Complete Solution
## Overview
I have created a complete web-based dashboard for searching and filtering your vehicle database with the following components:
1. **Web Dashboard Interface** - A responsive, modern UI built with HTML, CSS, and JavaScript
2. **Flask Backend** - API server that connects to your SQLite database
3. **Filtering System** - Search by brand, model, year, and engine
4. **Data Visualization** - Display vehicle details in an attractive card layout
## Features
- **Four-way Filtering**: Filter vehicles by brand, model, year, and engine type
- **Responsive Design**: Works on desktop, tablet, and mobile devices
- **Real-time Updates**: Filters update immediately when selections change
- **Detailed Information**: Shows power, displacement, cylinders, fuel type, trim, drivetrain, and transmission
- **Modern UI**: Bootstrap-based interface with cards, badges, and icons
## Architecture
### Frontend
- `index.html`: Main dashboard page with Bootstrap styling
- `dashboard.js`: JavaScript for UI interactions and API calls
### Backend
- `server.py`: Flask application serving the dashboard and API
- API endpoints for brands, models, years, engines, and vehicles
## How to Use
### Starting the Dashboard
1. Navigate to the dashboard directory:
```bash
cd /home/Autopartes/dashboard
```
2. Start the server:
```bash
python3 server.py
```
3. Open your web browser and go to: `http://localhost:5000`
### Using the Dashboard
1. On the left panel, use the dropdowns to select filters:
- Brand: Select a vehicle manufacturer
- Model: Select a model (updates based on selected brand)
- Year: Select a production year
- Engine: Select an engine type
2. Click "Search Vehicles" to apply filters
3. Results appear in the right panel with detailed information
4. Use "Reset Filters" to clear all selections
## API Endpoints
The dashboard uses these API endpoints:
- `GET /api/brands` - Get all vehicle brands
- `GET /api/models?brand=[brand]` - Get models for a specific brand
- `GET /api/years` - Get all years
- `GET /api/engines` - Get all engines
- `GET /api/vehicles?[filters]` - Search vehicles with optional filters
## Files Created
```
dashboard/
├── index.html # Main dashboard page
├── dashboard.js # Frontend JavaScript
├── server.py # Flask backend
├── requirements.txt # Python dependencies
├── start_dashboard.sh # Startup script
├── README.md # Documentation
└── static/ # Static files directory (created by Flask)
```
## Customization
You can customize the dashboard by:
- Modifying the CSS styles in index.html
- Adding more filters in the JavaScript
- Changing the layout in index.html
- Adding more vehicle details in the display
## Troubleshooting
- If the server won't start, ensure Flask is installed: `sudo apt-get install python3-flask`
- If filters don't populate, check that your vehicle database has data
- If the page doesn't load, verify that the database file exists at `../vehicle_database/vehicle_database.db`
- Check the browser console for JavaScript errors
- Check the terminal for server errors
## Next Steps
1. Start the dashboard server
2. Browse your vehicle data using the intuitive interface
3. Add more data to your database using the manual input tools
4. Customize the dashboard to meet your specific needs
The dashboard is now ready to use and provides a powerful interface for exploring your vehicle database!

126
FINAL_SUMMARY.md Normal file
View File

@@ -0,0 +1,126 @@
# Vehicle Database with RockAuto Data Integration
## Project Overview
This project combines two components:
1. A comprehensive vehicle database system
2. A data extraction system for RockAuto.com vehicle information
Due to anti-bot measures on RockAuto.com, a manual extraction approach is recommended for collecting vehicle data.
## System Components
### 1. Vehicle Database
- SQLite database with normalized schema
- Tables for brands, models, years, engines, and their relationships
- Python API for managing the database
- Interactive query interface
### 2. Data Extraction Tools
- Automated scraper (for sites without anti-bot measures)
- Manual extraction guide for RockAuto.com
- Data import functionality
## Database Schema
The database consists of five main tables:
- **brands**: Vehicle manufacturers (Toyota, Ford, etc.)
- **models**: Vehicle models (Camry, F-150, etc.)
- **engines**: Engine specifications (2JZ-GTE, EcoBoost, etc.)
- **years**: Calendar years for vehicle production
- **model_year_engine**: Junction table linking all entities with trim levels and specifications
## Using the System
### Initial Setup
```bash
cd vehicle_database
./setup.sh
```
### Querying the Database
```bash
python3 scripts/query_interface.py
```
### Adding More Data Manually
```python
from ../vehicle_scraper/manual_input import ManualDataInput
input_tool = ManualDataInput()
# Add a single vehicle
input_tool.add_vehicle_data("Toyota", "Corolla", 2021, "1.8L 4-Cylinder")
# Add multiple vehicles
vehicles = [
{"make": "Nissan", "model": "Altima", "year": 2020, "engine": "2.5L 4-Cylinder"},
{"make": "Hyundai", "model": "Elantra", "year": 2019, "engine": "2.0L 4-Cylinder"}
]
input_tool.add_multiple_vehicles(vehicles)
```
## Manual Data Extraction from RockAuto.com
Since RockAuto has anti-bot measures, follow this process:
1. Open your web browser and go to: https://www.rockauto.com
2. Click on the "Catalog" link in the navigation menu
3. You will see a list of vehicle manufacturers (makes)
4. For each manufacturer:
- Click on the manufacturer name
- You'll see a page with vehicle models organized by year
- Note down the models and years you see
5. To find engine information:
- Click on a specific model/year combination
- You'll see parts categories for that vehicle
- Look for "Engine" or "Engine Mechanical" category
- Note down the engine type/specifications
6. Use the ManualDataInput class to add the collected data to your database
## File Structure
```
vehicle_database/ # Main database system
├── sql/
│ └── schema.sql # Database schema
├── scripts/
│ ├── database_manager.py # Main database manager
│ ├── query_interface.py # Interactive query interface
│ └── csv_importer.py # CSV import functionality
├── data/ # Sample CSV data files
├── vehicle_database.db # SQLite database file
├── setup.sh # Setup script
├── README.md # Project documentation
└── GETTING_STARTED.md # Getting started guide
vehicle_scraper/ # Data extraction tools
├── rockauto_scraper.py # Automated scraper (for other sites)
├── rockauto_scraper_enhanced.py # Enhanced scraper
├── manual_input.py # Manual input tool
├── manual_input_simple.py # Simplified manual input
└── requirements.txt # Python dependencies
```
## Extending the Database
To add more vehicle data:
1. Collect data manually from RockAuto.com using the provided guide
2. Use the ManualDataInput class to add data to the database
3. Or prepare CSV files in the required format and use the CSV importer
## Future Enhancements
- Web scraping capabilities for other automotive parts sites
- Export functionality to share data
- Advanced search and filtering options
- Data validation and cleaning tools
## Troubleshooting
If you encounter issues:
1. Check that Python 3.x is installed
2. Ensure all required packages are installed (`pip3 install -r requirements.txt`)
3. Verify database file permissions
4. Check that the schema matches the expected structure
The system is now ready to use. You can start by exploring the existing data through the query interface and then add more data as needed.

53
QUICK_START.sh Executable file
View File

@@ -0,0 +1,53 @@
#!/bin/bash
# Quick Start Script for Vehicle Database with RockAuto Integration
echo "==========================================="
echo "Vehicle Database & RockAuto Data Integration"
echo "==========================================="
echo ""
echo "Welcome! This system allows you to create a comprehensive vehicle database"
echo "with information from RockAuto.com (via manual extraction)."
echo ""
echo "STEP 1: Explore the existing database"
echo "-------------------------------------"
echo "Start the query interface to see existing data:"
echo " cd vehicle_database"
echo " python3 scripts/query_interface.py"
echo ""
echo "STEP 2: Add more data from RockAuto.com"
echo "---------------------------------------"
echo "Since RockAuto.com has anti-bot measures, you'll need to manually"
echo "extract data. Here's how:"
echo ""
echo "1. Visit https://www.rockauto.com/catalog/"
echo "2. Browse through manufacturers, models, years, and engines"
echo "3. Note down the information you find"
echo "4. Add it to your database using Python:"
echo ""
echo " from vehicle_scraper.manual_input_simple import ManualDataInput"
echo " input_tool = ManualDataInput(db_path='vehicle_database/vehicle_database.db')"
echo " input_tool.add_vehicle_data('Make', 'Model', Year, 'Engine')"
echo ""
echo "STEP 3: Database structure"
echo "--------------------------"
echo "The database contains these tables:"
echo "- brands: Vehicle manufacturers"
echo "- models: Vehicle models"
echo "- years: Production years"
echo "- engines: Engine specifications"
echo "- model_year_engine: Links between all the above"
echo ""
echo "STEP 4: Sample queries"
echo "----------------------"
echo "Try these queries in the interface:"
echo "- Search for all Toyotas: Brand = 'Toyota'"
echo "- Find 2020 models: Year = 2020"
echo "- Look for turbo engines: Engine = 'Turbo'"
echo ""
echo "Your database is located at: vehicle_database/vehicle_database.db"
echo ""
echo "To see all available scripts:"
echo " ls -la vehicle_database/scripts/"
echo ""
echo "Ready to start building your vehicle database!"
echo "=============================================="

306
README.md Normal file
View File

@@ -0,0 +1,306 @@
# Autoparts DB
Sistema completo de gestión de base de datos de vehículos y autopartes con dashboard web, herramientas de web scraping y múltiples interfaces de consulta.
## Descripción
**Autoparts DB** es una solución integral para la gestión de información de vehículos que incluye:
- Base de datos SQLite normalizada con información de marcas, modelos, motores y años
- Dashboard web moderno y responsivo para consultar y explorar datos
- Herramientas de web scraping para recopilar datos de RockAuto.com
- Interfaces de línea de comandos (CLI) y programática
- Scripts de utilidad para gestión y mantenimiento de datos
## Estadísticas de la Base de Datos
| Elemento | Cantidad |
|----------|----------|
| Marcas | 12 |
| Modelos | 10,923 |
| Motores | 10,919 |
| Combinaciones modelo-año-motor | 12,075 |
## Tecnologías Utilizadas
### Backend
- **Python 3** - Lenguaje principal
- **SQLite 3** - Base de datos
- **Flask 2.3.3** - Framework web
- **BeautifulSoup4** - Web scraping
- **requests** - HTTP client
- **lxml** - Parser XML/HTML
### Frontend
- **HTML5** - Estructura
- **Bootstrap 5.3.0** - Framework CSS
- **JavaScript (ES6+)** - Lógica cliente
- **Font Awesome 6.0.0** - Iconos
## Estructura del Proyecto
```
Autopartes/
├── vehicle_database/ # Sistema principal de base de datos
│ ├── sql/
│ │ └── schema.sql # Esquema de la base de datos
│ ├── scripts/
│ │ ├── database_manager.py # Gestión de la BD
│ │ ├── query_interface.py # Interfaz CLI
│ │ └── csv_importer.py # Importador CSV
│ ├── data/
│ │ ├── brands.csv # Datos de marcas
│ │ ├── engines.csv # Datos de motores
│ │ └── models.csv # Datos de modelos
│ ├── vehicle_database.db # Base de datos SQLite
│ └── setup.sh # Script de inicialización
├── dashboard/ # Interfaz web
│ ├── server.py # Backend Flask
│ ├── index.html # Frontend HTML
│ ├── dashboard.js # Lógica JavaScript
│ └── start_dashboard.sh # Script de inicio
├── vehicle_scraper/ # Herramientas de web scraping
│ ├── rockauto_scraper.py # Scraper RockAuto
│ ├── rockauto_scraper_v2.py # Scraper mejorado
│ ├── scrape_toyota.py # Scraper Toyota
│ ├── scrape_nissan_ford_chevrolet.py
│ └── manual_input.py # Ingreso manual
├── add_*.py # Scripts para agregar datos
├── remove_*.py # Scripts de limpieza
└── QUICK_START.sh # Guía rápida de inicio
```
## Instalación
### Requisitos Previos
- Python 3.8 o superior
- pip (gestor de paquetes de Python)
### Pasos de Instalación
1. **Clonar el repositorio**
```bash
git clone https://git.consultoria-as.com/[usuario]/Autoparts-DB.git
cd Autoparts-DB
```
2. **Instalar dependencias**
```bash
pip install flask requests beautifulsoup4 lxml
```
3. **Inicializar la base de datos (opcional - ya incluye datos)**
```bash
cd vehicle_database
./setup.sh
```
## Uso
### Iniciar el Dashboard Web
```bash
cd dashboard
python3 server.py
```
El dashboard estará disponible en: `http://localhost:5000`
### Usar la Interfaz CLI
```bash
cd vehicle_database/scripts
python3 query_interface.py
```
### Ejecutar Web Scraping
```bash
cd vehicle_scraper
python3 rockauto_scraper_v2.py
```
### Agregar Datos Manualmente
```bash
cd vehicle_scraper
python3 manual_input.py
```
## API REST
El dashboard expone los siguientes endpoints:
| Endpoint | Método | Descripción |
|----------|--------|-------------|
| `/api/brands` | GET | Obtiene todas las marcas |
| `/api/models?brand=X` | GET | Obtiene modelos por marca |
| `/api/years` | GET | Obtiene años disponibles |
| `/api/engines` | GET | Obtiene motores disponibles |
| `/api/vehicles` | GET | Búsqueda con filtros |
### Ejemplo de Uso
```bash
# Obtener todas las marcas
curl http://localhost:5000/api/brands
# Buscar vehículos por marca y año
curl "http://localhost:5000/api/vehicles?brand=Toyota&year=2020"
```
## Esquema de Base de Datos
### Tablas
#### brands
| Campo | Tipo | Descripción |
|-------|------|-------------|
| id | INTEGER | Clave primaria |
| name | TEXT | Nombre de la marca |
| country | TEXT | País de origen |
| founded_year | INTEGER | Año de fundación |
#### models
| Campo | Tipo | Descripción |
|-------|------|-------------|
| id | INTEGER | Clave primaria |
| brand_id | INTEGER | FK a brands |
| name | TEXT | Nombre del modelo |
| body_type | TEXT | Tipo de carrocería |
| generation | TEXT | Generación |
| production_start_year | INTEGER | Año inicio producción |
| production_end_year | INTEGER | Año fin producción |
#### engines
| Campo | Tipo | Descripción |
|-------|------|-------------|
| id | INTEGER | Clave primaria |
| name | TEXT | Nombre del motor |
| displacement_cc | INTEGER | Cilindrada en cc |
| cylinders | INTEGER | Número de cilindros |
| fuel_type | TEXT | Tipo de combustible |
| power_hp | INTEGER | Potencia en HP |
| torque_nm | INTEGER | Torque en Nm |
| engine_code | TEXT | Código del motor |
#### years
| Campo | Tipo | Descripción |
|-------|------|-------------|
| id | INTEGER | Clave primaria |
| year | INTEGER | Año |
#### model_year_engine
| Campo | Tipo | Descripción |
|-------|------|-------------|
| id | INTEGER | Clave primaria |
| model_id | INTEGER | FK a models |
| year_id | INTEGER | FK a years |
| engine_id | INTEGER | FK a engines |
| trim_level | TEXT | Nivel de equipamiento |
| drivetrain | TEXT | Tracción |
| transmission | TEXT | Transmisión |
### Diagrama de Relaciones
```
brands ──┐
├──< models ──┐
│ │
years ───┼─────────────┼──< model_year_engine
│ │
engines ─┴─────────────┘
```
## Scripts Disponibles
### Scripts de Datos
| Script | Descripción |
|--------|-------------|
| `add_toyota_data.py` | Agrega datos de Toyota |
| `add_honda_data.py` | Agrega datos de Honda |
| `add_nissan_data.py` | Agrega datos de Nissan |
| `add_ford_data.py` | Agrega datos de Ford |
| `add_chevrolet_data.py` | Agrega datos de Chevrolet |
| `add_audi_data.py` | Agrega datos de Audi |
| `add_acura_data.py` | Agrega datos de Acura |
| ... | Y más marcas |
### Scripts de Mantenimiento
| Script | Descripción |
|--------|-------------|
| `remove_brands_and_cleanup.py` | Limpia marcas innecesarias |
| `check_and_remove_brands.py` | Verifica y elimina marcas |
## Funcionalidades del Dashboard
### Panel de Filtros
- Selección de marca
- Selección de modelo (dinámico según marca)
- Filtro por año
- Filtro por motor
### Panel de Resultados
- Visualización en tarjetas
- Información detallada del vehículo
- Especificaciones del motor
- Datos de transmisión y tracción
### Características
- Diseño responsivo
- Actualización en tiempo real
- Animaciones y transiciones suaves
- Soporte para múltiples idiomas
## Arquitectura del Sistema
```
┌─────────────────┐ ┌──────────────────┐
│ RockAuto.com │────>│ Web Scraper │
└─────────────────┘ └────────┬─────────┘
v
┌─────────────────┐ ┌──────────────────┐
│ Manual Input │────>│ SQLite Database │
└─────────────────┘ └────────┬─────────┘
┌───────────────────────┼───────────────────────┐
│ │ │
v v v
┌─────────────────┐ ┌──────────────────┐ ┌──────────────────┐
│ Flask API │ │ CLI Interface │ │ CSV Importer │
└────────┬────────┘ └──────────────────┘ └──────────────────┘
v
┌─────────────────┐
│ Web Dashboard │
│ (Browser) │
└─────────────────┘
```
## Contribuir
1. Fork el repositorio
2. Crea una rama para tu feature (`git checkout -b feature/nueva-funcionalidad`)
3. Commit tus cambios (`git commit -am 'Agrega nueva funcionalidad'`)
4. Push a la rama (`git push origin feature/nueva-funcionalidad`)
5. Crea un Pull Request
## Licencia
Este proyecto es de uso interno.
## Contacto
Para más información, contactar al equipo de desarrollo.
---
**Autoparts DB** - Sistema de Gestión de Base de Datos de Vehículos

177
add_abarth_data.py Normal file
View File

@@ -0,0 +1,177 @@
#!/usr/bin/env python3
"""
Script para agregar datos de Abarth a la base de datos de vehículos
"""
import sqlite3
import os
def add_abarth_data():
# Verificar que la base de datos exista
db_path = "vehicle_database/vehicle_database.db"
if not os.path.exists(db_path):
print(f"Error: Base de datos no encontrada en {db_path}")
return
conn = sqlite3.connect(db_path)
cursor = conn.cursor()
print("Agregando datos de Abarth a la base de datos...")
try:
# Insertar la marca Abarth
cursor.execute("INSERT OR IGNORE INTO brands (name) VALUES (?)", ("Abarth",))
cursor.execute("SELECT id FROM brands WHERE name = ?", ("Abarth",))
brand_id = cursor.fetchone()[0]
print(f"Marca Abarth tiene ID: {brand_id}")
# Insertar modelos de Abarth
models = [
'1000', '1300', '2000', 'SIMCA', '850', '1150', '1600', '750', '204', '205'
]
for model in models:
cursor.execute(
"INSERT OR IGNORE INTO models (brand_id, name) VALUES (?, ?)",
(brand_id, model)
)
print(f"Agregados {len(models)} modelos de Abarth")
# Datos de años y motores para cada modelo
abarth_data = [
# 1000
('1000', 1969, '982cc L4'),
('1000', 1968, '982cc L4'),
('1000', 1967, '982cc L4'),
('1000', 1966, '982cc L4'),
('1000', 1965, '982cc L4'),
('1000', 1964, '982cc L4'),
('1000', 1963, '982cc L4'),
('1000', 1962, '982cc L4'),
# 1300
('1300', 1969, '1.3L L4'),
('1300', 1968, '1.3L L4'),
('1300', 1967, '1.3L L4'),
('1300', 1966, '1.3L L4'),
# 2000
('2000', 1969, '1.9L L4'),
('2000', 1968, '1.9L L4'),
('2000', 1967, '1.9L L4'),
('2000', 1966, '1.9L L4'),
# SIMCA
('SIMCA', 1969, '1.3L L4'),
('SIMCA', 1969, '2.0L L4'),
('SIMCA', 1968, '1.3L L4'),
('SIMCA', 1968, '2.0L L4'),
('SIMCA', 1967, '1.3L L4'),
('SIMCA', 1967, '2.0L L4'),
('SIMCA', 1966, '1.3L L4'),
('SIMCA', 1966, '2.0L L4'),
('SIMCA', 1965, '1.3L L4'),
('SIMCA', 1965, '2.0L L4'),
('SIMCA', 1964, '1.3L L4'),
('SIMCA', 1964, '2.0L L4'),
('SIMCA', 1963, '1.3L L4'),
('SIMCA', 1963, '2.0L L4'),
('SIMCA', 1962, '1.3L L4'),
('SIMCA', 1962, '2.0L L4'),
# 850
('850', 1966, '847cc L4'),
('850', 1965, '847cc L4'),
('850', 1964, '847cc L4'),
('850', 1963, '847cc L4'),
('850', 1962, '847cc L4'),
('850', 1961, '833cc L4'),
('850', 1960, '833cc L4'),
# 1150
('1150', 1966, '1.1L L4'),
# 1600
('1600', 1966, '1.6L L4'),
('1600', 1965, '1.6L L4'),
('1600', 1964, '1.6L L4'),
('1600', 1963, '1.6L L4'),
('1600', 1962, '1.6L L4'),
('1600', 1961, '1.6L L4'),
('1600', 1960, '1.6L L4'),
# 750
('750', 1961, '747cc L4'),
('750', 1960, '747cc L4'),
('750', 1959, '747cc L4'),
('750', 1958, '747cc L4'),
('750', 1957, '747cc L4'),
('750', 1956, '747cc L4'),
# 204
('204', 1955, '1.1L L4'),
('204', 1954, '1.1L L4'),
('204', 1953, '1.1L L4'),
('204', 1952, '1.1L L4'),
('204', 1951, '1.1L L4'),
('204', 1950, '1.1L L4'),
('204', 1949, '1.1L L4'),
# 205
('205', 1955, '1.1L L4'),
('205', 1954, '1.1L L4'),
('205', 1953, '1.1L L4'),
('205', 1952, '1.1L L4'),
('205', 1951, '1.1L L4'),
('205', 1950, '1.1L L4'),
('205', 1949, '1.1L L4'),
]
# Insertar años
years = list(set([data[1] for data in abarth_data])) # Obtener años únicos
for year in years:
cursor.execute("INSERT OR IGNORE INTO years (year) VALUES (?)", (year,))
print(f"Agregados {len(years)} años")
# Insertar motores
engines = list(set([data[2] for data in abarth_data])) # Obtener motores únicos
for engine in engines:
cursor.execute("INSERT OR IGNORE INTO engines (name) VALUES (?)", (engine,))
print(f"Agregados {len(engines)} motores")
# Crear combinaciones modelo-año-motor
for model_name, year, engine_name in abarth_data:
# Obtener IDs
cursor.execute("SELECT id FROM models WHERE brand_id = ? AND name = ?", (brand_id, model_name))
model_id = cursor.fetchone()
if model_id:
model_id = model_id[0]
else:
print(f"Advertencia: Modelo {model_name} no encontrado para la marca Abarth")
continue
cursor.execute("SELECT id FROM years WHERE year = ?", (year,))
year_id = cursor.fetchone()[0]
cursor.execute("SELECT id FROM engines WHERE name = ?", (engine_name,))
engine_id = cursor.fetchone()[0]
# Insertar la combinación modelo-año-motor
cursor.execute(
"""INSERT OR IGNORE INTO model_year_engine
(model_id, year_id, engine_id) VALUES (?, ?, ?)""",
(model_id, year_id, engine_id)
)
conn.commit()
print(f"Se agregaron {len(abarth_data)} combinaciones modelo-año-motor para Abarth")
print("Datos de Abarth agregados exitosamente a la base de datos!")
except Exception as e:
print(f"Error al agregar datos de Abarth: {e}")
conn.rollback()
finally:
conn.close()
if __name__ == "__main__":
add_abarth_data()

178
add_ac_data.py Normal file
View File

@@ -0,0 +1,178 @@
#!/usr/bin/env python3
"""
Script para agregar datos de AC a la base de datos de vehículos
"""
import sqlite3
import os
def add_ac_data():
# Verificar que la base de datos exista
db_path = "vehicle_database/vehicle_database.db"
if not os.path.exists(db_path):
print(f"Error: Base de datos no encontrada en {db_path}")
return
conn = sqlite3.connect(db_path)
cursor = conn.cursor()
print("Agregando datos de AC a la base de datos...")
try:
# Insertar la marca AC
cursor.execute("INSERT OR IGNORE INTO brands (name) VALUES (?)", ("AC",))
cursor.execute("SELECT id FROM brands WHERE name = ?", ("AC",))
brand_id = cursor.fetchone()[0]
print(f"Marca AC tiene ID: {brand_id}")
# Insertar modelos de AC
models = [
'428', 'ACE', 'ACECA', 'GREYHOUND', 'TWO-LITRE'
]
for model in models:
cursor.execute(
"INSERT OR IGNORE INTO models (brand_id, name) VALUES (?, ?)",
(brand_id, model)
)
print(f"Agregados {len(models)} modelos de AC")
# Datos de años y motores para cada modelo
ac_data = [
# 428
('428', 1973, '7.0L V8'),
('428', 1972, '7.0L V8'),
('428', 1971, '7.0L V8'),
('428', 1970, '7.0L V8'),
('428', 1969, '7.0L V8'),
('428', 1968, '7.0L V8'),
('428', 1967, '7.0L V8'),
# ACE
('ACE', 1963, '2.0L L6'),
('ACE', 1963, '2.6L L6'),
('ACE', 1962, '2.0L L6'),
('ACE', 1962, '2.6L L6'),
('ACE', 1961, '2.0L L6'),
('ACE', 1961, '2.6L L6'),
('ACE', 1960, '2.0L L6'),
('ACE', 1960, '2.6L L6'),
('ACE', 1959, '2.0L L6'),
('ACE', 1958, '2.0L L6'),
('ACE', 1957, '2.0L L6'),
('ACE', 1956, '2.0L L6'),
('ACE', 1955, '2.0L L6'),
('ACE', 1954, '2.0L L6'),
('ACE', 1953, '2.0L L6'),
# ACECA
('ACECA', 1963, '2.0L L6'),
('ACECA', 1963, '2.6L L6'),
('ACECA', 1962, '2.0L L6'),
('ACECA', 1962, '2.6L L6'),
('ACECA', 1961, '2.0L L6'),
('ACECA', 1961, '2.6L L6'),
('ACECA', 1960, '2.0L L6'),
('ACECA', 1960, '2.6L L6'),
('ACECA', 1958, '2.0L L6'),
('ACECA', 1957, '2.0L L6'),
('ACECA', 1956, '2.0L L6'),
('ACECA', 1955, '2.0L L6'),
# GREYHOUND
('GREYHOUND', 1963, '2.0L L6'),
('GREYHOUND', 1962, '2.0L L6'),
('GREYHOUND', 1961, '2.0L L6'),
('GREYHOUND', 1960, '2.0L L6'),
# TWO-LITRE
('TWO-LITRE', 1958, '2.0L L6'),
('TWO-LITRE', 1957, '2.0L L6'),
('TWO-LITRE', 1956, '2.0L L6'),
('TWO-LITRE', 1955, '2.0L L6'),
('TWO-LITRE', 1954, '2.0L L6'),
('TWO-LITRE', 1953, '2.0L L6'),
('TWO-LITRE', 1952, '2.0L L6'),
('TWO-LITRE', 1951, '2.0L L6'),
('TWO-LITRE', 1950, '2.0L L6'),
('TWO-LITRE', 1949, '2.0L 122cid L6'),
('TWO-LITRE', 1948, '2.0L 122cid L6'),
('TWO-LITRE', 1947, '2.0L 122cid L6'),
]
# Insertar años
years = list(set([data[1] for data in ac_data])) # Obtener años únicos
for year in years:
cursor.execute("INSERT OR IGNORE INTO years (year) VALUES (?)", (year,))
print(f"Agregados {len(years)} años")
# Insertar motores
engines = list(set([data[2] for data in ac_data])) # Obtener motores únicos
for engine in engines:
cursor.execute("INSERT OR IGNORE INTO engines (name) VALUES (?)", (engine,))
print(f"Agregados {len(engines)} motores")
# Crear combinaciones modelo-año-motor
for model_name, year, engine_name in ac_data:
# Obtener IDs
cursor.execute("SELECT id FROM models WHERE brand_id = ? AND name = ?", (brand_id, model_name))
model_result = cursor.fetchone()
if model_result:
model_id = model_result[0]
else:
print(f"Advertencia: Modelo {model_name} no encontrado para la marca AC")
continue
cursor.execute("SELECT id FROM years WHERE year = ?", (year,))
year_result = cursor.fetchone()
if year_result:
year_id = year_result[0]
else:
print(f"Advertencia: Año {year} no encontrado")
continue
cursor.execute("SELECT id FROM engines WHERE name = ?", (engine_name,))
engine_result = cursor.fetchone()
if engine_result:
engine_id = engine_result[0]
else:
print(f"Advertencia: Motor {engine_name} no encontrado")
continue
# Insertar la combinación modelo-año-motor
cursor.execute(
"""INSERT OR REPLACE INTO model_year_engine
(model_id, year_id, engine_id) VALUES (?, ?, ?)""",
(model_id, year_id, engine_id)
)
conn.commit()
print(f"Se agregaron {len(ac_data)} combinaciones modelo-año-motor para AC")
print("Datos de AC agregados exitosamente a la base de datos!")
# Mostrar algunos resultados
print("\nAlgunos vehículos AC agregados:")
cursor.execute("""
SELECT b.name, m.name, y.year, e.name
FROM model_year_engine mye
JOIN models m ON mye.model_id = m.id
JOIN brands b ON m.brand_id = b.id
JOIN years y ON mye.year_id = y.id
JOIN engines e ON mye.engine_id = e.id
WHERE b.name = 'AC'
ORDER BY m.name, y.year DESC
LIMIT 10
""")
results = cursor.fetchall()
for brand, model, year, engine in results:
print(f" {year} {brand} {model} - {engine}")
except Exception as e:
print(f"Error al agregar datos de AC: {e}")
conn.rollback()
finally:
conn.close()
if __name__ == "__main__":
add_ac_data()

View File

@@ -0,0 +1,200 @@
#!/usr/bin/env python3
"""
Script para agregar datos adicionales de Acura a la base de datos de vehículos
"""
import sqlite3
import os
def add_acura_additional_data():
# Verificar que la base de datos exista
db_path = "vehicle_database/vehicle_database.db"
if not os.path.exists(db_path):
print(f"Error: Base de datos no encontrada en {db_path}")
return
conn = sqlite3.connect(db_path)
cursor = conn.cursor()
print("Agregando datos adicionales de Acura a la base de datos...")
try:
# Asegurar que la marca Acura exista
cursor.execute("INSERT OR IGNORE INTO brands (name) VALUES (?)", ("ACURA",))
cursor.execute("SELECT id FROM brands WHERE name = ?", ("ACURA",))
brand_id = cursor.fetchone()[0]
print(f"Marca ACURA tiene ID: {brand_id}")
# Insertar modelos adicionales de Acura que pueden faltar
additional_models = [
'CSX', 'MDX', 'RL', 'RSX', 'TL', 'TSX', 'EL', 'CL', 'NSX', 'SLX', 'INTEGRA'
]
for model in additional_models:
cursor.execute(
"INSERT OR IGNORE INTO models (brand_id, name) VALUES (?, ?)",
(brand_id, model)
)
print(f"Agregados {len(additional_models)} modelos de Acura (existentes o nuevos)")
# Datos adicionales de años y motores para cada modelo
acura_additional_data = [
# 2006
('CSX', 2006, '2.0L L4'),
('MDX', 2006, '3.5L V6'),
('RL', 2006, '3.5L V6'),
('RSX', 2006, '2.0L L4'),
('TL', 2006, '3.2L V6'),
('TSX', 2006, '2.4L L4'),
# 2005
('EL', 2005, '1.7L L4'),
('MDX', 2005, '3.5L V6'),
('NSX', 2005, '3.0L V6'),
('RSX', 2005, '3.2L V6'),
('RL', 2005, '3.5L V6'),
('RSX', 2005, '2.0L L4'),
('TL', 2005, '3.2L V6'),
('TSX', 2005, '2.4L L4'),
# 2004
('EL', 2004, '1.7L L4'),
('MDX', 2004, '3.5L V6'),
('NSX', 2004, '3.0L V6'),
('RSX', 2004, '3.2L V6'),
('RL', 2004, '3.5L V6'),
('TL', 2004, '3.2L V6'),
('TSX', 2004, '2.4L L4'),
# 2003
('CL', 2003, '3.2L V6'),
('EL', 2003, '1.7L L4'),
('MDX', 2003, '3.5L V6'),
('NSX', 2003, '3.0L V6'),
('RL', 2003, '3.5L V6'),
('RSX', 2003, '2.0L L4'),
('TL', 2003, '3.2L V6'),
# 2002
('CL', 2002, '3.2L V6'),
('EL', 2002, '1.7L L4'),
('MDX', 2002, '3.5L V6'),
('NSX', 2002, '3.0L V6'),
('RL', 2002, '3.5L V6'),
('RSX', 2002, '2.0L L4'),
('TL', 2002, '3.2L V6'),
# 2001
('CL', 2001, '3.2L V6'),
('EL', 2001, '1.7L L4'),
('INTEGRA', 2001, '1.8L L4'),
('MDX', 2001, '3.5L V6'),
('NSX', 2001, '3.0L V6'),
('RL', 2001, '3.5L V6'),
('TL', 2001, '3.2L V6'),
# 2000
('EL', 2000, '1.6L L4'),
('INTEGRA', 2000, '1.8L L4'),
('NSX', 2000, '3.0L V6'),
('RL', 2000, '3.5L V6'),
('TL', 2000, '3.2L V6'),
# 1999
('CL', 1999, '2.3L L4'),
('CL', 1999, '3.0L V6'),
('EL', 1999, '1.6L L4'),
('INTEGRA', 1999, '1.8L L4'),
('NSX', 1999, '3.0L V6'),
('RL', 1999, '3.5L V6'),
('SLX', 1999, '3.5L V6'),
('TL', 1999, '3.2L V6'),
# 1998
('CL', 1998, '2.3L L4'),
('CL', 1998, '3.0L V6'),
('EL', 1998, '1.6L L4'),
('INTEGRA', 1998, '1.8L L4'),
('NSX', 1998, '3.0L V6'),
('RL', 1998, '3.5L V6'),
('SLX', 1998, '3.5L V6'),
('TL', 1998, '2.5L L5'),
('TL', 1998, '3.2L V6')
]
# Insertar años adicionales
years = list(set([data[1] for data in acura_additional_data])) # Obtener años únicos
for year in years:
cursor.execute("INSERT OR IGNORE INTO years (year) VALUES (?)", (year,))
print(f"Agregados {len(years)} años adicionales")
# Insertar motores adicionales
engines = list(set([data[2] for data in acura_additional_data])) # Obtener motores únicos
for engine in engines:
cursor.execute("INSERT OR IGNORE INTO engines (name) VALUES (?)", (engine,))
print(f"Agregados {len(engines)} motores adicionales")
# Crear combinaciones modelo-año-motor adicionales
for model_name, year, engine_name in acura_additional_data:
# Obtener IDs
cursor.execute("SELECT id FROM models WHERE brand_id = ? AND name = ?", (brand_id, model_name))
model_result = cursor.fetchone()
if model_result:
model_id = model_result[0]
else:
print(f"Advertencia: Modelo {model_name} no encontrado para la marca ACURA")
continue
cursor.execute("SELECT id FROM years WHERE year = ?", (year,))
year_result = cursor.fetchone()
if year_result:
year_id = year_result[0]
else:
print(f"Advertencia: Año {year} no encontrado")
continue
cursor.execute("SELECT id FROM engines WHERE name = ?", (engine_name,))
engine_result = cursor.fetchone()
if engine_result:
engine_id = engine_result[0]
else:
print(f"Advertencia: Motor {engine_name} no encontrado")
continue
# Insertar la combinación modelo-año-motor
cursor.execute(
"""INSERT OR REPLACE INTO model_year_engine
(model_id, year_id, engine_id) VALUES (?, ?, ?)""",
(model_id, year_id, engine_id)
)
conn.commit()
print(f"Se agregaron {len(acura_additional_data)} combinaciones modelo-año-motor adicionales para ACURA")
print("Datos adicionales de ACURA agregados exitosamente a la base de datos!")
# Mostrar algunos resultados
print("\nAlgunos vehículos ACURA adicionales agregados:")
cursor.execute("""
SELECT b.name, m.name, y.year, e.name
FROM model_year_engine mye
JOIN models m ON mye.model_id = m.id
JOIN brands b ON m.brand_id = b.id
JOIN years y ON mye.year_id = y.id
JOIN engines e ON mye.engine_id = e.id
WHERE b.name = 'ACURA' AND y.year <= 2006
ORDER BY m.name, y.year DESC
LIMIT 15
""")
results = cursor.fetchall()
for brand, model, year, engine in results:
print(f" {year} {brand} {model} - {engine}")
except Exception as e:
print(f"Error al agregar datos adicionales de ACURA: {e}")
conn.rollback()
finally:
conn.close()
if __name__ == "__main__":
add_acura_additional_data()

317
add_acura_data.py Normal file
View File

@@ -0,0 +1,317 @@
#!/usr/bin/env python3
"""
Script para agregar datos de Acura a la base de datos de vehículos
"""
import sqlite3
import os
def add_acura_data():
# Verificar que la base de datos exista
db_path = "vehicle_database/vehicle_database.db"
if not os.path.exists(db_path):
print(f"Error: Base de datos no encontrada en {db_path}")
return
conn = sqlite3.connect(db_path)
cursor = conn.cursor()
print("Agregando datos de Acura a la base de datos...")
try:
# Insertar la marca Acura
cursor.execute("INSERT OR IGNORE INTO brands (name) VALUES (?)", ("ACURA",))
cursor.execute("SELECT id FROM brands WHERE name = ?", ("ACURA",))
brand_id = cursor.fetchone()[0]
print(f"Marca ACURA tiene ID: {brand_id}")
# Insertar modelos de Acura
models = [
'MDX', 'ADX', 'INTEGRA', 'RDX', 'TLX', 'ZDX', 'ILX', 'NSX', 'RLX', 'TL', 'TSX', 'CSX'
]
for model in models:
cursor.execute(
"INSERT OR IGNORE INTO models (brand_id, name) VALUES (?, ?)",
(brand_id, model)
)
print(f"Agregados {len(models)} modelos de Acura")
# Datos de años y motores para cada modelo
acura_data = [
# 2026
('MDX', 2026, '3.0L V6 Turbocharged'),
('MDX', 2026, '3.5L V6'),
# 2025
('ADX', 2025, '1.5L L4 Turbocharged'),
('INTEGRA', 2025, '1.5L L4 Turbocharged'),
('INTEGRA', 2025, '2.0L L4 Turbocharged'),
('MDX', 2025, '3.0L V6 Turbocharged'),
('MDX', 2025, '3.5L V6'),
('RDX', 2025, '2.0L L4 Turbocharged'),
('TLX', 2025, '2.0L L4 Turbocharged'),
('TLX', 2025, '3.0L V6 Turbocharged'),
# 2024
('INTEGRA', 2024, '1.5L L4 Turbocharged'),
('INTEGRA', 2024, '2.0L L4 Turbocharged'),
('MDX', 2024, '3.0L V6 Turbocharged'),
('MDX', 2024, '3.5L V6'),
('RDX', 2024, '2.0L L4 Turbocharged'),
('TLX', 2024, '2.0L L4 Turbocharged'),
('TLX', 2024, '3.0L V6 Turbocharged'),
('ZDX', 2024, 'ELECTRIC'),
# 2023
('INTEGRA', 2023, '1.5L L4 Turbocharged'),
('MDX', 2023, '3.0L V6 Turbocharged'),
('MDX', 2023, '3.5L V6'),
('RDX', 2023, '2.0L L4 Turbocharged'),
('TLX', 2023, '2.0L L4 Turbocharged'),
('TLX', 2023, '3.0L V6 Turbocharged'),
# 2022
('ILX', 2022, '2.4L L4'),
('MDX', 2022, '3.0L V6 Turbocharged'),
('MDX', 2022, '3.5L V6'),
('NSX', 2022, '3.5L V6 ELECTRIC/GAS Turbocharged'),
('RDX', 2022, '2.0L L4 Turbocharged'),
('TLX', 2022, '2.0L L4 Turbocharged'),
('TLX', 2022, '3.0L V6 Turbocharged'),
# 2021
('ILX', 2021, '2.4L L4'),
('NSX', 2021, '3.5L V6 ELECTRIC/GAS Turbocharged'),
('RDX', 2021, '2.0L L4 Turbocharged'),
('TLX', 2021, '2.0L L4 Turbocharged'),
('TLX', 2021, '3.0L V6 Turbocharged'),
# 2020
('ILX', 2020, '2.4L L4'),
('MDX', 2020, '3.0L V6 ELECTRIC/GAS'),
('MDX', 2020, '3.5L V6'),
('NSX', 2020, '3.5L V6 ELECTRIC/GAS Turbocharged'),
('RDX', 2020, '2.0L L4 Turbocharged'),
('RLX', 2020, '3.5L V6'),
('RLX', 2020, '3.5L V6 ELECTRIC/GAS'),
('TLX', 2020, '2.4L L4'),
('TLX', 2020, '3.5L V6 DOHC'),
('TLX', 2020, '3.5L V6 SOHC'),
# 2019
('ILX', 2019, '2.4L L4'),
('MDX', 2019, '3.0L V6'),
('MDX', 2019, '3.0L V6 ELECTRIC/GAS'),
('MDX', 2019, '3.5L V6'),
('NSX', 2019, '3.5L V6 ELECTRIC/GAS Turbocharged'),
('RDX', 2019, '2.0L L4 Turbocharged'),
('RLX', 2019, '3.5L V6'),
('RLX', 2019, '3.5L V6 ELECTRIC/GAS'),
('TLX', 2019, '2.4L L4'),
('TLX', 2019, '3.5L V6'),
# 2018
('ILX', 2018, '2.4L L4'),
('MDX', 2018, '3.0L V6 ELECTRIC/GAS'),
('MDX', 2018, '3.5L V6'),
('NSX', 2018, '3.5L V6 ELECTRIC/GAS Turbocharged'),
('RDX', 2018, '3.5L V6'),
('RLX', 2018, '3.5L V6'),
('RLX', 2018, '3.5L V6 ELECTRIC/GAS'),
('TLX', 2018, '2.4L L4'),
('TLX', 2018, '3.5L V6'),
# 2017
('ILX', 2017, '2.4L L4'),
('MDX', 2017, '3.0L V6 ELECTRIC/GAS'),
('MDX', 2017, '3.5L V6'),
('NSX', 2017, '3.5L V6 ELECTRIC/GAS Turbocharged'),
('RDX', 2017, '3.5L V6'),
('RLX', 2017, '3.5L V6'),
('RLX', 2017, '3.5L V6 ELECTRIC/GAS'),
('TLX', 2017, '2.4L L4'),
('TLX', 2017, '3.5L V6'),
# 2016
('ILX', 2016, '2.4L L4'),
('MDX', 2016, '3.5L V6'),
('RDX', 2016, '3.5L V6'),
('RLX', 2016, '3.5L V6'),
('RLX', 2016, '3.5L V6 ELECTRIC/GAS'),
('TLX', 2016, '2.4L L4'),
('TLX', 2016, '3.5L V6'),
# 2015
('ILX', 2015, '1.5L L4 ELECTRIC/GAS'),
('ILX', 2015, '2.0L L4'),
('ILX', 2015, '2.4L L4'),
('MDX', 2015, '3.5L V6'),
('RDX', 2015, '3.5L V6'),
('RLX', 2015, '3.5L V6'),
('RLX', 2015, '3.5L V6 ELECTRIC/GAS'),
('TLX', 2015, '2.4L L4'),
('TLX', 2015, '3.5L V6'),
# 2014
('ILX', 2014, '1.5L L4 ELECTRIC/GAS'),
('ILX', 2014, '2.0L L4'),
('ILX', 2014, '2.4L L4'),
('MDX', 2014, '3.5L V6'),
('RDX', 2014, '3.5L V6'),
('RLX', 2014, '3.5L V6'),
('RLX', 2014, '3.5L V6 ELECTRIC/GAS'),
('TL', 2014, '3.5L V6'),
('TSX', 2014, '2.4L L4'),
('TSX', 2014, '3.5L V6'),
# 2013
('ILX', 2013, '1.5L L4 ELECTRIC/GAS'),
('ILX', 2013, '2.0L L4'),
('ILX', 2013, '2.4L L4'),
('MDX', 2013, '3.7L V6'),
('RDX', 2013, '3.5L V6'),
('TL', 2013, '3.5L V6'),
('TL', 2013, '3.7L V6'),
('TSX', 2013, '2.4L L4'),
('TSX', 2013, '3.5L V6'),
('ZDX', 2013, '3.7L V6'),
# 2012
('MDX', 2012, '3.7L V6'),
('RDX', 2012, '2.3L L4 Turbocharged'),
('RL', 2012, '3.7L V6'),
('TL', 2012, '3.5L V6'),
('TL', 2012, '3.7L V6'),
('TSX', 2012, '2.4L L4'),
('TSX', 2012, '3.5L V6'),
('ZDX', 2012, '3.7L V6'),
# 2011
('CSX', 2011, '2.0L L4'),
('MDX', 2011, '3.7L V6'),
('RDX', 2011, '2.3L L4 Turbocharged'),
('RL', 2011, '3.7L V6'),
('TL', 2011, '3.5L V6'),
('TL', 2011, '3.7L V6'),
('TSX', 2011, '2.4L L4'),
('TSX', 2011, '3.5L V6'),
('ZDX', 2011, '3.7L V6'),
# 2010
('CSX', 2010, '2.0L L4'),
('MDX', 2010, '3.7L V6'),
('RDX', 2010, '2.3L L4 Turbocharged'),
('RL', 2010, '3.7L V6'),
('TL', 2010, '3.5L V6'),
('TL', 2010, '3.7L V6'),
('TSX', 2010, '2.4L L4'),
('TSX', 2010, '3.5L V6'),
('ZDX', 2010, '3.7L V6'),
# 2009
('CSX', 2009, '2.0L L4'),
('MDX', 2009, '3.7L V6'),
('RDX', 2009, '2.3L L4 Turbocharged'),
('RL', 2009, '3.7L V6'),
('TL', 2009, '3.5L V6'),
('TL', 2009, '3.7L V6'),
('TSX', 2009, '2.4L L4'),
('TSX', 2009, '3.5L V6'),
# 2008
('CSX', 2008, '2.0L L4'),
('MDX', 2008, '3.7L V6'),
('RDX', 2008, '2.3L L4 Turbocharged'),
('RL', 2008, '3.5L V6'),
('TL', 2008, '3.2L V6'),
('TL', 2008, '3.5L V6'),
('TSX', 2008, '2.4L L4'),
('TSX', 2008, '3.5L V6'),
# 2007
('CSX', 2007, '2.0L L4'),
('MDX', 2007, '3.7L V6'),
('RDX', 2007, '2.3L L4 Turbocharged'),
('RL', 2007, '3.5L V6'),
('TL', 2007, '3.2L V6'),
('TL', 2007, '3.5L V6'),
('TSX', 2007, '2.4L L4')
]
# Insertar años
years = list(set([data[1] for data in acura_data])) # Obtener años únicos
for year in years:
cursor.execute("INSERT OR IGNORE INTO years (year) VALUES (?)", (year,))
print(f"Agregados {len(years)} años")
# Insertar motores
engines = list(set([data[2] for data in acura_data])) # Obtener motores únicos
for engine in engines:
cursor.execute("INSERT OR IGNORE INTO engines (name) VALUES (?)", (engine,))
print(f"Agregados {len(engines)} motores")
# Crear combinaciones modelo-año-motor
for model_name, year, engine_name in acura_data:
# Obtener IDs
cursor.execute("SELECT id FROM models WHERE brand_id = ? AND name = ?", (brand_id, model_name))
model_result = cursor.fetchone()
if model_result:
model_id = model_result[0]
else:
print(f"Advertencia: Modelo {model_name} no encontrado para la marca ACURA")
continue
cursor.execute("SELECT id FROM years WHERE year = ?", (year,))
year_result = cursor.fetchone()
if year_result:
year_id = year_result[0]
else:
print(f"Advertencia: Año {year} no encontrado")
continue
cursor.execute("SELECT id FROM engines WHERE name = ?", (engine_name,))
engine_result = cursor.fetchone()
if engine_result:
engine_id = engine_result[0]
else:
print(f"Advertencia: Motor {engine_name} no encontrado")
continue
# Insertar la combinación modelo-año-motor
cursor.execute(
"""INSERT OR REPLACE INTO model_year_engine
(model_id, year_id, engine_id) VALUES (?, ?, ?)""",
(model_id, year_id, engine_id)
)
conn.commit()
print(f"Se agregaron {len(acura_data)} combinaciones modelo-año-motor para ACURA")
print("Datos de ACURA agregados exitosamente a la base de datos!")
# Mostrar algunos resultados
print("\nAlgunos vehículos ACURA agregados:")
cursor.execute("""
SELECT b.name, m.name, y.year, e.name
FROM model_year_engine mye
JOIN models m ON mye.model_id = m.id
JOIN brands b ON m.brand_id = b.id
JOIN years y ON mye.year_id = y.id
JOIN engines e ON mye.engine_id = e.id
WHERE b.name = 'ACURA'
ORDER BY m.name, y.year DESC
LIMIT 15
""")
results = cursor.fetchall()
for brand, model, year, engine in results:
print(f" {year} {brand} {model} - {engine}")
except Exception as e:
print(f"Error al agregar datos de ACURA: {e}")
conn.rollback()
finally:
conn.close()
if __name__ == "__main__":
add_acura_data()

View File

@@ -0,0 +1,188 @@
#!/usr/bin/env python3
"""
Script para agregar datos históricos adicionales de Acura a la base de datos de vehículos
"""
import sqlite3
import os
def add_acura_historical_data():
# Verificar que la base de datos exista
db_path = "vehicle_database/vehicle_database.db"
if not os.path.exists(db_path):
print(f"Error: Base de datos no encontrada en {db_path}")
return
conn = sqlite3.connect(db_path)
cursor = conn.cursor()
print("Agregando datos históricos adicionales de Acura a la base de datos...")
try:
# Asegurar que la marca Acura exista
cursor.execute("INSERT OR IGNORE INTO brands (name) VALUES (?)", ("ACURA",))
cursor.execute("SELECT id FROM brands WHERE name = ?", ("ACURA",))
brand_id = cursor.fetchone()[0]
print(f"Marca ACURA tiene ID: {brand_id}")
# Insertar modelos adicionales de Acura
additional_models = ['CL', 'INTEGRA', 'NSX', 'RL', 'SLX', 'TL', 'LEGEND', 'VIGOR']
for model in additional_models:
cursor.execute(
"INSERT OR IGNORE INTO models (brand_id, name) VALUES (?, ?)",
(brand_id, model)
)
print(f"Agregados {len(additional_models)} modelos adicionales de Acura")
# Datos históricos de años y motores para cada modelo
acura_historical_data = [
# 1997
('CL', 1997, '2.2L L4'),
('CL', 1997, '3.0L V6'),
('INTEGRA', 1997, '1.8L L4'),
('NSX', 1997, '3.0L V6'),
('NSX', 1997, '3.2L V6'),
('RL', 1997, '3.5L V6'),
('SLX', 1997, '3.2L V6'),
('TL', 1997, '2.5L L5'),
('TL', 1997, '3.2L V6'),
# 1996
('INTEGRA', 1996, '1.8L L4'),
('NSX', 1996, '3.0L V6'),
('RL', 1996, '3.5L V6'),
('SLX', 1996, '3.2L V6'),
('TL', 1996, '2.5L L5'),
('TL', 1996, '3.2L V6'),
# 1995
('INTEGRA', 1995, '1.8L L4'),
('LEGEND', 1995, '3.2L V6'),
('NSX', 1995, '3.0L V6'),
('TL', 1995, '2.5L L5'),
# 1994
('INTEGRA', 1994, '1.8L L4'),
('LEGEND', 1994, '3.2L V6'),
('NSX', 1994, '3.0L V6'),
('VIGOR', 1994, '2.5L L5'),
# 1993
('INTEGRA', 1993, '1.7L L4'),
('INTEGRA', 1993, '1.8L L4'),
('LEGEND', 1993, '3.2L V6'),
('NSX', 1993, '3.0L V6'),
('VIGOR', 1993, '2.5L L5'),
# 1992
('INTEGRA', 1992, '1.7L L4'),
('INTEGRA', 1992, '1.8L L4'),
('LEGEND', 1992, '3.2L V6'),
('NSX', 1992, '3.0L V6'),
('VIGOR', 1992, '2.5L L5'),
# 1991
('INTEGRA', 1991, '1.8L L4'),
('LEGEND', 1991, '3.2L V6'),
('NSX', 1991, '3.0L V6'),
# 1990
('INTEGRA', 1990, '1.8L L4'),
('LEGEND', 1990, '2.7L V6'),
# 1989
('INTEGRA', 1989, '1.6L L4'),
('LEGEND', 1989, '2.7L V6'),
# 1988
('INTEGRA', 1988, '1.6L L4'),
('LEGEND', 1988, '2.7L V6'),
# 1987
('INTEGRA', 1987, '1.6L L4'),
('LEGEND', 1987, '2.5L V6'),
('LEGEND', 1987, '2.7L V6'),
# 1986
('INTEGRA', 1986, '1.6L L4'),
('LEGEND', 1986, '2.5L V6'),
('LEGEND', 1986, '2.7L V6')
]
# Insertar años históricos
years = list(set([data[1] for data in acura_historical_data])) # Obtener años únicos
for year in years:
cursor.execute("INSERT OR IGNORE INTO years (year) VALUES (?)", (year,))
print(f"Agregados {len(years)} años históricos adicionales")
# Insertar motores históricos
engines = list(set([data[2] for data in acura_historical_data])) # Obtener motores únicos
for engine in engines:
cursor.execute("INSERT OR IGNORE INTO engines (name) VALUES (?)", (engine,))
print(f"Agregados {len(engines)} motores históricos adicionales")
# Crear combinaciones modelo-año-motor históricas
for model_name, year, engine_name in acura_historical_data:
# Obtener IDs
cursor.execute("SELECT id FROM models WHERE brand_id = ? AND name = ?", (brand_id, model_name))
model_result = cursor.fetchone()
if model_result:
model_id = model_result[0]
else:
print(f"Advertencia: Modelo {model_name} no encontrado para la marca ACURA")
continue
cursor.execute("SELECT id FROM years WHERE year = ?", (year,))
year_result = cursor.fetchone()
if year_result:
year_id = year_result[0]
else:
print(f"Advertencia: Año {year} no encontrado")
continue
cursor.execute("SELECT id FROM engines WHERE name = ?", (engine_name,))
engine_result = cursor.fetchone()
if engine_result:
engine_id = engine_result[0]
else:
print(f"Advertencia: Motor {engine_name} no encontrado")
continue
# Insertar la combinación modelo-año-motor
cursor.execute(
"""INSERT OR REPLACE INTO model_year_engine
(model_id, year_id, engine_id) VALUES (?, ?, ?)""",
(model_id, year_id, engine_id)
)
conn.commit()
print(f"Se agregaron {len(acura_historical_data)} combinaciones modelo-año-motor históricas adicionales para ACURA")
print("Datos históricos adicionales de ACURA agregados exitosamente a la base de datos!")
# Mostrar algunos resultados
print("\nAlgunos vehículos ACURA históricos adicionales agregados:")
cursor.execute("""
SELECT b.name, m.name, y.year, e.name
FROM model_year_engine mye
JOIN models m ON mye.model_id = m.id
JOIN brands b ON m.brand_id = b.id
JOIN years y ON mye.year_id = y.id
JOIN engines e ON mye.engine_id = e.id
WHERE b.name = 'ACURA' AND y.year BETWEEN 1986 AND 1997
ORDER BY y.year DESC, m.name
LIMIT 15
""")
results = cursor.fetchall()
for brand, model, year, engine in results:
print(f" {year} {brand} {model} - {engine}")
except Exception as e:
print(f"Error al agregar datos históricos adicionales de ACURA: {e}")
conn.rollback()
finally:
conn.close()
if __name__ == "__main__":
add_acura_historical_data()

308
add_alfa_romeo_data.py Normal file
View File

@@ -0,0 +1,308 @@
#!/usr/bin/env python3
"""
Script para agregar datos de Alfa Romeo a la base de datos de vehículos
"""
import sqlite3
import os
def add_alfa_romeo_data():
# Verificar que la base de datos exista
db_path = "vehicle_database/vehicle_database.db"
if not os.path.exists(db_path):
print(f"Error: Base de datos no encontrada en {db_path}")
return
conn = sqlite3.connect(db_path)
cursor = conn.cursor()
print("Agregando datos de Alfa Romeo a la base de datos...")
try:
# Insertar la marca Alfa Romeo
cursor.execute("INSERT OR IGNORE INTO brands (name) VALUES (?)", ("ALFA ROMEO",))
cursor.execute("SELECT id FROM brands WHERE name = ?", ("ALFA ROMEO",))
brand_id = cursor.fetchone()[0]
print(f"Marca ALFA ROMEO tiene ID: {brand_id}")
# Insertar modelos de Alfa Romeo (incluyendo GIULIA que aparece en los datos)
models = [
'4C', 'GIULIETTA', 'MITO', '159', '8C', 'BRERA', 'GT', 'SPIDER',
'147', '156', '166', 'SPORTWAGON', '164', 'MILANO', 'GTV-6',
'STELVIO', 'TONALE', 'GIULIA' # Agregué GIULIA que aparece en los datos
]
for model in models:
cursor.execute(
"INSERT OR IGNORE INTO models (brand_id, name) VALUES (?, ?)",
(brand_id, model)
)
print(f"Agregados {len(models)} modelos de Alfa Romeo")
# Datos de años y motores para cada modelo
alfa_data = [
# 2025
('GIULIA', 2025, '2.0L L4 Turbocharged'),
('STELVIO', 2025, '2.0L L4 Turbocharged'),
('TONALE', 2025, '1.3L L4 ELECTRIC/GAS Turbocharged SOHC'),
('TONALE', 2025, '2.0L L4 Turbocharged'),
# 2024
('GIULIA', 2024, '2.0L L4 Turbocharged'),
('STELVIO', 2024, '2.0L L4 Turbocharged'),
('TONALE', 2024, '1.3L L4 ELECTRIC/GAS Turbocharged'),
('TONALE', 2024, '2.0L L4 Turbocharged'),
# 2023
('GIULIA', 2023, '2.0L L4 Turbocharged'),
('STELVIO', 2023, '2.0L L4 Turbocharged'),
('STELVIO', 2023, '2.9L V6 Turbocharged'),
# 2022
('GIULIA', 2022, '2.0L L4 Turbocharged'),
('STELVIO', 2022, '2.0L L4 Turbocharged'),
('STELVIO', 2022, '2.9L V6 Turbocharged'),
# 2021
('GIULIA', 2021, '2.0L L4 Turbocharged'),
('GIULIA', 2021, '2.9L V6 Turbocharged'),
('GIULIETTA', 2021, '1.7L L4 Turbocharged'),
('STELVIO', 2021, '2.0L L4 Turbocharged'),
('STELVIO', 2021, '2.9L V6 Turbocharged'),
# 2020
('4C', 2020, '1.7L L4 Turbocharged'),
('GIULIA', 2020, '2.0L L4 Turbocharged'),
('GIULIA', 2020, '2.9L V6 Turbocharged'),
('GIULIETTA', 2020, '1.7L L4 Turbocharged'),
('STELVIO', 2020, '2.0L L4 Turbocharged'),
('STELVIO', 2020, '2.9L V6 Turbocharged'),
# 2019
('4C', 2019, '1.7L L4 Turbocharged'),
('GIULIA', 2019, '2.0L L4 Turbocharged'),
('GIULIA', 2019, '2.9L V6 Turbocharged'),
('GIULIETTA', 2019, '1.7L L4 Turbocharged'),
('MITO', 2019, '1.4L L4 Turbocharged'),
('STELVIO', 2019, '2.0L L4 Turbocharged'),
('STELVIO', 2019, '2.9L V6 Turbocharged'),
# 2018
('4C', 2018, '1.7L L4 Turbocharged'),
('GIULIA', 2018, '2.0L L4 Turbocharged'),
('GIULIA', 2018, '2.9L V6 Turbocharged'),
('GIULIETTA', 2018, '1.7L L4 Turbocharged'),
('MITO', 2018, '1.4L L4 Turbocharged'),
('STELVIO', 2018, '2.0L L4 Turbocharged'),
('STELVIO', 2018, '2.9L V6 Turbocharged'),
# 2017
('4C', 2017, '1.7L L4 Turbocharged'),
('GIULIA', 2017, '2.0L L4 Turbocharged'),
('GIULIA', 2017, '2.9L V6 Turbocharged'),
('GIULIETTA', 2017, '1.7L L4 Turbocharged'),
('MITO', 2017, '1.4L L4 Turbocharged'),
('STELVIO', 2017, '2.0L L4 Turbocharged'),
('STELVIO', 2017, '2.9L V6 Turbocharged'),
# 2016
('4C', 2016, '1.7L L4 Turbocharged'),
('GIULIA', 2016, '2.0L L4 Turbocharged'),
('GIULIA', 2016, '2.9L V6 Turbocharged'),
('GIULIETTA', 2016, '1.7L L4 Turbocharged'),
('MITO', 2016, '1.4L L4 Turbocharged'),
('STELVIO', 2016, '2.0L L4 Turbocharged'),
('STELVIO', 2016, '2.9L V6 Turbocharged'),
# 2015
('4C', 2015, '1.7L L4 Turbocharged'),
('GIULIETTA', 2015, '1.7L L4 Turbocharged'),
('GIULIETTA', 2015, '1.8L L4 Turbocharged'),
('MITO', 2015, '1.4L L4 Turbocharged'),
# 2014
('GIULIETTA', 2014, '1.7L L4 Turbocharged'),
# 2013
('GIULIETTA', 2013, '1.7L L4 Turbocharged'),
('MITO', 2013, '1.4L L4 Turbocharged'),
# 2012
('159', 2012, '2.2L L4'),
('159', 2012, '3.2L V6'),
('GIULIETTA', 2012, '1.8L L4 Turbocharged'),
('MITO', 2012, '1.4L L4 Turbocharged'),
# 2008
('159', 2008, '2.2L L4'),
('8C', 2008, '4.7L V8'),
('BRERA', 2008, '3.2L V6'),
('GT', 2008, '2.0L L4'),
('SPIDER', 2008, '3.2L V6'),
# 2007
('147', 2007, '2.0L L4'),
('159', 2007, '2.2L L4'),
('159', 2007, '3.2L V6'),
('BRERA', 2007, '3.2L V6'),
('GT', 2007, '2.0L L4'),
('SPIDER', 2007, '3.2L V6'),
# 2005
('147', 2005, '2.0L L4'),
# 2004
('147', 2004, '2.0L L4'),
# 2003
('147', 2003, '2.0L L4'),
('166', 2003, '3.0L V6'),
('GTV', 2003, '3.0L V6'), # Nota: En los datos originales dice 'GTV', pero en modelos dice 'GTV-6'
('SPIDER', 2003, '3.0L V6'),
# 2002
('147', 2002, '2.0L L4'),
('156', 2002, '2.0L L4'),
('166', 2002, '3.0L V6'),
('SPORTWAGON', 2002, '2.0L L4'),
# 1995
('164', 1995, '3.0L V6'),
# 1994
('164', 1994, '3.0L V6'),
('SPIDER', 1994, '2.0L L4'),
# 1993
('164', 1993, '3.0L V6'),
('SPIDER', 1993, '2.0L L4'),
# 1992
('164', 1992, '3.0L V6'),
('SPIDER', 1992, '2.0L L4'),
# 1991
('164', 1991, '2.0L L4'),
# 1990
('SPIDER', 1990, '2.0L L4'),
# 1989
('MILANO', 1989, '2.5L V6'),
('MILANO', 1989, '3.0L V6'),
('SPIDER', 1989, '2.0L L4'),
# 1988
('MILANO', 1988, '2.5L V6'),
('MILANO', 1988, '3.0L V6'),
('SPIDER', 1988, '2.0L L4'),
# 1987
('MILANO', 1987, '2.5L V6'),
('MILANO', 1987, '3.0L V6'),
('SPIDER', 1987, '2.0L L4'),
# 1986
('GTV-6', 1986, '2.5L V6'),
('SPIDER', 1986, '2.0L L4'),
# 1985
('GTV-6', 1985, '2.5L V6'),
('SPIDER', 1985, '2.0L L4'),
# 1984
('GTV-6', 1984, '2.5L V6'),
('SPIDER', 1984, '2.0L L4'),
# 1983
('GTV-6', 1983, '2.5L V6'),
('SPIDER', 1983, '2.0L L4'),
# 1982
('GTV-6', 1982, '2.5L V6'),
('SPIDER', 1982, '2.0L L4'),
# 1981
('GTV-6', 1981, '2.5L V6'),
('SPIDER', 1981, '2.0L L4'),
# 1980
('SPIDER', 1980, '2.0L L4')
]
# Insertar años
years = list(set([data[1] for data in alfa_data])) # Obtener años únicos
for year in years:
cursor.execute("INSERT OR IGNORE INTO years (year) VALUES (?)", (year,))
print(f"Agregados {len(years)} años")
# Insertar motores
engines = list(set([data[2] for data in alfa_data])) # Obtener motores únicos
for engine in engines:
cursor.execute("INSERT OR IGNORE INTO engines (name) VALUES (?)", (engine,))
print(f"Agregados {len(engines)} motores")
# Crear combinaciones modelo-año-motor
for model_name, year, engine_name in alfa_data:
# Obtener IDs
cursor.execute("SELECT id FROM models WHERE brand_id = ? AND name = ?", (brand_id, model_name))
model_result = cursor.fetchone()
if model_result:
model_id = model_result[0]
else:
print(f"Advertencia: Modelo {model_name} no encontrado para la marca ALFA ROMEO")
continue
cursor.execute("SELECT id FROM years WHERE year = ?", (year,))
year_result = cursor.fetchone()
if year_result:
year_id = year_result[0]
else:
print(f"Advertencia: Año {year} no encontrado")
continue
cursor.execute("SELECT id FROM engines WHERE name = ?", (engine_name,))
engine_result = cursor.fetchone()
if engine_result:
engine_id = engine_result[0]
else:
print(f"Advertencia: Motor {engine_name} no encontrado")
continue
# Insertar la combinación modelo-año-motor
cursor.execute(
"""INSERT OR REPLACE INTO model_year_engine
(model_id, year_id, engine_id) VALUES (?, ?, ?)""",
(model_id, year_id, engine_id)
)
conn.commit()
print(f"Se agregaron {len(alfa_data)} combinaciones modelo-año-motor para ALFA ROMEO")
print("Datos de ALFA ROMEO agregados exitosamente a la base de datos!")
# Mostrar algunos resultados
print("\nAlgunos vehículos ALFA ROMEO agregados:")
cursor.execute("""
SELECT b.name, m.name, y.year, e.name
FROM model_year_engine mye
JOIN models m ON mye.model_id = m.id
JOIN brands b ON m.brand_id = b.id
JOIN years y ON mye.year_id = y.id
JOIN engines e ON mye.engine_id = e.id
WHERE b.name = 'ALFA ROMEO'
ORDER BY y.year DESC, m.name
LIMIT 15
""")
results = cursor.fetchall()
for brand, model, year, engine in results:
print(f" {year} {brand} {model} - {engine}")
except Exception as e:
print(f"Error al agregar datos de ALFA ROMEO: {e}")
conn.rollback()
finally:
conn.close()
if __name__ == "__main__":
add_alfa_romeo_data()

279
add_american_motors_data.py Normal file
View File

@@ -0,0 +1,279 @@
"""
Script to add American Motors Corporation (AMC) vehicle data to the database.
This includes inserting the brand, models, and year/motor combinations.
"""
import sqlite3
from typing import List, Tuple
def connect_db(db_path: str = "vehicle_database/vehicle_database.db") -> sqlite3.Connection:
"""Connect to the vehicle database."""
conn = sqlite3.connect(db_path)
conn.execute("PRAGMA foreign_keys = ON") # Enable foreign key constraints
return conn
def insert_brand(conn: sqlite3.Connection, brand_name: str) -> int:
"""Insert a brand if it doesn't exist and return its ID."""
cursor = conn.cursor()
# Check if brand already exists
cursor.execute("SELECT id FROM brands WHERE name = ?", (brand_name,))
result = cursor.fetchone()
if result:
return result[0] # Return existing ID
# Insert new brand
cursor.execute("INSERT INTO brands (name) VALUES (?)", (brand_name,))
conn.commit()
return cursor.lastrowid
def insert_models(conn: sqlite3.Connection, brand_id: int, models: List[str]) -> None:
"""Insert models if they don't exist."""
cursor = conn.cursor()
for model_name in models:
# Check if model already exists for this brand
cursor.execute(
"SELECT id FROM models WHERE brand_id = ? AND name = ?",
(brand_id, model_name)
)
result = cursor.fetchone()
if not result:
# Insert new model
cursor.execute(
"INSERT INTO models (brand_id, name) VALUES (?, ?)",
(brand_id, model_name)
)
conn.commit()
def get_or_insert_engine(conn: sqlite3.Connection, engine_name: str) -> int:
"""Get engine ID or insert if it doesn't exist."""
cursor = conn.cursor()
# Check if engine already exists
cursor.execute("SELECT id FROM engines WHERE name = ?", (engine_name,))
result = cursor.fetchone()
if result:
return result[0] # Return existing ID
# Insert new engine
cursor.execute("INSERT INTO engines (name) VALUES (?)", (engine_name,))
conn.commit()
return cursor.lastrowid
def get_or_insert_year(conn: sqlite3.Connection, year: int) -> int:
"""Get year ID or insert if it doesn't exist."""
cursor = conn.cursor()
# Check if year already exists
cursor.execute("SELECT id FROM years WHERE year = ?", (year,))
result = cursor.fetchone()
if result:
return result[0] # Return existing ID
# Insert new year
cursor.execute("INSERT INTO years (year) VALUES (?)", (year,))
conn.commit()
return cursor.lastrowid
def insert_versions(conn: sqlite3.Connection, versions: List[Tuple]) -> None:
"""Insert vehicle versions if they don't exist."""
cursor = conn.cursor()
for model_name, year, engine in versions:
# Get model ID
cursor.execute(
"SELECT m.id FROM models m JOIN brands ma ON m.brand_id = ma.id "
"WHERE ma.name = 'AMERICAN MOTORS' AND m.name = ?",
(model_name,)
)
model_result = cursor.fetchone()
if model_result:
model_id = model_result[0]
# Get or insert year
year_id = get_or_insert_year(conn, year)
# Get or insert engine
engine_id = get_or_insert_engine(conn, engine)
# Check if version relationship already exists
cursor.execute(
"SELECT id FROM model_year_engine WHERE model_id = ? AND year_id = ? AND engine_id = ?",
(model_id, year_id, engine_id)
)
version_result = cursor.fetchone()
if not version_result:
# Insert new version relationship
cursor.execute(
"INSERT INTO model_year_engine (model_id, year_id, engine_id) VALUES (?, ?, ?)",
(model_id, year_id, engine_id)
)
conn.commit()
def main():
"""Main function to add American Motors Corporation data."""
print("Adding American Motors Corporation data...")
# Connect to database
conn = connect_db()
# Insert brand
brand_id = insert_brand(conn, "AMERICAN MOTORS")
print(f"Brand 'AMERICAN MOTORS' inserted with ID: {brand_id}")
# Define models
models = [
'GREMLIN',
'HORNET',
'MATADOR',
'PACER',
'AMX',
'CONCORD',
'EAGLE',
'SPIRIT'
]
# Insert models
insert_models(conn, brand_id, models)
print(f"Models inserted for AMERICAN MOTORS: {', '.join(models)}")
# Define versions (model, year, engine)
versions = [
# 1988
('EAGLE', 1988, '4.2L 258cid L6'),
# 1987
('EAGLE', 1987, '4.2L 258cid L6'),
# 1986
('EAGLE', 1986, '4.2L 258cid L6'),
# 1985
('EAGLE', 1985, '4.2L 258cid L6'),
# 1984
('EAGLE', 1984, '2.5L 150cid L4'),
('EAGLE', 1984, '4.2L 258cid L6'),
# 1983
('CONCORD', 1983, '2.5L 151cid L4'),
('CONCORD', 1983, '4.2L 258cid L6'),
('EAGLE', 1983, '2.5L 151cid L4'),
('EAGLE', 1983, '4.2L 258cid L6'),
('SPIRIT', 1983, '2.5L 151cid L4'),
('SPIRIT', 1983, '4.2L 258cid L6'),
# 1982
('CONCORD', 1982, '2.5L 151cid L4'),
('CONCORD', 1982, '4.2L 258cid L6'),
('EAGLE', 1982, '2.5L 151cid L4'),
('EAGLE', 1982, '4.2L 258cid L6'),
('SPIRIT', 1982, '2.5L 151cid L4'),
('SPIRIT', 1982, '4.2L 258cid L6'),
# 1981
('CONCORD', 1981, '2.5L 151cid L4'),
('CONCORD', 1981, '4.2L 258cid L6'),
('EAGLE', 1981, '2.5L 151cid L4'),
('EAGLE', 1981, '4.2L 258cid L6'),
('SPIRIT', 1981, '2.5L 151cid L4'),
('SPIRIT', 1981, '4.2L 258cid L6'),
# 1980
('AMX', 1980, '4.2L 258cid L6'),
('CONCORD', 1980, '2.5L 151cid L4'),
('CONCORD', 1980, '4.2L 258cid L6'),
('EAGLE', 1980, '2.5L 151cid L4'),
('EAGLE', 1980, '4.2L 258cid L6'),
('PACER', 1980, '4.2L 258cid L6'),
('SPIRIT', 1980, '2.5L 151cid L4'),
('SPIRIT', 1980, '4.2L 258cid L6'),
# 1979
('AMX', 1979, '4.2L 258cid L6'),
('CONCORD', 1979, '2.0L 121cid L4'),
('CONCORD', 1979, '3.8L 232cid L6'),
('CONCORD', 1979, '4.2L 258cid L6'),
('EAGLE', 1979, '2.5L 151cid L4'),
('EAGLE', 1979, '4.2L 258cid L6'),
('PACER', 1979, '4.2L 258cid L6'),
('SPIRIT', 1979, '2.5L 151cid L4'),
('SPIRIT', 1979, '4.2L 258cid L6'),
# 1978
('AMX', 1978, '4.2L 258cid L6'),
('CONCORD', 1978, '2.0L 121cid L4'),
('CONCORD', 1978, '3.8L 232cid L6'),
('CONCORD', 1978, '4.2L 258cid L6'),
('EAGLE', 1978, '2.5L 151cid L4'),
('EAGLE', 1978, '4.2L 258cid L6'),
('PACER', 1978, '4.2L 258cid L6'),
('SPIRIT', 1978, '2.5L 151cid L4'),
('SPIRIT', 1978, '4.2L 258cid L6'),
# 1977
('GREMLIN', 1977, '2.0L 121cid L4'),
('GREMLIN', 1977, '3.8L 232cid L6'),
('GREMLIN', 1977, '4.2L 258cid L6'),
('HORNET', 1977, '3.8L 232cid L6'),
('HORNET', 1977, '4.2L 258cid L6'),
('HORNET', 1977, '5.0L 304cid V8'),
('MATADOR', 1977, '4.2L 258cid L6'),
('MATADOR', 1977, '5.0L 304cid V8'),
('MATADOR', 1977, '5.9L 360cid V8'),
('PACER', 1977, '3.8L 232cid L6'),
('PACER', 1977, '4.2L 258cid L6'),
# 1976
('GREMLIN', 1976, '3.8L 232cid L6'),
('GREMLIN', 1976, '4.2L 258cid L6'),
('GREMLIN', 1976, '5.0L 304cid V8'),
('HORNET', 1976, '3.8L 232cid L6'),
('HORNET', 1976, '4.2L 258cid L6'),
('HORNET', 1976, '5.0L 304cid V8'),
('MATADOR', 1976, '4.2L 258cid L6'),
('MATADOR', 1976, '5.0L 304cid V8'),
('MATADOR', 1976, '5.9L 360cid V8'),
('PACER', 1976, '3.8L 232cid L6'),
('PACER', 1976, '4.2L 258cid L6'),
# 1975
('GREMLIN', 1975, '3.8L 232cid L6'),
('GREMLIN', 1975, '4.2L 258cid L6'),
('GREMLIN', 1975, '5.0L 304cid V8'),
('HORNET', 1975, '3.8L 232cid L6'),
('HORNET', 1975, '4.2L 258cid L6'),
('HORNET', 1975, '5.0L 304cid V8'),
('MATADOR', 1975, '4.2L 258cid L6'),
('MATADOR', 1975, '5.0L 304cid V8'),
('MATADOR', 1975, '5.9L 360cid V8'),
('PACER', 1975, '3.8L 232cid L6'),
('PACER', 1975, '4.2L 258cid L6')
]
# Insert versions
insert_versions(conn, versions)
print(f"Inserted {len(versions)} versions for AMERICAN MOTORS vehicles")
# Close connection
conn.close()
print("American Motors Corporation data added successfully!")
if __name__ == "__main__":
main()

445
add_aston_martin_data.py Normal file
View File

@@ -0,0 +1,445 @@
"""
Script to add Aston Martin vehicle data to the database.
This includes inserting the brand, models, and year/motor combinations.
"""
import sqlite3
from typing import List, Tuple
def connect_db(db_path: str = "vehicle_database/vehicle_database.db") -> sqlite3.Connection:
"""Connect to the vehicle database."""
conn = sqlite3.connect(db_path)
conn.execute("PRAGMA foreign_keys = ON") # Enable foreign key constraints
return conn
def get_or_insert_brand(conn: sqlite3.Connection, brand_name: str) -> int:
"""Get brand ID or insert if it doesn't exist."""
cursor = conn.cursor()
# Check if brand already exists
cursor.execute("SELECT id FROM brands WHERE name = ?", (brand_name,))
result = cursor.fetchone()
if result:
return result[0] # Return existing ID
# Insert new brand
cursor.execute("INSERT INTO brands (name) VALUES (?)", (brand_name,))
conn.commit()
return cursor.lastrowid
def get_or_insert_model(conn: sqlite3.Connection, brand_id: int, model_name: str) -> int:
"""Get model ID or insert if it doesn't exist."""
cursor = conn.cursor()
# Check if model already exists for this brand
cursor.execute(
"SELECT id FROM models WHERE brand_id = ? AND name = ?",
(brand_id, model_name)
)
result = cursor.fetchone()
if result:
return result[0] # Return existing ID
# Insert new model
cursor.execute(
"INSERT INTO models (brand_id, name) VALUES (?, ?)",
(brand_id, model_name)
)
conn.commit()
return cursor.lastrowid
def get_or_insert_engine(conn: sqlite3.Connection, engine_name: str) -> int:
"""Get engine ID or insert if it doesn't exist."""
cursor = conn.cursor()
# Check if engine already exists
cursor.execute("SELECT id FROM engines WHERE name = ?", (engine_name,))
result = cursor.fetchone()
if result:
return result[0] # Return existing ID
# Insert new engine
cursor.execute("INSERT INTO engines (name) VALUES (?)", (engine_name,))
conn.commit()
return cursor.lastrowid
def get_or_insert_year(conn: sqlite3.Connection, year: int) -> int:
"""Get year ID or insert if it doesn't exist."""
cursor = conn.cursor()
# Check if year already exists
cursor.execute("SELECT id FROM years WHERE year = ?", (year,))
result = cursor.fetchone()
if result:
return result[0] # Return existing ID
# Insert new year
cursor.execute("INSERT INTO years (year) VALUES (?)", (year,))
conn.commit()
return cursor.lastrowid
def insert_version_relationship(conn: sqlite3.Connection, model_id: int, year_id: int, engine_id: int) -> None:
"""Insert a version relationship if it doesn't exist."""
cursor = conn.cursor()
# Check if version relationship already exists
cursor.execute(
"SELECT id FROM model_year_engine WHERE model_id = ? AND year_id = ? AND engine_id = ?",
(model_id, year_id, engine_id)
)
result = cursor.fetchone()
if not result:
# Insert new version relationship
cursor.execute(
"INSERT INTO model_year_engine (model_id, year_id, engine_id) VALUES (?, ?, ?)",
(model_id, year_id, engine_id)
)
conn.commit()
def main():
"""Main function to add Aston Martin data."""
print("Adding Aston Martin data...")
# Connect to database
conn = connect_db()
# Insert brand
brand_id = get_or_insert_brand(conn, "ASTON MARTIN")
print(f"Brand 'ASTON MARTIN' inserted with ID: {brand_id}")
# Define models
models = [
'LAGONDA',
'ZAGATO',
'DB7',
'VANTAGE',
'VIRAGE',
'VANQUISH',
'DB9',
'DBS',
'RAPIDE',
'ONE-77',
'V12 VANTAGE',
'DB11',
'DBX',
'DB12',
'VALHALLA',
'VALOUR',
'ARRA'
]
# Insert models
for model_name in models:
model_id = get_or_insert_model(conn, brand_id, model_name)
print(f"Models inserted for ASTON MARTIN: {', '.join(models)}")
# Define versions (model, year, engine)
versions = [
# 2025
('DB12', 2025, '4.0L V8 Turbocharged'),
('DBX707', 2025, '4.0L V8 Turbocharged'),
('VALHALLA', 2025, '4.0L V8 ELECTRIC/GAS Turbocharged'),
('VANQUISH', 2025, '5.2L V12 Turbocharged'),
('VANTAGE', 2025, '4.0L V8 Turbocharged'),
('VANTAGE', 2025, '5.2L V12 Turbocharged'),
# 2024
('DB12', 2024, '4.0L V8 Turbocharged'),
('DBS', 2024, '5.2L V12 Turbocharged'),
('DBX', 2024, '4.0L V8 Turbocharged'),
('DBX707', 2024, '4.0L V8 Turbocharged'),
('VALOUR', 2024, '5.2L V12 Turbocharged'),
('VANTAGE', 2024, '4.0L V8 Turbocharged'),
('VANTAGE', 2024, '5.2L V12 Turbocharged'),
# 2023
('DB11', 2023, '4.0L V8 Turbocharged'),
('DBS', 2023, '5.2L V12 Turbocharged'),
('DBX', 2023, '4.0L V8 Turbocharged'),
('DBX707', 2023, '4.0L V8 Turbocharged'),
('VANTAGE', 2023, '4.0L V8 Turbocharged'),
('VANTAGE', 2023, '5.2L V12 Turbocharged'),
# 2022
('DB11', 2022, '4.0L V8 Turbocharged'),
('DBS', 2022, '5.2L V12 Turbocharged'),
('DBX', 2022, '4.0L V8 Turbocharged'),
('VANTAGE', 2022, '4.0L V8 Turbocharged'),
('VANTAGE', 2022, '5.2L V12 Turbocharged'),
# 2021
('DB11', 2021, '4.0L V8 Turbocharged'),
('DBS', 2021, '5.2L V12 Turbocharged'),
('DBX', 2021, '4.0L V8 Turbocharged'),
('VANTAGE', 2021, '4.0L V8 Turbocharged'),
('VANTAGE', 2021, '5.2L V12 Turbocharged'),
# 2020
('DB11', 2020, '4.0L V8 Turbocharged'),
('DBS', 2020, '5.2L V12 Turbocharged'),
('VANTAGE', 2020, '4.0L V8 Turbocharged'),
('VANTAGE', 2020, '5.2L V12 Turbocharged'),
# 2019
('DB11', 2019, '4.0L V8 Turbocharged'),
('DBS', 2019, '5.2L V12 Turbocharged'),
('RAPIDE', 2019, '4.0L V8 Turbocharged'),
('VANTAGE', 2019, '4.0L V8 Turbocharged'),
# 2018
('DB11', 2018, '4.0L V8 Turbocharged'),
('RAPIDE', 2018, '4.0L V8 Turbocharged'),
('VANTAGE', 2018, '4.0L V8 Turbocharged'),
# 2017
('DB11', 2017, '5.2L V12 Turbocharged'),
('RAPIDE', 2017, '6.0L V12'),
('V12 VANTAGE', 2017, '6.0L V12'),
('V8 VANTAGE', 2017, '4.7L V8'),
('VANQUISH', 2017, '6.0L V12'),
# 2016
('DB9', 2016, '6.0L V12'),
('RAPIDE', 2016, '6.0L V12'),
('V12 VANTAGE', 2016, '6.0L V12'),
('V8 VANTAGE', 2016, '4.7L V8'),
('VANQUISH', 2016, '6.0L V12'),
# 2015
('DB9', 2015, '6.0L V12'),
('RAPIDE', 2015, '6.0L V12'),
('V12 VANTAGE', 2015, '6.0L V12'),
('V8 VANTAGE', 2015, '4.7L V8'),
('VANQUISH', 2015, '6.0L V12'),
# 2014
('DB9', 2014, '6.0L V12'),
('RAPIDE', 2014, '6.0L V12'),
('V12 VANTAGE', 2014, '6.0L V12'),
('V8 VANTAGE', 2014, '4.7L V8'),
('VANQUISH', 2014, '6.0L V12'),
# 2013
('DB9', 2013, '6.0L V12'),
('DBS', 2013, '6.0L V12'),
('RAPIDE', 2013, '6.0L V12'),
('V12 VANTAGE', 2013, '6.0L V12'),
('V8 VANTAGE', 2013, '4.7L V8'),
('VANQUISH', 2013, '6.0L V12'),
# 2012
('DB9', 2012, '6.0L V12'),
('DBS', 2012, '6.0L V12'),
('RAPIDE', 2012, '6.0L V12'),
('V12 VANTAGE', 2012, '6.0L V12'),
('V8 VANTAGE', 2012, '4.7L V8'),
('VANQUISH', 2012, '6.0L V12'),
# 2011
('DB9', 2011, '6.0L V12'),
('DBS', 2011, '6.0L V12'),
('ONE-77', 2011, '7.3L V12'),
('RAPIDE', 2011, '6.0L V12'),
('V12 VANTAGE', 2011, '6.0L V12'),
('V8 VANTAGE', 2011, '4.7L V8'),
('VANQUISH', 2011, '6.0L V12'),
# 2010
('DB9', 2010, '6.0L V12'),
('DBS', 2010, '6.0L V12'),
('RAPIDE', 2010, '6.0L V12'),
('V12 VANTAGE', 2010, '6.0L V12'),
('V8 VANTAGE', 2010, '4.7L V8'),
('VANQUISH', 2010, '6.0L V12'),
# 2009
('DB9', 2009, '6.0L V12'),
('DBS', 2009, '6.0L V12'),
('V12 VANTAGE', 2009, '6.0L V12'),
('V8 VANTAGE', 2009, '4.3L V8'),
('V8 VANTAGE', 2009, '4.7L V8'),
('VANQUISH', 2009, '6.0L V12'),
# 2008
('DB9', 2008, '6.0L V12'),
('DBS', 2008, '6.0L V12'),
('V12 VANTAGE', 2008, '6.0L V12'),
('V8 VANTAGE', 2008, '4.3L V8'),
('V8 VANTAGE', 2008, '4.7L V8'),
('VANQUISH', 2008, '6.0L V12'),
# 2007
('DB9', 2007, '6.0L V12'),
('V12 VANTAGE', 2007, '6.0L V12'),
('V8 VANTAGE', 2007, '4.3L V8'),
('VANQUISH', 2007, '6.0L V12'),
# 2006
('DB9', 2006, '6.0L V12'),
('V12 VANTAGE', 2006, '6.0L V12'),
('V8 VANTAGE', 2006, '4.3L V8'),
('VANQUISH', 2006, '6.0L V12'),
# 2005
('DB7', 2005, '5.9L V12'),
('DB9', 2005, '6.0L V12'),
('VANQUISH', 2005, '6.0L V12'),
# 2004
('DB7', 2004, '5.9L V12'),
('DB9', 2004, '6.0L V12'),
('VANQUISH', 2004, '6.0L V12'),
# 2003
('DB7', 2003, '5.9L V12'),
('DB9', 2003, '6.0L V12'),
('VANQUISH', 2003, '6.0L V12'),
# 2002
('DB7', 2002, '5.9L V12'),
('VANQUISH', 2002, '6.0L V12'),
# 2001
('DB7', 2001, '5.9L V12'),
('VANQUISH', 2001, '6.0L V12'),
# 2000
('DB7', 2000, '3.2L L6 Supercharged'),
('DB7', 2000, '5.9L V12'),
('VANQUISH', 2000, '6.0L V12'),
# 1999
('DB7', 1999, '3.2L L6 Supercharged'),
('DB7', 1999, '5.9L V12'),
# 1998
('DB7', 1998, '3.2L L6 Supercharged'),
('DB7', 1998, '5.9L V12'),
# 1997
('DB7', 1997, '3.2L L6 Supercharged'),
('DB7', 1997, '5.9L V12'),
# 1995
('VIRAGE', 1995, '5.3L V8'),
# 1994
('VIRAGE', 1994, '5.3L V8'),
# 1993
('VIRAGE', 1993, '5.3L V8'),
# 1992
('VIRAGE', 1992, '5.3L V8'),
# 1991
('VIRAGE', 1991, '5.3L V8'),
# 1990
('VIRAGE', 1990, '5.3L V8'),
# 1989
('LAGONDA', 1989, '5.3L V8'),
('VIRAGE', 1989, '5.3L V8'),
# 1988
('LAGONDA', 1988, '5.3L V8'),
('VIRAGE', 1988, '5.3L V8'),
('ZAGATO', 1988, '5.3L V8'),
# 1987
('LAGONDA', 1987, '5.3L V8'),
('VIRAGE', 1987, '5.3L V8'),
('ZAGATO', 1987, '5.3L V8'),
# 1986
('LAGONDA', 1986, '5.3L V8'),
('VIRAGE', 1986, '5.3L V8'),
('ZAGATO', 1986, '5.3L V8'),
# 1985
('LAGONDA', 1985, '5.3L V8'),
('VIRAGE', 1985, '5.3L V8'),
('ZAGATO', 1985, '5.3L V8'),
# 1984
('LAGONDA', 1984, '5.3L V8'),
('VIRAGE', 1984, '5.3L V8'),
('ZAGATO', 1984, '5.3L V8'),
# 1983
('LAGONDA', 1983, '5.3L V8'),
('VIRAGE', 1983, '5.3L V8'),
('ZAGATO', 1983, '5.3L V8'),
# 1982
('LAGONDA', 1982, '5.3L V8'),
('VIRAGE', 1982, '5.3L V8'),
('ZAGATO', 1982, '5.3L V8'),
# 1981
('LAGONDA', 1981, '5.3L V8'),
('VIRAGE', 1981, '5.3L V8'),
('ZAGATO', 1981, '5.3L V8'),
# 1980
('LAGONDA', 1980, '5.3L V8'),
('VIRAGE', 1980, '5.3L V8'),
('ZAGATO', 1980, '5.3L V8'),
# 1979
('LAGONDA', 1979, '5.3L V8'),
('VIRAGE', 1979, '5.3L V8'),
('ZAGATO', 1979, '5.3L V8'),
# 1978
('LAGONDA', 1978, '5.3L V8'),
('VIRAGE', 1978, '5.3L V8'),
('ZAGATO', 1978, '5.3L V8'),
# 1977
('LAGONDA', 1977, '5.3L V8'),
('VIRAGE', 1977, '5.3L V8'),
('ZAGATO', 1977, '5.3L V8'),
# 1976
('LAGONDA', 1976, '5.3L V8'),
('VIRAGE', 1976, '5.3L V8'),
('ZAGATO', 1976, '5.3L V8'),
# 1975
('LAGONDA', 1975, '5.3L V8'),
('VIRAGE', 1975, '5.3L V8'),
('ZAGATO', 1975, '5.3L V8'),
# ARRA (modelo italiano)
('ARRA', 2024, 'ELECTRIC')
]
# Insert version relationships
for model_name, year, engine in versions:
model_id = get_or_insert_model(conn, brand_id, model_name)
year_id = get_or_insert_year(conn, year)
engine_id = get_or_insert_engine(conn, engine)
insert_version_relationship(conn, model_id, year_id, engine_id)
print(f"Inserted {len(versions)} version relationships for ASTON MARTIN vehicles")
# Close connection
conn.close()
print("Aston Martin data added successfully!")
if __name__ == "__main__":
main()

167
add_asuna_data.py Normal file
View File

@@ -0,0 +1,167 @@
"""
Script to add Asuna vehicle data to the database.
This includes inserting the brand, models, and year/motor combinations.
"""
import sqlite3
from typing import List, Tuple
def connect_db(db_path: str = "vehicle_database/vehicle_database.db") -> sqlite3.Connection:
"""Connect to the vehicle database."""
conn = sqlite3.connect(db_path)
conn.execute("PRAGMA foreign_keys = ON") # Enable foreign key constraints
return conn
def get_or_insert_brand(conn: sqlite3.Connection, brand_name: str) -> int:
"""Get brand ID or insert if it doesn't exist."""
cursor = conn.cursor()
# Check if brand already exists
cursor.execute("SELECT id FROM brands WHERE name = ?", (brand_name,))
result = cursor.fetchone()
if result:
return result[0] # Return existing ID
# Insert new brand
cursor.execute("INSERT INTO brands (name) VALUES (?)", (brand_name,))
conn.commit()
return cursor.lastrowid
def get_or_insert_model(conn: sqlite3.Connection, brand_id: int, model_name: str) -> int:
"""Get model ID or insert if it doesn't exist."""
cursor = conn.cursor()
# Check if model already exists for this brand
cursor.execute(
"SELECT id FROM models WHERE brand_id = ? AND name = ?",
(brand_id, model_name)
)
result = cursor.fetchone()
if result:
return result[0] # Return existing ID
# Insert new model
cursor.execute(
"INSERT INTO models (brand_id, name) VALUES (?, ?)",
(brand_id, model_name)
)
conn.commit()
return cursor.lastrowid
def get_or_insert_engine(conn: sqlite3.Connection, engine_name: str) -> int:
"""Get engine ID or insert if it doesn't exist."""
cursor = conn.cursor()
# Check if engine already exists
cursor.execute("SELECT id FROM engines WHERE name = ?", (engine_name,))
result = cursor.fetchone()
if result:
return result[0] # Return existing ID
# Insert new engine
cursor.execute("INSERT INTO engines (name) VALUES (?)", (engine_name,))
conn.commit()
return cursor.lastrowid
def get_or_insert_year(conn: sqlite3.Connection, year: int) -> int:
"""Get year ID or insert if it doesn't exist."""
cursor = conn.cursor()
# Check if year already exists
cursor.execute("SELECT id FROM years WHERE year = ?", (year,))
result = cursor.fetchone()
if result:
return result[0] # Return existing ID
# Insert new year
cursor.execute("INSERT INTO years (year) VALUES (?)", (year,))
conn.commit()
return cursor.lastrowid
def insert_version_relationship(conn: sqlite3.Connection, model_id: int, year_id: int, engine_id: int) -> None:
"""Insert a version relationship if it doesn't exist."""
cursor = conn.cursor()
# Check if version relationship already exists
cursor.execute(
"SELECT id FROM model_year_engine WHERE model_id = ? AND year_id = ? AND engine_id = ?",
(model_id, year_id, engine_id)
)
result = cursor.fetchone()
if not result:
# Insert new version relationship
cursor.execute(
"INSERT INTO model_year_engine (model_id, year_id, engine_id) VALUES (?, ?, ?)",
(model_id, year_id, engine_id)
)
conn.commit()
def main():
"""Main function to add Asuna data."""
print("Adding Asuna data...")
# Connect to database
conn = connect_db()
# Insert brand
brand_id = get_or_insert_brand(conn, "ASUNA")
print(f"Brand 'ASUNA' inserted with ID: {brand_id}")
# Define models
models = [
'SUNRUNNER',
'GT',
'SE',
'SUNFIRE'
]
# Insert models
for model_name in models:
model_id = get_or_insert_model(conn, brand_id, model_name)
print(f"Models inserted for ASUNA: {', '.join(models)}")
# Define versions (model, year, engine)
versions = [
# 1995
('SUNRUNNER', 1995, '1.6L L4'),
# 1994
('SUNRUNNER', 1994, '1.6L L4'),
# 1993
('GT', 1993, '1.6L L4'),
('SE', 1993, '1.6L L4'),
('SUNFIRE', 1993, '1.8L L4'),
('SUNRUNNER', 1993, '1.6L L4'),
# 1992
('SUNRUNNER', 1992, '1.6L L4')
]
# Insert version relationships
for model_name, year, engine in versions:
model_id = get_or_insert_model(conn, brand_id, model_name)
year_id = get_or_insert_year(conn, year)
engine_id = get_or_insert_engine(conn, engine)
insert_version_relationship(conn, model_id, year_id, engine_id)
print(f"Inserted {len(versions)} version relationships for ASUNA vehicles")
# Close connection
conn.close()
print("Asuna data added successfully!")
if __name__ == "__main__":
main()

372
add_audi_data.py Normal file
View File

@@ -0,0 +1,372 @@
"""
Script to add Audi vehicle data to the database.
This includes inserting the brand, models, and year/motor combinations.
"""
import sqlite3
from typing import List, Tuple
def connect_db(db_path: str = "vehicle_database/vehicle_database.db") -> sqlite3.Connection:
"""Connect to the vehicle database."""
conn = sqlite3.connect(db_path)
conn.execute("PRAGMA foreign_keys = ON") # Enable foreign key constraints
return conn
def get_or_insert_brand(conn: sqlite3.Connection, brand_name: str) -> int:
"""Get brand ID or insert if it doesn't exist."""
cursor = conn.cursor()
# Check if brand already exists
cursor.execute("SELECT id FROM brands WHERE name = ?", (brand_name,))
result = cursor.fetchone()
if result:
return result[0] # Return existing ID
# Insert new brand
cursor.execute("INSERT INTO brands (name) VALUES (?)", (brand_name,))
conn.commit()
return cursor.lastrowid
def get_or_insert_model(conn: sqlite3.Connection, brand_id: int, model_name: str) -> int:
"""Get model ID or insert if it doesn't exist."""
cursor = conn.cursor()
# Check if model already exists for this brand
cursor.execute(
"SELECT id FROM models WHERE brand_id = ? AND name = ?",
(brand_id, model_name)
)
result = cursor.fetchone()
if result:
return result[0] # Return existing ID
# Insert new model
cursor.execute(
"INSERT INTO models (brand_id, name) VALUES (?, ?)",
(brand_id, model_name)
)
conn.commit()
return cursor.lastrowid
def get_or_insert_engine(conn: sqlite3.Connection, engine_name: str) -> int:
"""Get engine ID or insert if it doesn't exist."""
cursor = conn.cursor()
# Check if engine already exists
cursor.execute("SELECT id FROM engines WHERE name = ?", (engine_name,))
result = cursor.fetchone()
if result:
return result[0] # Return existing ID
# Insert new engine
cursor.execute("INSERT INTO engines (name) VALUES (?)", (engine_name,))
conn.commit()
return cursor.lastrowid
def get_or_insert_year(conn: sqlite3.Connection, year: int) -> int:
"""Get year ID or insert if it doesn't exist."""
cursor = conn.cursor()
# Check if year already exists
cursor.execute("SELECT id FROM years WHERE year = ?", (year,))
result = cursor.fetchone()
if result:
return result[0] # Return existing ID
# Insert new year
cursor.execute("INSERT INTO years (year) VALUES (?)", (year,))
conn.commit()
return cursor.lastrowid
def insert_version_relationship(conn: sqlite3.Connection, model_id: int, year_id: int, engine_id: int) -> None:
"""Insert a version relationship if it doesn't exist."""
cursor = conn.cursor()
# Check if version relationship already exists
cursor.execute(
"SELECT id FROM model_year_engine WHERE model_id = ? AND year_id = ? AND engine_id = ?",
(model_id, year_id, engine_id)
)
result = cursor.fetchone()
if not result:
# Insert new version relationship
cursor.execute(
"INSERT INTO model_year_engine (model_id, year_id, engine_id) VALUES (?, ?, ?)",
(model_id, year_id, engine_id)
)
conn.commit()
def main():
"""Main function to add Audi data."""
print("Adding Audi data...")
# Connect to database
conn = connect_db()
# Insert brand
brand_id = get_or_insert_brand(conn, "AUDI")
print(f"Brand 'AUDI' inserted with ID: {brand_id}")
# Define models
models = [
'A1',
'A3',
'A4',
'A5',
'A6',
'A7',
'A8',
'Q2',
'Q3',
'Q4',
'Q5',
'Q6',
'Q7',
'Q8',
'R8',
'RS3',
'RS5',
'RS6',
'RS7',
'S3',
'S4',
'S5',
'S6',
'S7',
'S8',
'SQ5',
'SQ7',
'SQ8',
'TT',
'E-TRON',
'RS E-TRON GT',
'RS Q3',
'RS Q8'
]
# Insert models
for model_name in models:
model_id = get_or_insert_model(conn, brand_id, model_name)
print(f"Models inserted for AUDI: {', '.join(models)}")
# Define versions (model, year, engine)
versions = [
# 2026
('A3', 2026, '2.0L L4 Turbocharged'),
('A8', 2026, '3.0L V6 Turbocharged'),
('Q4', 2026, '2.0L L4 Turbocharged'),
('Q7', 2026, '2.0L L4 Turbocharged'),
('Q7', 2026, '3.0L V6 Turbocharged'),
('Q8', 2026, '3.0L V6 Turbocharged'),
('RS6', 2026, '4.0L V8 Turbocharged'),
('RS7', 2026, '4.0L V8 Turbocharged'),
('RS E-TRON GT', 2026, 'ELECTRIC'),
('RS Q8', 2026, '4.0L V8 Turbocharged'),
('S3', 2026, '2.0L L4 Turbocharged'),
('S4', 2026, '3.0L V6 Turbocharged'),
('S5', 2026, '3.0L V6 Turbocharged'),
('S6', 2026, '2.9L V6 Turbocharged'),
('S7', 2026, '2.9L V6 Turbocharged'),
('S8', 2026, '4.0L V8 Turbocharged'),
('SQ5', 2026, '3.0L V6 Turbocharged'),
('SQ7', 2026, '4.0L V8 Turbocharged'),
('SQ8', 2026, '4.0L V8 Turbocharged'),
('TT', 2026, '2.0L L4 Turbocharged'),
('TT', 2026, '2.5L L5 Turbocharged'),
# 2025
('A1', 2025, '1.5L L4 Turbocharged'),
('A3', 2025, '1.4L L4 Turbocharged'),
('A3', 2025, '2.0L L4 Turbocharged'),
('A4', 2025, '2.0L L4 Turbocharged'),
('A5', 2025, '2.0L L4 Turbocharged'),
('A6', 2025, '2.0L L4 Turbocharged'),
('A6', 2025, '3.0L V6 Turbocharged'),
('A7', 2025, '2.0L L4 Turbocharged'),
('A8', 2025, '3.0L V6 Turbocharged'),
('A8', 2025, '4.0L V8 Turbocharged'),
('Q2', 2025, '1.4L L4 Turbocharged'),
('Q3', 2025, '1.4L L4 Turbocharged'),
('Q3', 2025, '2.0L L4 Turbocharged'),
('Q4', 2025, '2.0L L4 Turbocharged'),
('Q5', 2025, '2.0L L4 Turbocharged'),
('Q5', 2025, '2.0L L4 ELECTRIC/GAS Turbocharged'),
('Q6', 2025, 'ELECTRIC'),
('Q7', 2025, '2.0L L4 Turbocharged'),
('Q7', 2025, '3.0L V6 Turbocharged'),
('Q8', 2025, '3.0L V6 Turbocharged'),
('R8', 2025, '5.2L V10'),
('RS3', 2025, '2.5L L5 Turbocharged'),
('RS5', 2025, '2.9L V6 Turbocharged'),
('RS6', 2025, '4.0L V8 Turbocharged'),
('RS7', 2025, '4.0L V8 Turbocharged'),
('RS E-TRON GT', 2025, 'ELECTRIC'),
('RS Q3', 2025, '2.5L L5 Turbocharged'),
('RS Q8', 2025, '4.0L V8 Turbocharged'),
('S3', 2025, '2.0L L4 Turbocharged'),
('S4', 2025, '3.0L V6 Turbocharged'),
('S5', 2025, '3.0L V6 Turbocharged'),
('S6', 2025, '2.9L V6 Turbocharged'),
('S7', 2025, '2.9L V6 Turbocharged'),
('S8', 2025, '4.0L V8 Turbocharged'),
('SQ5', 2025, '3.0L V6 Turbocharged'),
('SQ7', 2025, '4.0L V8 Turbocharged'),
('SQ8', 2025, '4.0L V8 Turbocharged'),
('TT', 2025, '2.0L L4 Turbocharged'),
('TT', 2025, '2.5L L5 Turbocharged'),
('E-TRON', 2025, 'ELECTRIC'),
# 2024
('A1', 2024, '1.5L L4 Turbocharged'),
('A3', 2024, '1.4L L4 Turbocharged'),
('A3', 2024, '2.0L L4 Turbocharged'),
('A4', 2024, '2.0L L4 Turbocharged'),
('A5', 2024, '2.0L L4 Turbocharged'),
('A6', 2024, '2.0L L4 Turbocharged'),
('A6', 2024, '3.0L V6 Turbocharged'),
('A7', 2024, '2.0L L4 Turbocharged'),
('A8', 2024, '3.0L V6 Turbocharged'),
('A8', 2024, '4.0L V8 Turbocharged'),
('Q2', 2024, '1.4L L4 Turbocharged'),
('Q3', 2024, '1.4L L4 Turbocharged'),
('Q3', 2024, '2.0L L4 Turbocharged'),
('Q4', 2024, '2.0L L4 Turbocharged'),
('Q5', 2024, '2.0L L4 Turbocharged'),
('Q5', 2024, '2.0L L4 ELECTRIC/GAS Turbocharged'),
('Q6', 2024, 'ELECTRIC'),
('Q7', 2024, '2.0L L4 Turbocharged'),
('Q7', 2024, '3.0L V6 Turbocharged'),
('Q8', 2024, '3.0L V6 Turbocharged'),
('R8', 2024, '5.2L V10'),
('RS3', 2024, '2.5L L5 Turbocharged'),
('RS5', 2024, '2.9L V6 Turbocharged'),
('RS6', 2024, '4.0L V8 Turbocharged'),
('RS7', 2024, '4.0L V8 Turbocharged'),
('RS E-TRON GT', 2024, 'ELECTRIC'),
('RS Q3', 2024, '2.5L L5 Turbocharged'),
('RS Q8', 2024, '4.0L V8 Turbocharged'),
('S3', 2024, '2.0L L4 Turbocharged'),
('S4', 2024, '3.0L V6 Turbocharged'),
('S5', 2024, '3.0L V6 Turbocharged'),
('S6', 2024, '2.9L V6 Turbocharged'),
('S7', 2024, '2.9L V6 Turbocharged'),
('S8', 2024, '4.0L V8 Turbocharged'),
('SQ5', 2024, '3.0L V6 Turbocharged'),
('SQ7', 2024, '4.0L V8 Turbocharged'),
('SQ8', 2024, '4.0L V8 Turbocharged'),
('TT', 2024, '2.0L L4 Turbocharged'),
('TT', 2024, '2.5L L5 Turbocharged'),
('E-TRON', 2024, 'ELECTRIC'),
# 2023
('A1', 2023, '1.5L L4 Turbocharged'),
('A3', 2023, '1.4L L4 Turbocharged'),
('A3', 2023, '2.0L L4 Turbocharged'),
('A4', 2023, '2.0L L4 Turbocharged'),
('A5', 2023, '2.0L L4 Turbocharged'),
('A6', 2023, '2.0L L4 Turbocharged'),
('A6', 2023, '3.0L V6 Turbocharged'),
('A7', 2023, '2.0L L4 Turbocharged'),
('A8', 2023, '3.0L V6 Turbocharged'),
('A8', 2023, '4.0L V8 Turbocharged'),
('Q2', 2023, '1.4L L4 Turbocharged'),
('Q3', 2023, '1.4L L4 Turbocharged'),
('Q3', 2023, '2.0L L4 Turbocharged'),
('Q4', 2023, '2.0L L4 Turbocharged'),
('Q5', 2023, '2.0L L4 Turbocharged'),
('Q5', 2023, '2.0L L4 ELECTRIC/GAS Turbocharged'),
('Q6', 2023, 'ELECTRIC'),
('Q7', 2023, '2.0L L4 Turbocharged'),
('Q7', 2023, '3.0L V6 Turbocharged'),
('Q8', 2023, '3.0L V6 Turbocharged'),
('R8', 2023, '5.2L V10'),
('RS3', 2023, '2.5L L5 Turbocharged'),
('RS5', 2023, '2.9L V6 Turbocharged'),
('RS6', 2023, '4.0L V8 Turbocharged'),
('RS7', 2023, '4.0L V8 Turbocharged'),
('RS E-TRON GT', 2023, 'ELECTRIC'),
('RS Q3', 2023, '2.5L L5 Turbocharged'),
('RS Q8', 2023, '4.0L V8 Turbocharged'),
('S3', 2023, '2.0L L4 Turbocharged'),
('S4', 2023, '3.0L V6 Turbocharged'),
('S5', 2023, '3.0L V6 Turbocharged'),
('S6', 2023, '2.9L V6 Turbocharged'),
('S7', 2023, '2.9L V6 Turbocharged'),
('S8', 2023, '4.0L V8 Turbocharged'),
('SQ5', 2023, '3.0L V6 Turbocharged'),
('SQ7', 2023, '4.0L V8 Turbocharged'),
('SQ8', 2023, '4.0L V8 Turbocharged'),
('TT', 2023, '2.0L L4 Turbocharged'),
('TT', 2023, '2.5L L5 Turbocharged'),
('E-TRON', 2023, 'ELECTRIC'),
# 2022
('A1', 2022, '1.5L L4 Turbocharged'),
('A3', 2022, '1.4L L4 Turbocharged'),
('A3', 2022, '2.0L L4 Turbocharged'),
('A4', 2022, '2.0L L4 Turbocharged'),
('A5', 2022, '2.0L L4 Turbocharged'),
('A6', 2022, '2.0L L4 Turbocharged'),
('A6', 2022, '3.0L V6 Turbocharged'),
('A7', 2022, '2.0L L4 Turbocharged'),
('A8', 2022, '3.0L V6 Turbocharged'),
('A8', 2022, '4.0L V8 Turbocharged'),
('Q2', 2022, '1.4L L4 Turbocharged'),
('Q3', 2022, '1.4L L4 Turbocharged'),
('Q3', 2022, '2.0L L4 Turbocharged'),
('Q4', 2022, '2.0L L4 Turbocharged'),
('Q5', 2022, '2.0L L4 Turbocharged'),
('Q5', 2022, '2.0L L4 ELECTRIC/GAS Turbocharged'),
('Q6', 2022, 'ELECTRIC'),
('Q7', 2022, '2.0L L4 Turbocharged'),
('Q7', 2022, '3.0L V6 Turbocharged'),
('Q8', 2022, '3.0L V6 Turbocharged'),
('R8', 2022, '5.2L V10'),
('RS3', 2022, '2.5L L5 Turbocharged'),
('RS5', 2022, '2.9L V6 Turbocharged'),
('RS6', 2022, '4.0L V8 Turbocharged'),
('RS7', 2022, '4.0L V8 Turbocharged'),
('RS E-TRON GT', 2022, 'ELECTRIC'),
('RS Q3', 2022, '2.5L L5 Turbocharged'),
('RS Q8', 2022, '4.0L V8 Turbocharged'),
('S3', 2022, '2.0L L4 Turbocharged'),
('S4', 2022, '3.0L V6 Turbocharged'),
('S5', 2022, '3.0L V6 Turbocharged'),
('S6', 2022, '2.9L V6 Turbocharged'),
('S7', 2022, '2.9L V6 Turbocharged'),
('S8', 2022, '4.0L V8 Turbocharged'),
('SQ5', 2022, '3.0L V6 Turbocharged'),
('SQ7', 2022, '4.0L V8 Turbocharged'),
('SQ8', 2022, '4.0L V8 Turbocharged'),
('TT', 2022, '2.0L L4 Turbocharged'),
('TT', 2022, '2.5L L5 Turbocharged'),
('E-TRON', 2022, 'ELECTRIC')
]
# Insert version relationships
for model_name, year, engine in versions:
model_id = get_or_insert_model(conn, brand_id, model_name)
year_id = get_or_insert_year(conn, year)
engine_id = get_or_insert_engine(conn, engine)
insert_version_relationship(conn, model_id, year_id, engine_id)
print(f"Inserted {len(versions)} version relationships for AUDI vehicles")
# Close connection
conn.close()
print("Audi data added successfully!")
if __name__ == "__main__":
main()

379
add_audi_data_extended.py Normal file
View File

@@ -0,0 +1,379 @@
"""
Script to add extended Audi vehicle data (2017-2021) to the database.
This includes additional models and year/motor combinations.
"""
import sqlite3
from typing import List, Tuple
def connect_db(db_path: str = "vehicle_database/vehicle_database.db") -> sqlite3.Connection:
"""Connect to the vehicle database."""
conn = sqlite3.connect(db_path)
conn.execute("PRAGMA foreign_keys = ON") # Enable foreign key constraints
return conn
def get_or_insert_brand(conn: sqlite3.Connection, brand_name: str) -> int:
"""Get brand ID or insert if it doesn't exist."""
cursor = conn.cursor()
# Check if brand already exists
cursor.execute("SELECT id FROM brands WHERE name = ?", (brand_name,))
result = cursor.fetchone()
if result:
return result[0] # Return existing ID
# Insert new brand
cursor.execute("INSERT INTO brands (name) VALUES (?)", (brand_name,))
conn.commit()
return cursor.lastrowid
def get_or_insert_model(conn: sqlite3.Connection, brand_id: int, model_name: str) -> int:
"""Get model ID or insert if it doesn't exist."""
cursor = conn.cursor()
# Check if model already exists for this brand
cursor.execute(
"SELECT id FROM models WHERE brand_id = ? AND name = ?",
(brand_id, model_name)
)
result = cursor.fetchone()
if result:
return result[0] # Return existing ID
# Insert new model
cursor.execute(
"INSERT INTO models (brand_id, name) VALUES (?, ?)",
(brand_id, model_name)
)
conn.commit()
return cursor.lastrowid
def get_or_insert_engine(conn: sqlite3.Connection, engine_name: str) -> int:
"""Get engine ID or insert if it doesn't exist."""
cursor = conn.cursor()
# Check if engine already exists
cursor.execute("SELECT id FROM engines WHERE name = ?", (engine_name,))
result = cursor.fetchone()
if result:
return result[0] # Return existing ID
# Insert new engine
cursor.execute("INSERT INTO engines (name) VALUES (?)", (engine_name,))
conn.commit()
return cursor.lastrowid
def get_or_insert_year(conn: sqlite3.Connection, year: int) -> int:
"""Get year ID or insert if it doesn't exist."""
cursor = conn.cursor()
# Check if year already exists
cursor.execute("SELECT id FROM years WHERE year = ?", (year,))
result = cursor.fetchone()
if result:
return result[0] # Return existing ID
# Insert new year
cursor.execute("INSERT INTO years (year) VALUES (?)", (year,))
conn.commit()
return cursor.lastrowid
def insert_version_relationship(conn: sqlite3.Connection, model_id: int, year_id: int, engine_id: int) -> None:
"""Insert a version relationship if it doesn't exist."""
cursor = conn.cursor()
# Check if version relationship already exists
cursor.execute(
"SELECT id FROM model_year_engine WHERE model_id = ? AND year_id = ? AND engine_id = ?",
(model_id, year_id, engine_id)
)
result = cursor.fetchone()
if not result:
# Insert new version relationship
cursor.execute(
"INSERT INTO model_year_engine (model_id, year_id, engine_id) VALUES (?, ?, ?)",
(model_id, year_id, engine_id)
)
conn.commit()
def main():
"""Main function to add extended Audi data."""
print("Adding extended Audi data (2017-2021)...")
# Connect to database
conn = connect_db()
# Get brand ID (should already exist)
brand_id = get_or_insert_brand(conn, "AUDI")
print(f"Brand 'AUDI' has ID: {brand_id}")
# Define additional models that might need to be added
additional_models = [
'A4 ALLROAD',
'A6 ALLROAD',
'Q2 QUATTRO'
]
# Insert additional models if they don't exist
for model_name in additional_models:
model_id = get_or_insert_model(conn, brand_id, model_name)
# Define versions (model, year, engine) for years 2017-2021
versions = [
# 2021
('A1', 2021, '1.5L L4 Turbocharged'),
('A1', 2021, '2.0L L4 Turbocharged'),
('A1', 2021, '999cc L3 Turbocharged'),
('A4', 2021, '2.0L L4 ELECTRIC/GAS Turbocharged'),
('A4', 2021, '2.0L L4 Turbocharged'),
('A4 ALLROAD', 2021, '2.0L L4 Turbocharged'),
('A5', 2021, '2.0L L4 Turbocharged'),
('A6', 2021, '2.0L L4 Turbocharged'),
('A6', 2021, '3.0L V6 Turbocharged'),
('A6 ALLROAD', 2021, '3.0L V6 Turbocharged'),
('A7', 2021, '2.0L L4 ELECTRIC/GAS Turbocharged'),
('A7', 2021, '2.0L L4 Turbocharged'),
('A7', 2021, '3.0L V6 Turbocharged'),
('A8', 2021, '3.0L V6 ELECTRIC/GAS Turbocharged'),
('A8', 2021, '3.0L V6 Turbocharged'),
('A8', 2021, '4.0L V8 Turbocharged'),
('E-TRON', 2021, 'ELECTRIC'),
('Q2', 2021, '1.4L L4 Turbocharged'),
('Q3', 2021, '1.4L L4 Turbocharged'),
('Q3', 2021, '2.0L L4 Turbocharged'),
('Q5', 2021, '2.0L L4 ELECTRIC/GAS Turbocharged'),
('Q5', 2021, '2.0L L4 Turbocharged'),
('Q7', 2021, '2.0L L4 Turbocharged'),
('Q7', 2021, '3.0L V6 Turbocharged'),
('Q8', 2021, '3.0L V6 Turbocharged'),
('R8', 2021, '5.2L V10'),
('RS3', 2021, '2.5L L5 Turbocharged'),
('RS5', 2021, '2.9L V6 Turbocharged'),
('RS6', 2021, '4.0L V8 Turbocharged'),
('RS7', 2021, '4.0L V8 Turbocharged'),
('RS Q3', 2021, '2.5L L5 Turbocharged'),
('RS Q8', 2021, '4.0L V8 Turbocharged'),
('S3', 2021, '2.0L L4 Turbocharged'),
('S4', 2021, '3.0L V6 Turbocharged'),
('S5', 2021, '3.0L V6 Turbocharged'),
('S6', 2021, '2.9L V6 Turbocharged'),
('S7', 2021, '2.9L V6 Turbocharged'),
('S8', 2021, '4.0L V8 Turbocharged'),
('SQ5', 2021, '3.0L V6 Turbocharged'),
('SQ7', 2021, '4.0L V8 Turbocharged'),
('SQ8', 2021, '4.0L V8 Turbocharged'),
('TT', 2021, '2.0L L4 Turbocharged'),
('TT', 2021, '2.5L L5 Turbocharged'),
# 2020
('A1', 2020, '1.5L L4 Turbocharged'),
('A1', 2020, '2.0L L4 Turbocharged'),
('A1', 2020, '999cc L3 Turbocharged'),
('A3', 2020, '1.4L L4 Turbocharged'),
('A3', 2020, '2.0L L4 Turbocharged'),
('A4', 2020, '2.0L L4 Turbocharged'),
('A4 ALLROAD', 2020, '2.0L L4 Turbocharged'),
('A5', 2020, '2.0L L4 Turbocharged'),
('A6', 2020, '2.0L L4 Turbocharged'),
('A6', 2020, '3.0L V6 Turbocharged'),
('A6 ALLROAD', 2020, '3.0L V6 Turbocharged'),
('A7', 2020, '3.0L V6 Turbocharged'),
('A8', 2020, '3.0L V6 ELECTRIC/GAS Turbocharged'),
('A8', 2020, '3.0L V6 Turbocharged'),
('A8', 2020, '4.0L V8 Turbocharged'),
('E-TRON', 2020, 'ELECTRIC'),
('Q2', 2020, '1.4L L4 Turbocharged'),
('Q2 QUATTRO', 2020, '2.0L L4 Turbocharged'),
('Q3', 2020, '1.4L L4 Turbocharged'),
('Q3', 2020, '2.0L L4 Turbocharged'),
('Q5', 2020, '2.0L L4 ELECTRIC/GAS Turbocharged'),
('Q5', 2020, '2.0L L4 Turbocharged'),
('Q7', 2020, '2.0L L4 Turbocharged'),
('Q7', 2020, '3.0L V6 Turbocharged'),
('Q8', 2020, '3.0L V6 Turbocharged'),
('R8', 2020, '5.2L V10'),
('RS3', 2020, '2.5L L5 Turbocharged'),
('RS5', 2020, '2.9L V6 Turbocharged'),
('RS6', 2020, '4.0L V8 Turbocharged'),
('RS7', 2020, '4.0L V8 Turbocharged'),
('RS Q3', 2020, '2.5L L5 Turbocharged'),
('RS Q8', 2020, '4.0L V8 Turbocharged'),
('S3', 2020, '2.0L L4 Turbocharged'),
('S4', 2020, '3.0L V6 Turbocharged'),
('S5', 2020, '3.0L V6 Turbocharged'),
('S6', 2020, '2.9L V6 Turbocharged'),
('S7', 2020, '2.9L V6 Turbocharged'),
('S8', 2020, '4.0L V8 Turbocharged'),
('SQ5', 2020, '3.0L V6 Turbocharged'),
('SQ7', 2020, '4.0L V8 Turbocharged'),
('SQ8', 2020, '4.0L V8 Turbocharged'),
('TT', 2020, '2.0L L4 Turbocharged'),
('TT', 2020, '2.5L L5 Turbocharged'),
# 2019
('A3', 2019, '1.4L L4 Turbocharged'),
('A3', 2019, '2.0L L4 Turbocharged'),
('A4', 2019, '2.0L L4 Turbocharged'),
('A4 ALLROAD', 2019, '2.0L L4 Turbocharged'),
('A5', 2019, '2.0L L4 Turbocharged'),
('A6', 2019, '2.0L L4 Turbocharged'),
('A6', 2019, '3.0L V6 Turbocharged'),
('A7', 2019, '3.0L V6 Turbocharged'),
('A8', 2019, '3.0L V6 Turbocharged'),
('A8', 2019, '4.0L V8 Turbocharged'),
('E-TRON', 2019, 'ELECTRIC'),
('Q2', 2019, '1.4L L4 Turbocharged'),
('Q2', 2019, '2.0L L4 Turbocharged'),
('Q3', 2019, '1.4L L4 Turbocharged'),
('Q3', 2019, '2.0L L4 Turbocharged'),
('Q5', 2019, '2.0L L4 Turbocharged'),
('Q7', 2019, '2.0L L4 Turbocharged'),
('Q7', 2019, '3.0L V6 DIESEL Turbocharged'),
('Q7', 2019, '3.0L V6 Supercharged'),
('Q8', 2019, '3.0L V6 Turbocharged'),
('R8', 2019, '5.2L V10'),
('RS3', 2019, '2.5L L5 Turbocharged'),
('RS5', 2019, '2.9L V6 Turbocharged'),
('RS6', 2019, '4.0L V8 Turbocharged'),
('RS7', 2019, '4.0L V8 Turbocharged'),
('RS Q3', 2019, '2.5L L5 Turbocharged'),
('RS Q8', 2019, '4.0L V8 Turbocharged'),
('S3', 2019, '2.0L L4 Turbocharged'),
('S4', 2019, '3.0L V6 Turbocharged'),
('S5', 2019, '3.0L V6 Turbocharged'),
('S6', 2019, '2.9L V6 Turbocharged'),
('S7', 2019, '2.9L V6 Turbocharged'),
('S8', 2019, '4.0L V8 Turbocharged'),
('SQ5', 2019, '3.0L V6 Turbocharged'),
('SQ7', 2019, '4.0L V8 Turbocharged'),
('SQ8', 2019, '4.0L V8 Turbocharged'),
('TT', 2019, '2.0L L4 Turbocharged'),
('TT', 2019, '2.5L L5 Turbocharged'),
# 2018
('A1', 2018, '1.4L L4 Turbocharged'),
('A1', 2018, '1.8L L4 Turbocharged'),
('A3', 2018, '1.4L L4 ELECTRIC/GAS Turbocharged'),
('A3', 2018, '1.4L L4 Turbocharged'),
('A3', 2018, '1.8L L4 Turbocharged'),
('A3', 2018, '2.0L L4 Turbocharged'),
('A4', 2018, '2.0L L4 Turbocharged'),
('A4 ALLROAD', 2018, '2.0L L4 Turbocharged'),
('A5', 2018, '2.0L L4 Turbocharged'),
('A6', 2018, '1.8L L4 Turbocharged'),
('A6', 2018, '2.0L L4 Turbocharged'),
('A6', 2018, '3.0L V6 Supercharged'),
('A7', 2018, '2.0L L4 Turbocharged'),
('A7', 2018, '3.0L V6 Supercharged'),
('A8', 2018, '3.0L V6 Supercharged'),
('A8', 2018, '4.0L V8 Turbocharged'),
('A8', 2018, '6.3L W12'),
('Q2', 2018, '1.4L L4 Turbocharged'),
('Q2', 2018, '2.0L L4 Turbocharged'),
('Q3', 2018, '1.4L L4 Turbocharged'),
('Q3', 2018, '2.0L L4 Turbocharged'),
('Q5', 2018, '2.0L L4 Turbocharged'),
('Q7', 2018, '2.0L L4 Turbocharged'),
('Q7', 2018, '3.0L V6 DIESEL Turbocharged'),
('Q7', 2018, '3.0L V6 Supercharged'),
('Q8', 2018, '3.0L V6 Turbocharged'),
('R8', 2018, '5.2L V10'),
('RS3', 2018, '2.5L L5 Turbocharged'),
('RS5', 2018, '2.9L V6 Turbocharged'),
('RS6', 2018, '4.0L V8 Turbocharged'),
('RS7', 2018, '4.0L V8 Turbocharged'),
('RS Q3', 2018, '2.5L L5 Turbocharged'),
('RS Q8', 2018, '4.0L V8 Turbocharged'),
('S3', 2018, '2.0L L4 Turbocharged'),
('S4', 2018, '3.0L V6 Supercharged'),
('S4', 2018, '3.0L V6 Turbocharged'),
('S5', 2018, '3.0L V6 Supercharged'),
('S5', 2018, '3.0L V6 Turbocharged'),
('S6', 2018, '4.0L V8 Turbocharged'),
('S7', 2018, '4.0L V8 Turbocharged'),
('S8', 2018, '4.0L V8 Turbocharged'),
('SQ5', 2018, '3.0L V6 Supercharged'),
('SQ5', 2018, '3.0L V6 Turbocharged'),
('SQ7', 2018, '4.0L V8 Turbocharged'),
('SQ8', 2018, '4.0L V8 Turbocharged'),
('TT', 2018, '1.8L L4 Turbocharged'),
('TT', 2018, '2.0L L4 Turbocharged'),
('TT', 2018, '2.5L L5 Turbocharged'),
# 2017
('A1', 2017, '1.4L L4 Turbocharged'),
('A1', 2017, '1.8L L4 Turbocharged'),
('A3', 2017, '1.4L L4 ELECTRIC/GAS Turbocharged'),
('A3', 2017, '1.4L L4 Turbocharged'),
('A3', 2017, '2.0L L4 Turbocharged'),
('A4', 2017, '2.0L L4 Turbocharged'),
('A4 ALLROAD', 2017, '2.0L L4 Turbocharged'),
('A5', 2017, '2.0L L4 Turbocharged'),
('A6', 2017, '1.8L L4 Turbocharged'),
('A6', 2017, '2.0L L4 Turbocharged'),
('A6', 2017, '3.0L V6 Supercharged'),
('A7', 2017, '2.0L L4 Turbocharged'),
('A7', 2017, '3.0L V6 Supercharged'),
('A8', 2017, '3.0L V6 Supercharged'),
('A8', 2017, '4.0L V8 Turbocharged'),
('A8', 2017, '6.3L W12'),
('Q3', 2017, '1.4L L4 Turbocharged'),
('Q3', 2017, '2.0L L4 Turbocharged'),
('Q5', 2017, '2.0L L4 Turbocharged'),
('Q5', 2017, '3.0L V6 DIESEL Turbocharged'),
('Q5', 2017, '3.0L V6 Supercharged'),
('Q7', 2017, '2.0L L4 Turbocharged'),
('Q7', 2017, '3.0L V6 DIESEL Turbocharged'),
('Q7', 2017, '3.0L V6 Supercharged'),
('Q8', 2017, '3.0L V6 Turbocharged'),
('R8', 2017, '5.2L V10'),
('RS3', 2017, '2.5L L5 Turbocharged'),
('RS5', 2017, '2.9L V6 Turbocharged'),
('RS6', 2017, '4.0L V8 Turbocharged'),
('RS7', 2017, '4.0L V8 Turbocharged'),
('RS Q3', 2017, '2.5L L5 Turbocharged'),
('RS Q8', 2017, '4.0L V8 Turbocharged'),
('S3', 2017, '2.0L L4 Turbocharged'),
('S4', 2017, '3.0L V6 Supercharged'),
('S4', 2017, '3.0L V6 Turbocharged'),
('S5', 2017, '3.0L V6 Supercharged'),
('S5', 2017, '3.0L V6 Turbocharged'),
('S6', 2017, '4.0L V8 Turbocharged'),
('S7', 2017, '4.0L V8 Turbocharged'),
('S8', 2017, '4.0L V8 Turbocharged'),
('SQ5', 2017, '3.0L V6 Supercharged'),
('SQ5', 2017, '3.0L V6 Turbocharged'),
('SQ7', 2017, '4.0L V8 Turbocharged'),
('SQ8', 2017, '4.0L V8 Turbocharged'),
('TT', 2017, '1.8L L4 Turbocharged'),
('TT', 2017, '2.0L L4 Turbocharged'),
('TT', 2017, '2.5L L5 Turbocharged')
]
# Insert version relationships
for model_name, year, engine in versions:
model_id = get_or_insert_model(conn, brand_id, model_name)
year_id = get_or_insert_year(conn, year)
engine_id = get_or_insert_engine(conn, engine)
insert_version_relationship(conn, model_id, year_id, engine_id)
print(f"Inserted {len(versions)} additional version relationships for AUDI vehicles (2017-2021)")
# Close connection
conn.close()
print("Extended Audi data added successfully!")
if __name__ == "__main__":
main()

367
add_audi_data_extended2.py Normal file
View File

@@ -0,0 +1,367 @@
"""
Script to add extended Audi vehicle data (2012-2016) to the database.
This includes additional models and year/motor combinations.
"""
import sqlite3
from typing import List, Tuple
def connect_db(db_path: str = "vehicle_database/vehicle_database.db") -> sqlite3.Connection:
"""Connect to the vehicle database."""
conn = sqlite3.connect(db_path)
conn.execute("PRAGMA foreign_keys = ON") # Enable foreign key constraints
return conn
def get_or_insert_brand(conn: sqlite3.Connection, brand_name: str) -> int:
"""Get brand ID or insert if it doesn't exist."""
cursor = conn.cursor()
# Check if brand already exists
cursor.execute("SELECT id FROM brands WHERE name = ?", (brand_name,))
result = cursor.fetchone()
if result:
return result[0] # Return existing ID
# Insert new brand
cursor.execute("INSERT INTO brands (name) VALUES (?)", (brand_name,))
conn.commit()
return cursor.lastrowid
def get_or_insert_model(conn: sqlite3.Connection, brand_id: int, model_name: str) -> int:
"""Get model ID or insert if it doesn't exist."""
cursor = conn.cursor()
# Check if model already exists for this brand
cursor.execute(
"SELECT id FROM models WHERE brand_id = ? AND name = ?",
(brand_id, model_name)
)
result = cursor.fetchone()
if result:
return result[0] # Return existing ID
# Insert new model
cursor.execute(
"INSERT INTO models (brand_id, name) VALUES (?, ?)",
(brand_id, model_name)
)
conn.commit()
return cursor.lastrowid
def get_or_insert_engine(conn: sqlite3.Connection, engine_name: str) -> int:
"""Get engine ID or insert if it doesn't exist."""
cursor = conn.cursor()
# Check if engine already exists
cursor.execute("SELECT id FROM engines WHERE name = ?", (engine_name,))
result = cursor.fetchone()
if result:
return result[0] # Return existing ID
# Insert new engine
cursor.execute("INSERT INTO engines (name) VALUES (?)", (engine_name,))
conn.commit()
return cursor.lastrowid
def get_or_insert_year(conn: sqlite3.Connection, year: int) -> int:
"""Get year ID or insert if it doesn't exist."""
cursor = conn.cursor()
# Check if year already exists
cursor.execute("SELECT id FROM years WHERE year = ?", (year,))
result = cursor.fetchone()
if result:
return result[0] # Return existing ID
# Insert new year
cursor.execute("INSERT INTO years (year) VALUES (?)", (year,))
conn.commit()
return cursor.lastrowid
def insert_version_relationship(conn: sqlite3.Connection, model_id: int, year_id: int, engine_id: int) -> None:
"""Insert a version relationship if it doesn't exist."""
cursor = conn.cursor()
# Check if version relationship already exists
cursor.execute(
"SELECT id FROM model_year_engine WHERE model_id = ? AND year_id = ? AND engine_id = ?",
(model_id, year_id, engine_id)
)
result = cursor.fetchone()
if not result:
# Insert new version relationship
cursor.execute(
"INSERT INTO model_year_engine (model_id, year_id, engine_id) VALUES (?, ?, ?)",
(model_id, year_id, engine_id)
)
conn.commit()
def main():
"""Main function to add extended Audi data (2012-2016)."""
print("Adding extended Audi data (2012-2016)...")
# Connect to database
conn = connect_db()
# Get brand ID (should already exist)
brand_id = get_or_insert_brand(conn, "AUDI")
print(f"Brand 'AUDI' has ID: {brand_id}")
# Define additional models that might need to be added
additional_models = [
'ALLROAD'
]
# Insert additional models if they don't exist
for model_name in additional_models:
model_id = get_or_insert_model(conn, brand_id, model_name)
# Define versions (model, year, engine) for years 2012-2016
versions = [
# 2016
('A1', 2016, '1.4L L4 Turbocharged'),
('A1', 2016, '1.8L L4 Turbocharged'),
('A3', 2016, '1.4L L4 ELECTRIC/GAS Turbocharged'),
('A3', 2016, '1.4L L4 Turbocharged'),
('A3', 2016, '1.8L L4 Turbocharged'),
('A3', 2016, '2.0L L4 DIESEL Turbocharged'),
('A3', 2016, '2.0L L4 Turbocharged'),
('A4', 2016, '1.8L L4 Turbocharged'),
('A4', 2016, '2.0L L4 Turbocharged'),
('A4 ALLROAD', 2016, '2.0L L4 Turbocharged'),
('A5', 2016, '2.0L L4 Turbocharged'),
('A5', 2016, '3.0L V6 Supercharged'),
('A6', 2016, '1.8L L4 Turbocharged'),
('A6', 2016, '2.0L L4 Turbocharged'),
('A6', 2016, '3.0L V6 DIESEL Turbocharged'),
('A6', 2016, '3.0L V6 Supercharged'),
('A7', 2016, '2.0L L4 Turbocharged'),
('A7', 2016, '3.0L V6 DIESEL Turbocharged'),
('A7', 2016, '3.0L V6 Supercharged'),
('A8', 2016, '3.0L V6 DIESEL Turbocharged'),
('A8', 2016, '3.0L V6 Supercharged'),
('A8', 2016, '4.0L V8 Turbocharged'),
('A8', 2016, '6.3L W12 Turbocharged'),
('ALLROAD', 2016, '2.0L L4 Turbocharged'),
('Q3', 2016, '1.4L L4 Turbocharged'),
('Q3', 2016, '2.0L L4 Turbocharged'),
('Q5', 2016, '2.0L L4 ELECTRIC/GAS Turbocharged'),
('Q5', 2016, '2.0L L4 Turbocharged'),
('Q5', 2016, '3.0L V6 DIESEL Turbocharged'),
('Q7', 2016, '2.0L L4 Turbocharged'),
('Q7', 2016, '3.0L V6 DIESEL Turbocharged'),
('Q7', 2016, '3.0L V6 Supercharged'),
('Q8', 2016, '3.0L V6 Turbocharged'),
('R8', 2016, '4.2L V8'),
('R8', 2016, '5.2L V10'),
('RS5', 2016, '4.2L V8'),
('RS7', 2016, '4.0L V8 Turbocharged'),
('S3', 2016, '2.0L L4 Turbocharged'),
('S4', 2016, '3.0L V6 Supercharged'),
('S5', 2016, '3.0L V6 Supercharged'),
('S6', 2016, '4.0L V8 Turbocharged'),
('S7', 2016, '4.0L V8 Turbocharged'),
('S8', 2016, '4.0L V8 Turbocharged'),
('SQ5', 2016, '3.0L V6 Supercharged'),
('TT', 2016, '1.8L L4 Turbocharged'),
('TT', 2016, '2.0L L4 Turbocharged'),
# 2015
('A1', 2015, '1.4L L4 Turbocharged'),
('A3', 2015, '1.4L L4 Turbocharged'),
('A3', 2015, '1.8L L4 Turbocharged'),
('A3', 2015, '2.0L L4 DIESEL Turbocharged'),
('A3', 2015, '2.0L L4 Turbocharged'),
('A4', 2015, '1.8L L4 Turbocharged'),
('A4', 2015, '2.0L L4 Turbocharged'),
('A4 ALLROAD', 2015, '2.0L L4 Turbocharged'),
('A5', 2015, '1.8L L4 Turbocharged'),
('A5', 2015, '2.0L L4 Turbocharged'),
('A5', 2015, '3.0L V6 Supercharged'),
('A6', 2015, '2.0L L4 Turbocharged'),
('A6', 2015, '3.0L V6 DIESEL Turbocharged'),
('A6', 2015, '3.0L V6 Supercharged'),
('A7', 2015, '2.0L L4 Turbocharged'),
('A7', 2015, '3.0L V6 DIESEL Turbocharged'),
('A7', 2015, '3.0L V6 Supercharged'),
('A8', 2015, '3.0L V6 DIESEL Turbocharged'),
('A8', 2015, '3.0L V6 Supercharged'),
('A8', 2015, '4.0L V8 Turbocharged'),
('A8', 2015, '6.3L W12'),
('ALLROAD', 2015, '2.0L L4 Turbocharged'),
('Q3', 2015, '2.0L L4 Turbocharged'),
('Q5', 2015, '2.0L L4 ELECTRIC/GAS Turbocharged'),
('Q5', 2015, '2.0L L4 Turbocharged'),
('Q5', 2015, '3.0L V6 DIESEL Turbocharged'),
('Q7', 2015, '2.0L L4 Turbocharged'),
('Q7', 2015, '3.0L V6 DIESEL Turbocharged'),
('Q7', 2015, '3.0L V6 Supercharged'),
('Q8', 2015, '3.0L V6 Turbocharged'),
('R8', 2015, '4.2L V8'),
('R8', 2015, '5.2L V10'),
('RS5', 2015, '4.2L V8'),
('RS7', 2015, '4.0L V8 Turbocharged'),
('S3', 2015, '2.0L L4 Turbocharged'),
('S4', 2015, '3.0L V6 Supercharged'),
('S5', 2015, '3.0L V6 Supercharged'),
('S6', 2015, '4.0L V8 Turbocharged'),
('S7', 2015, '4.0L V8 Turbocharged'),
('S8', 2015, '4.0L V8 Turbocharged'),
('SQ5', 2015, '3.0L V6 Supercharged'),
('TT', 2015, '1.8L L4 Turbocharged'),
('TT', 2015, '2.0L L4 Turbocharged'),
# 2014
('A1', 2014, '1.4L L4 Turbocharged'),
('A3', 2014, '1.4L L4 Turbocharged'),
('A3', 2014, '1.8L L4 Turbocharged'),
('A4', 2014, '1.8L L4 Turbocharged'),
('A4', 2014, '2.0L L4 Turbocharged'),
('A4 ALLROAD', 2014, '2.0L L4 Turbocharged'),
('A5', 2014, '1.8L L4 Turbocharged'),
('A5', 2014, '2.0L L4 Turbocharged'),
('A5', 2014, '3.0L V6 Supercharged'),
('A6', 2014, '2.0L L4 Turbocharged'),
('A6', 2014, '3.0L V6 DIESEL Turbocharged'),
('A6', 2014, '3.0L V6 Supercharged'),
('A7', 2014, '2.0L L4 Turbocharged'),
('A7', 2014, '3.0L V6 DIESEL Turbocharged'),
('A7', 2014, '3.0L V6 Supercharged'),
('A8', 2014, '3.0L V6 DIESEL Turbocharged'),
('A8', 2014, '3.0L V6 Supercharged'),
('A8', 2014, '4.0L V8 Turbocharged'),
('A8', 2014, '6.3L W12'),
('ALLROAD', 2014, '2.0L L4 Turbocharged'),
('Q3', 2014, '2.0L L4 Turbocharged'),
('Q5', 2014, '2.0L L4 Turbocharged'),
('Q5', 2014, '3.0L V6 DIESEL Turbocharged'),
('Q7', 2014, '2.0L L4 Turbocharged'),
('Q7', 2014, '3.0L V6 DIESEL Turbocharged'),
('Q7', 2014, '3.0L V6 Supercharged'),
('Q8', 2014, '3.0L V6 Turbocharged'),
('R8', 2014, '4.2L V8'),
('R8', 2014, '5.2L V10'),
('RS5', 2014, '4.2L V8'),
('RS7', 2014, '4.0L V8 Turbocharged'),
('S3', 2014, '2.0L L4 Turbocharged'),
('S4', 2014, '3.0L V6 Supercharged'),
('S5', 2014, '3.0L V6 Supercharged'),
('S6', 2014, '4.0L V8 Turbocharged'),
('S7', 2014, '4.0L V8 Turbocharged'),
('S8', 2014, '4.0L V8 Turbocharged'),
('SQ5', 2014, '3.0L V6 Supercharged'),
('TT', 2014, '1.8L L4 Turbocharged'),
('TT', 2014, '2.0L L4 Turbocharged'),
# 2013
('A1', 2013, '1.4L L4 Turbocharged'),
('A3', 2013, '1.4L L4 Turbocharged'),
('A3', 2013, '1.8L L4 Turbocharged'),
('A3', 2013, '2.0L L4 DIESEL Turbocharged'),
('A3', 2013, '2.0L L4 Turbocharged'),
('A4', 2013, '1.8L L4 Turbocharged'),
('A4', 2013, '2.0L L4 Turbocharged'),
('A5', 2013, '1.8L L4 Turbocharged'),
('A5', 2013, '2.0L L4 Turbocharged'),
('A5', 2013, '3.0L V6 Supercharged'),
('A6', 2013, '2.0L L4 Turbocharged'),
('A6', 2013, '2.8L V6'),
('A6', 2013, '3.0L V6 DIESEL Turbocharged'),
('A6', 2013, '3.0L V6 Supercharged'),
('A7', 2013, '3.0L V6 Supercharged'),
('A8', 2013, '3.0L V6 Supercharged'),
('A8', 2013, '4.0L V8 Turbocharged'),
('A8', 2013, '6.3L W12'),
('ALLROAD', 2013, '2.0L L4 Turbocharged'),
('Q3', 2013, '2.0L L4 Turbocharged'),
('Q5', 2013, '2.0L L4 ELECTRIC/GAS Turbocharged'),
('Q5', 2013, '2.0L L4 Turbocharged'),
('Q5', 2013, '3.0L V6 DIESEL Turbocharged'),
('Q7', 2013, '2.0L L4 Turbocharged'),
('Q7', 2013, '3.0L V6 DIESEL Turbocharged'),
('Q7', 2013, '3.0L V6 Supercharged'),
('Q8', 2013, '3.0L V6 Turbocharged'),
('R8', 2013, '4.2L V8'),
('R8', 2013, '5.2L V10'),
('RS5', 2013, '4.2L V8'),
('RS7', 2013, '4.0L V8 Turbocharged'),
('S3', 2013, '2.0L L4 Turbocharged'),
('S4', 2013, '3.0L V6 Supercharged'),
('S5', 2013, '3.0L V6 Supercharged'),
('S6', 2013, '4.0L V8 Turbocharged'),
('S7', 2013, '4.0L V8 Turbocharged'),
('S8', 2013, '4.0L V8 Turbocharged'),
('SQ5', 2013, '3.0L V6 Supercharged'),
('TT', 2013, '1.8L L4 Turbocharged'),
('TT', 2013, '2.0L L4 Turbocharged'),
('TT', 2013, '2.5L L5 Turbocharged'),
# 2012
('A1', 2012, '1.4L L4 Turbocharged'),
('A3', 2012, '1.4L L4 Turbocharged'),
('A3', 2012, '1.8L L4 Turbocharged'),
('A3', 2012, '2.0L L4 DIESEL Turbocharged'),
('A3', 2012, '2.0L L4 Turbocharged'),
('A4', 2012, '1.8L L4 Turbocharged'),
('A4', 2012, '2.0L L4 Turbocharged'),
('A5', 2012, '1.8L L4 Turbocharged'),
('A5', 2012, '2.0L L4 Turbocharged'),
('A5', 2012, '3.0L V6 Supercharged'),
('A6', 2012, '2.0L L4 Turbocharged'),
('A6', 2012, '2.8L V6'),
('A6', 2012, '3.0L V6 DIESEL Turbocharged'),
('A6', 2012, '3.0L V6 Supercharged'),
('A7', 2012, '3.0L V6 Supercharged'),
('A8', 2012, '3.0L V6 Supercharged'),
('A8', 2012, '4.0L V8 Turbocharged'),
('A8', 2012, '6.3L W12'),
('Q3', 2012, '2.0L L4 Turbocharged'),
('Q5', 2012, '2.0L L4 Turbocharged'),
('Q5', 2012, '3.0L V6 DIESEL Turbocharged'),
('Q7', 2012, '2.0L L4 Turbocharged'),
('Q7', 2012, '3.0L V6 DIESEL Turbocharged'),
('Q7', 2012, '3.0L V6 Supercharged'),
('Q8', 2012, '3.0L V6 Turbocharged'),
('R8', 2012, '4.2L V8'),
('R8', 2012, '5.2L V10'),
('RS5', 2012, '4.2L V8'),
('RS7', 2012, '4.0L V8 Turbocharged'),
('S3', 2012, '2.0L L4 Turbocharged'),
('S4', 2012, '3.0L V6 Supercharged'),
('S5', 2012, '3.0L V6 Supercharged'),
('S6', 2012, '4.0L V8 Turbocharged'),
('S7', 2012, '4.0L V8 Turbocharged'),
('S8', 2012, '4.0L V8 Turbocharged'),
('SQ5', 2012, '3.0L V6 Supercharged'),
('TT', 2012, '1.8L L4 Turbocharged'),
('TT', 2012, '2.0L L4 Turbocharged'),
('TT', 2012, '2.5L L5 Turbocharged')
]
# Insert version relationships
for model_name, year, engine in versions:
model_id = get_or_insert_model(conn, brand_id, model_name)
year_id = get_or_insert_year(conn, year)
engine_id = get_or_insert_engine(conn, engine)
insert_version_relationship(conn, model_id, year_id, engine_id)
print(f"Inserted {len(versions)} additional version relationships for AUDI vehicles (2012-2016)")
# Close connection
conn.close()
print("Extended Audi data (2012-2016) added successfully!")
if __name__ == "__main__":
main()

177
add_crosley_data.py Normal file
View File

@@ -0,0 +1,177 @@
#!/usr/bin/env python3
"""
Script para agregar datos de Crosley a la base de datos de vehículos
"""
import sqlite3
import os
def add_crosley_data():
# Verificar que la base de datos exista
db_path = "vehicle_database/vehicle_database.db"
if not os.path.exists(db_path):
print(f"Error: Base de datos no encontrada en {db_path}")
return
conn = sqlite3.connect(db_path)
cursor = conn.cursor()
print("Agregando datos de Crosley a la base de datos...")
try:
# Insertar la marca Crosley
cursor.execute("INSERT OR IGNORE INTO brands (name) VALUES (?)", ("CROSLEY",))
cursor.execute("SELECT id FROM brands WHERE name = ?", ("CROSLEY",))
brand_id = cursor.fetchone()[0]
print(f"Marca CROSLEY tiene ID: {brand_id}")
# Insertar modelos de Crosley
models = [
'FARM-O-ROAD', 'HOT SHOT', 'PANEL DELIVERY', 'PICKUP',
'STANDARD', 'SUPER', 'SUPER SPORTS', 'CROSLEY' # Agregué 'CROSLEY' porque aparece en los datos
]
for model in models:
cursor.execute(
"INSERT OR IGNORE INTO models (brand_id, name) VALUES (?, ?)",
(brand_id, model)
)
print(f"Agregados {len(models)} modelos de Crosley")
# Datos de años y motores para cada modelo
crosley_data = [
# 1952
('FARM-O-ROAD', 1952, '724cc 44cid L4'),
('HOT SHOT', 1952, '724cc 44cid L4'),
('PANEL DELIVERY', 1952, '724cc 44cid L4'),
('PICKUP', 1952, '724cc 44cid L4'),
('STANDARD', 1952, '724cc 44cid L4'),
('SUPER', 1952, '0.7L 44cid L4'),
('SUPER SHOT', 1952, '0.7L 44cid L4'),
('SUPER SPORTS', 1952, '0.7L 44cid L4'),
# 1951
('FARM-O-ROAD', 1951, '724cc 44cid L4'),
('HOT SHOT', 1951, '724cc 44cid L4'),
('PANEL DELIVERY', 1951, '724cc 44cid L4'),
('PICKUP', 1951, '724cc 44cid L4'),
('STANDARD', 1951, '724cc 44cid L4'),
('SUPER', 1951, '0.7L 44cid L4'),
('SUPER SPORTS', 1951, '0.7L 44cid L4'),
# 1950
('CROSLEY', 1950, '724cc 44cid L4'),
('FARM-O-ROAD', 1950, '724cc 44cid L4'),
('HOT SHOT', 1950, '724cc 44cid L4'),
('PANEL DELIVERY', 1950, '724cc 44cid L4'),
('PICKUP', 1950, '724cc 44cid L4'),
('STANDARD', 1950, '724cc 44cid L4'),
('SUPER', 1950, '0.7L 44cid L4'),
# 1949
('CROSLEY', 1949, '724cc 44cid L4'),
('HOT SHOT', 1949, '724cc 44cid L4'),
('PANEL DELIVERY', 1949, '724cc 44cid L4'),
('PICKUP', 1949, '724cc 44cid L4'),
# 1948
('CROSLEY', 1948, '724cc 44cid L4'),
('PANEL DELIVERY', 1948, '724cc 44cid L4'),
('PICKUP', 1948, '724cc 44cid L4'),
# 1947
('CROSLEY', 1947, '724cc 44cid L4'),
('PICKUP', 1947, '724cc 44cid L4'),
# 1946
('CROSLEY', 1946, '724cc 44cid L4'),
# 1942
('CROSLEY', 1942, '724cc 44cid L4'),
# 1941
('CROSLEY', 1941, '579cc 35cid L2'),
# 1940
('CROSLEY', 1940, '579cc 35cid L2'),
# 1939
('CROSLEY', 1939, '638cc 39cid L2')
]
# Insertar años
years = list(set([data[1] for data in crosley_data])) # Obtener años únicos
for year in years:
cursor.execute("INSERT OR IGNORE INTO years (year) VALUES (?)", (year,))
print(f"Agregados {len(years)} años")
# Insertar motores
engines = list(set([data[2] for data in crosley_data])) # Obtener motores únicos
for engine in engines:
cursor.execute("INSERT OR IGNORE INTO engines (name) VALUES (?)", (engine,))
print(f"Agregados {len(engines)} motores")
# Crear combinaciones modelo-año-motor
for model_name, year, engine_name in crosley_data:
# Obtener IDs
cursor.execute("SELECT id FROM models WHERE brand_id = ? AND name = ?", (brand_id, model_name))
model_result = cursor.fetchone()
if model_result:
model_id = model_result[0]
else:
print(f"Advertencia: Modelo {model_name} no encontrado para la marca CROSLEY")
continue
cursor.execute("SELECT id FROM years WHERE year = ?", (year,))
year_result = cursor.fetchone()
if year_result:
year_id = year_result[0]
else:
print(f"Advertencia: Año {year} no encontrado")
continue
cursor.execute("SELECT id FROM engines WHERE name = ?", (engine_name,))
engine_result = cursor.fetchone()
if engine_result:
engine_id = engine_result[0]
else:
print(f"Advertencia: Motor {engine_name} no encontrado")
continue
# Insertar la combinación modelo-año-motor
cursor.execute(
"""INSERT OR REPLACE INTO model_year_engine
(model_id, year_id, engine_id) VALUES (?, ?, ?)""",
(model_id, year_id, engine_id)
)
conn.commit()
print(f"Se agregaron {len(crosley_data)} combinaciones modelo-año-motor para CROSLEY")
print("Datos de CROSLEY agregados exitosamente a la base de datos!")
# Mostrar algunos resultados
print("\nAlgunos vehículos CROSLEY agregados:")
cursor.execute("""
SELECT b.name, m.name, y.year, e.name
FROM model_year_engine mye
JOIN models m ON mye.model_id = m.id
JOIN brands b ON m.brand_id = b.id
JOIN years y ON mye.year_id = y.id
JOIN engines e ON mye.engine_id = e.id
WHERE b.name = 'CROSLEY'
ORDER BY y.year DESC, m.name
LIMIT 15
""")
results = cursor.fetchall()
for brand, model, year, engine in results:
print(f" {year} {brand} {model} - {engine}")
except Exception as e:
print(f"Error al agregar datos de CROSLEY: {e}")
conn.rollback()
finally:
conn.close()
if __name__ == "__main__":
add_crosley_data()

255
add_historical_data.py Normal file
View File

@@ -0,0 +1,255 @@
#!/usr/bin/env python3
"""
Script para agregar datos históricos de varias marcas a la base de datos de vehículos
"""
import sqlite3
import os
def add_historical_data():
# Verificar que la base de datos exista
db_path = "vehicle_database/vehicle_database.db"
if not os.path.exists(db_path):
print(f"Error: Base de datos no encontrada en {db_path}")
return
conn = sqlite3.connect(db_path)
cursor = conn.cursor()
print("Agregando datos históricos de varias marcas a la base de datos...")
try:
# Insertar marcas
brands = ['CONTINENTAL', 'CORD', 'COLE', 'CLEVELAND', 'CISITALIA', 'CHIREY']
for brand in brands:
cursor.execute("INSERT OR IGNORE INTO brands (name) VALUES (?)", (brand,))
print(f"Agregadas {len(brands)} marcas históricas")
# Insertar modelos por marca
# CONTINENTAL
continental_models = ['BEACON', 'ACE', 'FLYER']
for model in continental_models:
cursor.execute("SELECT id FROM brands WHERE name = ?", ("CONTINENTAL",))
brand_id = cursor.fetchone()[0]
cursor.execute(
"INSERT OR IGNORE INTO models (brand_id, name) VALUES (?, ?)",
(brand_id, model)
)
# CORD
cord_models = ['L-29', '810', '812']
for model in cord_models:
cursor.execute("SELECT id FROM brands WHERE name = ?", ("CORD",))
brand_id = cursor.fetchone()[0]
cursor.execute(
"INSERT OR IGNORE INTO models (brand_id, name) VALUES (?, ?)",
(brand_id, model)
)
# COLE
cole_models = ['SERIES 890', 'AERO EIGHT', 'SERIES 870', '8-50', '4-40', '6-50', '6-60',
'FOUR', 'SIX', 'FIFTY', 'FORTY', 'SIXTY', 'MODEL 30']
for model in cole_models:
cursor.execute("SELECT id FROM brands WHERE name = ?", ("COLE",))
brand_id = cursor.fetchone()[0]
cursor.execute(
"INSERT OR IGNORE INTO models (brand_id, name) VALUES (?, ?)",
(brand_id, model)
)
# CLEVELAND
cleveland_models = ['MODEL 31', 'MODEL 43', 'MODEL 42', 'MODEL 41', 'MODEL 40']
for model in cleveland_models:
cursor.execute("SELECT id FROM brands WHERE name = ?", ("CLEVELAND",))
brand_id = cursor.fetchone()[0]
cursor.execute(
"INSERT OR IGNORE INTO models (brand_id, name) VALUES (?, ?)",
(brand_id, model)
)
# CISITALIA
cisitalia_models = ['202']
for model in cisitalia_models:
cursor.execute("SELECT id FROM brands WHERE name = ?", ("CISITALIA",))
brand_id = cursor.fetchone()[0]
cursor.execute(
"INSERT OR IGNORE INTO models (brand_id, name) VALUES (?, ?)",
(brand_id, model)
)
# CHIREY
chirey_models = ['ARRIZO 8', 'TIGGO 4PRO', 'TIGGO 7PRO', 'TIGGO 8PRO', 'OMODA 5']
for model in chirey_models:
cursor.execute("SELECT id FROM brands WHERE name = ?", ("CHIREY",))
brand_id = cursor.fetchone()[0]
cursor.execute(
"INSERT OR IGNORE INTO models (brand_id, name) VALUES (?, ?)",
(brand_id, model)
)
print("Agregados modelos para todas las marcas")
# Datos históricos de años y motores para cada marca
historical_data = [
# CONTINENTAL
('CONTINENTAL', 'BEACON', 1934, '4cyl'),
('CONTINENTAL', 'ACE', 1933, '6cyl'),
('CONTINENTAL', 'BEACON', 1933, '4cyl'),
('CONTINENTAL', 'FLYER', 1933, '6cyl'),
# CORD
('CORD', 'L-29', 1933, '4.7L 289cid V8'),
('CORD', '812', 1936, '4.7L 289cid V8'),
('CORD', '810', 1936, '4.7L 289cid V8'),
('CORD', '812', 1936, '8cyl'),
('CORD', 'L-29', 1932, '4.9L 298cid L8'),
('CORD', 'L-29', 1931, '4.9L 298cid L8'),
('CORD', 'L-29', 1930, '4.9L 298cid L8'),
('CORD', 'L-29', 1929, '8cyl'),
# COLE
('COLE', 'SERIES 890', 1925, '8cyl'),
('COLE', 'SERIES 890', 1924, '8cyl'),
('COLE', 'SERIES 890', 1923, '8cyl'),
('COLE', 'AERO EIGHT', 1922, '8cyl'),
('COLE', 'AERO EIGHT', 1921, '8cyl'),
('COLE', 'AERO EIGHT', 1920, '8cyl'),
('COLE', 'SERIES 870', 1919, '8cyl'),
('COLE', 'SERIES 870', 1918, '8cyl'),
('COLE', '8-50', 1916, '8cyl'),
('COLE', '4-40', 1915, '4cyl'),
('COLE', '6-50', 1915, '6cyl'),
('COLE', '6-60', 1915, '6cyl'),
('COLE', 'FOUR', 1914, '4cyl'),
('COLE', 'SIX', 1914, '6cyl'),
('COLE', 'FIFTY', 1913, '4cyl'),
('COLE', 'FORTY', 1913, '4cyl'),
('COLE', 'SIXTY', 1913, '6cyl'),
('COLE', 'FORTY', 1912, '4cyl'),
('COLE', 'MODEL 30', 1911, '4cyl'),
('COLE', 'MODEL 30', 1910, '4cyl'),
# CLEVELAND
('CLEVELAND', 'MODEL 31', 1926, '6cyl'),
('CLEVELAND', 'MODEL 43', 1926, '6cyl'),
('CLEVELAND', 'MODEL 31', 1925, '6cyl'),
('CLEVELAND', 'MODEL 43', 1925, '6cyl'),
('CLEVELAND', 'MODEL 42', 1924, '6cyl'),
('CLEVELAND', 'MODEL 42', 1923, '6cyl'),
('CLEVELAND', 'MODEL 41', 1922, '6cyl'),
('CLEVELAND', 'MODEL 41', 1921, '6cyl'),
('CLEVELAND', 'MODEL 40', 1920, '6cyl'),
('CLEVELAND', 'MODEL 40', 1919, '6cyl'),
# CISITALIA
('CISITALIA', '202', 1952, '1.1L L4'),
('CISITALIA', '202', 1951, '1.1L L4'),
('CISITALIA', '202', 1950, '1.1L L4'),
('CISITALIA', '202', 1949, '1.1L 66cid L4'),
('CISITALIA', '202', 1948, '1.1L 66cid L4'),
('CISITALIA', '202', 1947, '1.1L 66cid L4'),
# CHIREY
('CHIREY', 'ARRIZO 8', 2025, '1.6L L4 Turbocharged'),
('CHIREY', 'TIGGO 4PRO', 2025, '1.5L L4 Turbocharged'),
('CHIREY', 'TIGGO 7PRO', 2025, '1.5L L4 Turbocharged'),
('CHIREY', 'TIGGO 8PRO', 2025, '1.6L L4 Turbocharged'),
('CHIREY', 'ARRIZO 8', 2024, '1.6L L4 Turbocharged'),
('CHIREY', 'TIGGO 4PRO', 2024, '1.5L L4 Turbocharged'),
('CHIREY', 'TIGGO 7PRO', 2024, '1.5L L4 ELECTRIC/GAS Turbocharged'),
('CHIREY', 'TIGGO 7PRO', 2024, '1.5L L4 Turbocharged'),
('CHIREY', 'TIGGO 8PRO', 2024, '1.6L L4 Turbocharged'),
('CHIREY', 'TIGGO 8PRO', 2024, '1.5L L4 ELECTRIC/GAS Turbocharged'),
('CHIREY', 'TIGGO 8PRO', 2024, '2.0L L4 Turbocharged'),
('CHIREY', 'OMODA 5', 2023, '1.5L L4'),
('CHIREY', 'TIGGO 4PRO', 2023, '1.5L L4'),
('CHIREY', 'TIGGO 7PRO', 2023, '1.5L L4'),
('CHIREY', 'TIGGO 8PRO', 2023, '1.5L L4 ELECTRIC/GAS Turbocharged'),
('CHIREY', 'TIGGO 8PRO', 2023, '1.6L L4 Turbocharged'),
('CHIREY', 'TIGGO 8PRO', 2023, '2.0L L4 Turbocharged')
]
# Insertar años
years = list(set([data[2] for data in historical_data])) # Obtener años únicos
for year in years:
cursor.execute("INSERT OR IGNORE INTO years (year) VALUES (?)", (year,))
print(f"Agregados {len(years)} años históricos")
# Insertar motores
engines = list(set([data[3] for data in historical_data])) # Obtener motores únicos
for engine in engines:
cursor.execute("INSERT OR IGNORE INTO engines (name) VALUES (?)", (engine,))
print(f"Agregados {len(engines)} motores históricos")
# Crear combinaciones modelo-año-motor
for brand_name, model_name, year, engine_name in historical_data:
# Obtener IDs
cursor.execute("SELECT id FROM brands WHERE name = ?", (brand_name,))
brand_result = cursor.fetchone()
if brand_result:
brand_id = brand_result[0]
else:
print(f"Advertencia: Marca {brand_name} no encontrada")
continue
cursor.execute("SELECT id FROM models WHERE brand_id = ? AND name = ?", (brand_id, model_name))
model_result = cursor.fetchone()
if model_result:
model_id = model_result[0]
else:
print(f"Advertencia: Modelo {model_name} no encontrado para la marca {brand_name}")
continue
cursor.execute("SELECT id FROM years WHERE year = ?", (year,))
year_result = cursor.fetchone()
if year_result:
year_id = year_result[0]
else:
print(f"Advertencia: Año {year} no encontrado")
continue
cursor.execute("SELECT id FROM engines WHERE name = ?", (engine_name,))
engine_result = cursor.fetchone()
if engine_result:
engine_id = engine_result[0]
else:
print(f"Advertencia: Motor {engine_name} no encontrado")
continue
# Insertar la combinación modelo-año-motor
cursor.execute(
"""INSERT OR REPLACE INTO model_year_engine
(model_id, year_id, engine_id) VALUES (?, ?, ?)""",
(model_id, year_id, engine_id)
)
conn.commit()
print(f"Se agregaron {len(historical_data)} combinaciones modelo-año-motor históricas")
print("Datos históricos agregados exitosamente a la base de datos!")
# Mostrar algunos resultados
print("\nAlgunos vehículos históricos agregados:")
cursor.execute("""
SELECT b.name, m.name, y.year, e.name
FROM model_year_engine mye
JOIN models m ON mye.model_id = m.id
JOIN brands b ON m.brand_id = b.id
JOIN years y ON mye.year_id = y.id
JOIN engines e ON mye.engine_id = e.id
ORDER BY y.year DESC
LIMIT 20
""")
results = cursor.fetchall()
for brand, model, year, engine in results:
print(f" {year} {brand} {model} - {engine}")
except Exception as e:
print(f"Error al agregar datos históricos: {e}")
conn.rollback()
finally:
conn.close()
if __name__ == "__main__":
add_historical_data()

127
check_and_remove_brands.py Normal file
View File

@@ -0,0 +1,127 @@
#!/usr/bin/env python3
"""
Script para eliminar marcas específicas y limpiar marcas sin vehículos
"""
import sqlite3
import os
def remove_brands_and_cleanup():
# Verificar que la base de datos exista
db_path = "vehicle_database/vehicle_database.db"
if not os.path.exists(db_path):
print(f"Error: Base de datos no encontrada en {db_path}")
return
conn = sqlite3.connect(db_path)
cursor = conn.cursor()
print("Verificando marcas en la base de datos...")
# Mostrar todas las marcas
cursor.execute("SELECT id, name FROM brands ORDER BY name")
all_brands = cursor.fetchall()
print("Todas las marcas en la base de datos:")
for brand_id, brand_name in all_brands:
print(f" ID: {brand_id}, Nombre: '{brand_name}'")
# Marcas a eliminar (ahora con las mayúsculas exactas según lo que vimos en el resultado anterior)
brands_to_remove = ['Ford', 'Toyota', 'Nissan', 'Honda', 'Chevrolet']
print(f"\nMarcas a eliminar: {', '.join(brands_to_remove)}")
try:
# Contar cuántos vehículos tenemos para estas marcas antes de eliminar
placeholders = ','.join(['?' for _ in brands_to_remove])
cursor.execute(f"""
SELECT COUNT(*)
FROM model_year_engine mye
JOIN models m ON mye.model_id = m.id
JOIN brands b ON m.brand_id = b.id
WHERE b.name IN ({placeholders})
""", brands_to_remove)
count_to_delete = cursor.fetchone()[0]
print(f"Se eliminarán {count_to_delete} vehículos de las marcas especificadas")
if count_to_delete > 0:
print("Procediendo con la eliminación...")
# Eliminar las combinaciones modelo-año-motor para los modelos de las marcas especificadas
cursor.execute(f"""
DELETE FROM model_year_engine
WHERE model_id IN (
SELECT m.id FROM models m
JOIN brands b ON m.brand_id = b.id
WHERE b.name IN ({placeholders})
)
""", brands_to_remove)
# Eliminar los modelos de las marcas especificadas
cursor.execute(f"""
DELETE FROM models
WHERE brand_id IN (
SELECT id FROM brands WHERE name IN ({placeholders})
)
""", brands_to_remove)
# Eliminar las marcas especificadas
cursor.execute(f"""
DELETE FROM brands
WHERE name IN ({placeholders})
""", brands_to_remove)
# Eliminar marcas que no tienen modelos asociados
print("Eliminando marcas sin vehículos...")
cursor.execute("""
DELETE FROM brands
WHERE id NOT IN (
SELECT DISTINCT brand_id FROM models
)
""")
conn.commit()
# Mostrar un resumen de la base de datos actualizada
print("\nResumen de la base de datos actualizada:")
# Contar vehículos restantes
cursor.execute("""
SELECT COUNT(*)
FROM model_year_engine mye
JOIN models m ON mye.model_id = m.id
JOIN brands b ON m.brand_id = b.id
""")
total_vehicles = cursor.fetchone()[0]
print(f"Total de vehículos restantes: {total_vehicles}")
# Contar marcas restantes
cursor.execute("SELECT COUNT(*) FROM brands")
total_brands = cursor.fetchone()[0]
print(f"Total de marcas restantes: {total_brands}")
# Mostrar marcas restantes
cursor.execute("SELECT name FROM brands ORDER BY name")
remaining_brands = cursor.fetchall()
print(f"Marcas restantes: {[brand[0] for brand in remaining_brands]}")
# Mostrar rango de años actual
cursor.execute("""
SELECT MIN(y.year), MAX(y.year)
FROM years y
JOIN model_year_engine mye ON y.id = mye.year_id
""")
min_year, max_year = cursor.fetchone()
if min_year and max_year:
print(f"Rango de años actual: {min_year} - {max_year}")
else:
print("No hay años con vehículos registrados")
except Exception as e:
print(f"Error al eliminar marcas y limpiar la base de datos: {e}")
conn.rollback()
finally:
conn.close()
if __name__ == "__main__":
remove_brands_and_cleanup()

79
dashboard/README.md Normal file
View File

@@ -0,0 +1,79 @@
# Vehicle Database Dashboard
A web-based dashboard for searching and filtering vehicle data from your database.
## Features
- Filter vehicles by brand, model, year, and engine
- Responsive web interface with Bootstrap
- Real-time filtering and search
- Detailed vehicle information display
- Modern UI with cards and badges
## Prerequisites
- Python 3.x
- Flask (installed via `sudo apt-get install python3-flask`)
- SQLite database with vehicle data (created in the vehicle_database directory)
## Setup
1. Make sure you have the vehicle database created in the `../vehicle_database/vehicle_database.db` path
2. Install Flask: `sudo apt-get install python3-flask`
3. Run the dashboard server: `python3 server.py`
## Usage
1. Start the server:
```bash
cd dashboard
python3 server.py
```
2. Open your web browser and navigate to `http://localhost:5000`
3. Use the filters on the left panel to search for vehicles:
- Select a brand from the dropdown
- Select a model (based on the selected brand)
- Select a year
- Select an engine type
- Click "Search Vehicles" to apply filters
4. The results will appear in the right panel with detailed information
## API Endpoints
The dashboard uses the following API endpoints:
- `GET /api/brands` - Get all vehicle brands
- `GET /api/models?brand=[brand]` - Get models for a specific brand
- `GET /api/years` - Get all years
- `GET /api/engines` - Get all engines
- `GET /api/vehicles?[filters]` - Search vehicles with optional filters
## File Structure
```
dashboard/
├── index.html # Main dashboard page
├── dashboard.js # Frontend JavaScript
├── server.py # Flask backend
├── requirements.txt # Python dependencies
├── start_dashboard.sh # Startup script
└── README.md # This file
```
## Customization
You can customize the dashboard by:
- Modifying the CSS styles in index.html
- Adding more filters in the JavaScript
- Changing the layout in index.html
- Adding more vehicle details in the display
## Troubleshooting
- If the server won't start, make sure the vehicle database exists
- If filters don't populate, check that the database has data
- If the page doesn't load, verify that Flask is installed correctly

440
dashboard/dashboard.js Normal file
View File

@@ -0,0 +1,440 @@
// Vehicle Dashboard JavaScript - Navegación por tarjetas
class VehicleDashboard {
constructor() {
this.currentView = 'brands'; // brands, models, vehicles
this.selectedBrand = null;
this.selectedModel = null;
this.allVehicles = [];
this.filteredVehicles = [];
this.stats = { brands: 0, models: 0, vehicles: 0 };
this.init();
}
async init() {
await this.loadStats();
await this.showBrands();
this.bindFilterEvents();
}
async loadStats() {
try {
const [brandsRes, vehiclesRes] = await Promise.all([
fetch('/api/brands'),
fetch('/api/vehicles')
]);
if (brandsRes.ok && vehiclesRes.ok) {
const brands = await brandsRes.json();
const vehicles = await vehiclesRes.json();
// Contar modelos únicos
const uniqueModels = new Set(vehicles.map(v => `${v.brand}-${v.model}`));
this.stats.brands = brands.length;
this.stats.models = uniqueModels.size;
this.stats.vehicles = vehicles.length;
document.getElementById('totalBrands').textContent = this.stats.brands;
document.getElementById('totalModels').textContent = this.stats.models;
document.getElementById('totalVehicles').textContent = this.stats.vehicles;
}
} catch (error) {
console.error('Error loading stats:', error);
}
}
updateBreadcrumb() {
const breadcrumb = document.getElementById('breadcrumb');
let html = '';
if (this.currentView === 'brands') {
html = `<li class="breadcrumb-item active"><i class="fas fa-home"></i> Marcas</li>`;
} else if (this.currentView === 'models') {
html = `
<li class="breadcrumb-item">
<a href="#" onclick="dashboard.goToBrands(); return false;">
<i class="fas fa-home"></i> Marcas
</a>
</li>
<li class="breadcrumb-item active">${this.selectedBrand}</li>
`;
} else if (this.currentView === 'vehicles') {
html = `
<li class="breadcrumb-item">
<a href="#" onclick="dashboard.goToBrands(); return false;">
<i class="fas fa-home"></i> Marcas
</a>
</li>
<li class="breadcrumb-item">
<a href="#" onclick="dashboard.goToModels('${this.selectedBrand}'); return false;">
${this.selectedBrand}
</a>
</li>
<li class="breadcrumb-item active">${this.selectedModel}</li>
`;
}
breadcrumb.innerHTML = html;
}
async showBrands() {
this.currentView = 'brands';
this.selectedBrand = null;
this.selectedModel = null;
this.updateBreadcrumb();
this.hideFilters();
const container = document.getElementById('mainContent');
container.innerHTML = `
<div class="loading-state">
<i class="fas fa-spinner fa-spin"></i>
<h4>Cargando marcas...</h4>
</div>
`;
try {
const [brandsRes, vehiclesRes] = await Promise.all([
fetch('/api/brands'),
fetch('/api/vehicles')
]);
if (!brandsRes.ok || !vehiclesRes.ok) {
throw new Error('Error al cargar datos');
}
const brands = await brandsRes.json();
const vehicles = await vehiclesRes.json();
// Contar modelos y vehículos por marca
const brandStats = {};
brands.forEach(brand => {
brandStats[brand] = { models: new Set(), vehicles: 0 };
});
vehicles.forEach(v => {
if (brandStats[v.brand]) {
brandStats[v.brand].models.add(v.model);
brandStats[v.brand].vehicles++;
}
});
if (brands.length === 0) {
container.innerHTML = `
<div class="empty-state">
<i class="fas fa-car"></i>
<h4>No hay marcas disponibles</h4>
<p>Agrega algunas marcas a la base de datos</p>
</div>
`;
return;
}
container.innerHTML = `<div class="content-grid brands-grid">
${brands.map(brand => `
<div class="brand-card" onclick="dashboard.goToModels('${brand}')">
<div class="brand-icon">
<i class="fas fa-car"></i>
</div>
<div class="brand-name">${brand}</div>
<div class="brand-count">
${brandStats[brand].models.size} modelos
</div>
<div class="brand-count">
${brandStats[brand].vehicles} vehículos
</div>
</div>
`).join('')}
</div>`;
} catch (error) {
console.error('Error:', error);
container.innerHTML = `
<div class="empty-state">
<i class="fas fa-exclamation-triangle"></i>
<h4>Error al cargar marcas</h4>
<p>${error.message}</p>
</div>
`;
}
}
async goToModels(brand) {
this.currentView = 'models';
this.selectedBrand = brand;
this.selectedModel = null;
this.updateBreadcrumb();
this.hideFilters();
const container = document.getElementById('mainContent');
container.innerHTML = `
<div class="loading-state">
<i class="fas fa-spinner fa-spin"></i>
<h4>Cargando modelos de ${brand}...</h4>
</div>
`;
try {
const [modelsRes, vehiclesRes] = await Promise.all([
fetch(`/api/models?brand=${encodeURIComponent(brand)}`),
fetch(`/api/vehicles?brand=${encodeURIComponent(brand)}`)
]);
if (!modelsRes.ok || !vehiclesRes.ok) {
throw new Error('Error al cargar datos');
}
const models = await modelsRes.json();
const vehicles = await vehiclesRes.json();
// Contar vehículos y años por modelo
const modelStats = {};
models.forEach(model => {
modelStats[model] = { years: new Set(), vehicles: 0, engines: new Set() };
});
vehicles.forEach(v => {
if (modelStats[v.model]) {
modelStats[v.model].years.add(v.year);
modelStats[v.model].vehicles++;
modelStats[v.model].engines.add(v.engine);
}
});
if (models.length === 0) {
container.innerHTML = `
<div class="empty-state">
<i class="fas fa-car-side"></i>
<h4>No hay modelos para ${brand}</h4>
<p>Esta marca no tiene modelos registrados</p>
<button class="btn btn-back mt-3" onclick="dashboard.goToBrands()">
<i class="fas fa-arrow-left"></i> Volver a marcas
</button>
</div>
`;
return;
}
container.innerHTML = `<div class="content-grid models-grid">
${models.map(model => {
const stats = modelStats[model];
const yearsArray = Array.from(stats.years).sort((a, b) => b - a);
const yearRange = yearsArray.length > 0
? (yearsArray.length > 1
? `${yearsArray[yearsArray.length - 1]} - ${yearsArray[0]}`
: `${yearsArray[0]}`)
: 'N/A';
return `
<div class="model-card" onclick="dashboard.goToVehicles('${brand}', '${model}')">
<div class="model-name">${model}</div>
<div class="model-info">
<i class="fas fa-calendar-alt"></i> ${yearRange}
</div>
<div class="model-info">
<i class="fas fa-cogs"></i> ${stats.engines.size} motores
</div>
<div class="model-info">
<i class="fas fa-list"></i> ${stats.vehicles} variantes
</div>
</div>
`;
}).join('')}
</div>`;
} catch (error) {
console.error('Error:', error);
container.innerHTML = `
<div class="empty-state">
<i class="fas fa-exclamation-triangle"></i>
<h4>Error al cargar modelos</h4>
<p>${error.message}</p>
<button class="btn btn-back mt-3" onclick="dashboard.goToBrands()">
<i class="fas fa-arrow-left"></i> Volver a marcas
</button>
</div>
`;
}
}
async goToVehicles(brand, model) {
this.currentView = 'vehicles';
this.selectedBrand = brand;
this.selectedModel = model;
this.updateBreadcrumb();
this.showFilters();
const container = document.getElementById('mainContent');
container.innerHTML = `
<div class="loading-state">
<i class="fas fa-spinner fa-spin"></i>
<h4>Cargando vehículos...</h4>
</div>
`;
try {
const response = await fetch(
`/api/vehicles?brand=${encodeURIComponent(brand)}&model=${encodeURIComponent(model)}`
);
if (!response.ok) {
throw new Error('Error al cargar vehículos');
}
this.allVehicles = await response.json();
this.filteredVehicles = [...this.allVehicles];
// Poblar filtros
await this.populateFilters(brand, model);
this.displayVehicles();
} catch (error) {
console.error('Error:', error);
container.innerHTML = `
<div class="empty-state">
<i class="fas fa-exclamation-triangle"></i>
<h4>Error al cargar vehículos</h4>
<p>${error.message}</p>
<button class="btn btn-back mt-3" onclick="dashboard.goToModels('${brand}')">
<i class="fas fa-arrow-left"></i> Volver a modelos
</button>
</div>
`;
}
}
async populateFilters(brand, model) {
try {
const [yearsRes, enginesRes] = await Promise.all([
fetch(`/api/years?brand=${encodeURIComponent(brand)}&model=${encodeURIComponent(model)}`),
fetch(`/api/engines?brand=${encodeURIComponent(brand)}&model=${encodeURIComponent(model)}`)
]);
if (yearsRes.ok) {
const years = await yearsRes.json();
const yearFilter = document.getElementById('yearFilter');
yearFilter.innerHTML = '<option value="">Todos los años</option>';
years.forEach(year => {
yearFilter.innerHTML += `<option value="${year}">${year}</option>`;
});
}
if (enginesRes.ok) {
const engines = await enginesRes.json();
const engineFilter = document.getElementById('engineFilter');
engineFilter.innerHTML = '<option value="">Todos los motores</option>';
engines.forEach(engine => {
engineFilter.innerHTML += `<option value="${engine}">${engine}</option>`;
});
}
} catch (error) {
console.error('Error populating filters:', error);
}
}
bindFilterEvents() {
document.getElementById('yearFilter').addEventListener('change', () => {
this.applyFilters();
});
document.getElementById('engineFilter').addEventListener('change', () => {
this.applyFilters();
});
}
applyFilters() {
const year = document.getElementById('yearFilter').value;
const engine = document.getElementById('engineFilter').value;
this.filteredVehicles = this.allVehicles.filter(v => {
return (!year || v.year.toString() === year) &&
(!engine || v.engine === engine);
});
this.displayVehicles();
}
displayVehicles() {
const container = document.getElementById('mainContent');
const resultCount = document.getElementById('resultCount');
resultCount.textContent = `${this.filteredVehicles.length} resultado${this.filteredVehicles.length !== 1 ? 's' : ''}`;
if (this.filteredVehicles.length === 0) {
container.innerHTML = `
<div class="empty-state">
<i class="fas fa-car"></i>
<h4>No se encontraron vehículos</h4>
<p>Intenta ajustar los filtros</p>
</div>
`;
return;
}
container.innerHTML = `<div class="content-grid vehicles-grid">
${this.filteredVehicles.map(v => `
<div class="vehicle-card">
<div class="vehicle-header">
<div class="vehicle-title">${v.year} ${v.brand} ${v.model}</div>
<div class="vehicle-engine">${v.engine}</div>
</div>
<div class="vehicle-body">
<div class="vehicle-specs">
<div class="spec-item">
<i class="fas fa-gas-pump"></i>
<div class="spec-value">${v.fuel_type || 'N/A'}</div>
</div>
<div class="spec-item">
<i class="fas fa-tachometer-alt"></i>
<div class="spec-value">${v.power_hp || 0} HP</div>
</div>
<div class="spec-item">
<i class="fas fa-cogs"></i>
<div class="spec-value">${v.transmission || 'N/A'}</div>
</div>
<div class="spec-item">
<i class="fas fa-road"></i>
<div class="spec-value">${v.drivetrain || 'N/A'}</div>
</div>
<div class="spec-item">
<i class="fas fa-cube"></i>
<div class="spec-value">${v.cylinders || 0} cil.</div>
</div>
<div class="spec-item">
<i class="fas fa-oil-can"></i>
<div class="spec-value">${v.displacement_cc || 0} cc</div>
</div>
</div>
${v.trim_level && v.trim_level !== 'unknown' ? `
<div class="mt-2 text-center">
<span class="badge bg-primary">${v.trim_level}</span>
</div>
` : ''}
</div>
</div>
`).join('')}
</div>`;
}
goToBrands() {
this.showBrands();
}
showFilters() {
document.getElementById('filtersBar').style.display = 'block';
// Reset filters
document.getElementById('yearFilter').value = '';
document.getElementById('engineFilter').value = '';
}
hideFilters() {
document.getElementById('filtersBar').style.display = 'none';
}
}
// Initialize dashboard globally
let dashboard;
document.addEventListener('DOMContentLoaded', () => {
dashboard = new VehicleDashboard();
});

367
dashboard/index.html Normal file
View File

@@ -0,0 +1,367 @@
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Base de Datos de Vehículos</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
<style>
:root {
--primary-color: #2c3e50;
--secondary-color: #3498db;
--accent-color: #e74c3c;
--bg-color: #ecf0f1;
}
body {
background-color: var(--bg-color);
min-height: 100vh;
}
.dashboard-header {
background: linear-gradient(135deg, var(--primary-color), #1a252f);
color: white;
padding: 2rem 0;
margin-bottom: 2rem;
}
.breadcrumb-nav {
background: white;
padding: 1rem 1.5rem;
border-radius: 10px;
margin-bottom: 1.5rem;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
.breadcrumb-nav .breadcrumb {
margin-bottom: 0;
}
.breadcrumb-nav .breadcrumb-item a {
color: var(--secondary-color);
text-decoration: none;
font-weight: 500;
}
.breadcrumb-nav .breadcrumb-item a:hover {
color: var(--primary-color);
}
.breadcrumb-nav .breadcrumb-item.active {
color: var(--primary-color);
font-weight: 600;
}
/* Tarjetas de marcas */
.brand-card {
background: white;
border-radius: 15px;
padding: 2rem;
text-align: center;
transition: all 0.3s ease;
cursor: pointer;
border: 2px solid transparent;
height: 100%;
}
.brand-card:hover {
transform: translateY(-10px);
box-shadow: 0 15px 30px rgba(0,0,0,0.15);
border-color: var(--secondary-color);
}
.brand-card .brand-icon {
width: 80px;
height: 80px;
background: linear-gradient(135deg, var(--secondary-color), #2980b9);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
margin: 0 auto 1rem;
font-size: 2rem;
color: white;
}
.brand-card .brand-name {
font-size: 1.3rem;
font-weight: 700;
color: var(--primary-color);
margin-bottom: 0.5rem;
}
.brand-card .brand-count {
color: #7f8c8d;
font-size: 0.9rem;
}
.brand-card .brand-country {
font-size: 0.85rem;
color: #95a5a6;
margin-top: 0.5rem;
}
/* Tarjetas de modelos */
.model-card {
background: white;
border-radius: 12px;
padding: 1.5rem;
transition: all 0.3s ease;
cursor: pointer;
border: 2px solid transparent;
height: 100%;
}
.model-card:hover {
transform: translateY(-5px);
box-shadow: 0 10px 25px rgba(0,0,0,0.12);
border-color: var(--secondary-color);
}
.model-card .model-name {
font-size: 1.2rem;
font-weight: 600;
color: var(--primary-color);
margin-bottom: 0.5rem;
}
.model-card .model-info {
color: #7f8c8d;
font-size: 0.9rem;
}
/* Tarjetas de vehículos */
.vehicle-card {
background: white;
border-radius: 12px;
overflow: hidden;
transition: all 0.3s ease;
height: 100%;
}
.vehicle-card:hover {
transform: translateY(-5px);
box-shadow: 0 10px 25px rgba(0,0,0,0.12);
}
.vehicle-header {
background: linear-gradient(135deg, var(--primary-color), #1a252f);
color: white;
padding: 1.2rem;
}
.vehicle-header .vehicle-title {
font-size: 1.1rem;
font-weight: 600;
margin-bottom: 0.3rem;
}
.vehicle-header .vehicle-engine {
font-size: 0.9rem;
opacity: 0.9;
}
.vehicle-body {
padding: 1rem;
}
.vehicle-specs {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 0.8rem;
}
.spec-item {
background: var(--bg-color);
padding: 0.6rem;
border-radius: 8px;
text-align: center;
font-size: 0.85rem;
}
.spec-item i {
color: var(--secondary-color);
margin-bottom: 0.3rem;
display: block;
}
.spec-item .spec-value {
font-weight: 600;
color: var(--primary-color);
}
/* Filtros en vista de vehículos */
.filters-bar {
background: white;
padding: 1rem 1.5rem;
border-radius: 10px;
margin-bottom: 1.5rem;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
.filters-bar .form-select {
border-radius: 8px;
}
/* Grid de contenido */
.content-grid {
display: grid;
gap: 1.5rem;
}
.content-grid.brands-grid {
grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
}
.content-grid.models-grid {
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
}
.content-grid.vehicles-grid {
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
}
/* Estados */
.loading-state, .empty-state {
text-align: center;
padding: 4rem 2rem;
color: #7f8c8d;
}
.loading-state i, .empty-state i {
font-size: 4rem;
margin-bottom: 1rem;
color: #bdc3c7;
}
/* Botón volver */
.btn-back {
background: var(--secondary-color);
color: white;
border: none;
padding: 0.5rem 1.5rem;
border-radius: 8px;
font-weight: 500;
transition: all 0.3s;
}
.btn-back:hover {
background: #2980b9;
color: white;
}
/* Estadísticas */
.stats-bar {
display: flex;
gap: 2rem;
flex-wrap: wrap;
}
.stat-item {
text-align: center;
}
.stat-item .stat-number {
font-size: 2rem;
font-weight: 700;
color: white;
}
.stat-item .stat-label {
font-size: 0.9rem;
opacity: 0.8;
}
@media (max-width: 768px) {
.content-grid.brands-grid {
grid-template-columns: repeat(2, 1fr);
}
.stats-bar {
justify-content: center;
}
}
@media (max-width: 480px) {
.content-grid.brands-grid {
grid-template-columns: 1fr;
}
}
</style>
</head>
<body>
<div class="dashboard-header">
<div class="container">
<div class="row align-items-center">
<div class="col-md-6">
<h1><i class="fas fa-car-side"></i> Base de Datos de Vehículos</h1>
<p class="lead mb-0">Explora vehículos por marca, modelo y especificaciones</p>
</div>
<div class="col-md-6">
<div class="stats-bar justify-content-md-end">
<div class="stat-item">
<div class="stat-number" id="totalBrands">0</div>
<div class="stat-label">Marcas</div>
</div>
<div class="stat-item">
<div class="stat-number" id="totalModels">0</div>
<div class="stat-label">Modelos</div>
</div>
<div class="stat-item">
<div class="stat-number" id="totalVehicles">0</div>
<div class="stat-label">Vehículos</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="container">
<!-- Breadcrumb navegación -->
<div class="breadcrumb-nav" id="breadcrumbNav">
<nav aria-label="breadcrumb">
<ol class="breadcrumb" id="breadcrumb">
<li class="breadcrumb-item active">
<i class="fas fa-home"></i> Marcas
</li>
</ol>
</nav>
</div>
<!-- Barra de filtros (solo visible en vista de vehículos) -->
<div class="filters-bar" id="filtersBar" style="display: none;">
<div class="row g-3 align-items-center">
<div class="col-auto">
<label class="col-form-label fw-bold">Filtrar por:</label>
</div>
<div class="col-md-3">
<select id="yearFilter" class="form-select">
<option value="">Todos los años</option>
</select>
</div>
<div class="col-md-3">
<select id="engineFilter" class="form-select">
<option value="">Todos los motores</option>
</select>
</div>
<div class="col-auto">
<span id="resultCount" class="badge bg-secondary fs-6">0 resultados</span>
</div>
</div>
</div>
<!-- Contenedor principal -->
<div id="mainContent">
<div class="loading-state">
<i class="fas fa-spinner fa-spin"></i>
<h4>Cargando...</h4>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<script src="dashboard.js"></script>
</body>
</html>

View File

@@ -0,0 +1 @@
Flask==2.3.3

248
dashboard/server.py Normal file
View File

@@ -0,0 +1,248 @@
from flask import Flask, render_template, jsonify, request, send_from_directory
import sqlite3
import os
app = Flask(__name__, static_folder='.')
# Database path - adjust as needed
DATABASE_PATH = '../vehicle_database/vehicle_database.db'
def get_db_connection():
"""Get a connection to the vehicle database"""
conn = sqlite3.connect(DATABASE_PATH)
conn.row_factory = sqlite3.Row # This enables column access by name
return conn
def get_all_brands():
"""Get all unique brands from the database"""
conn = get_db_connection()
cursor = conn.cursor()
cursor.execute("SELECT DISTINCT name FROM brands ORDER BY name")
brands = [row['name'] for row in cursor.fetchall()]
conn.close()
return brands
def get_all_years():
"""Get all unique years from the database"""
conn = get_db_connection()
cursor = conn.cursor()
cursor.execute("SELECT DISTINCT year FROM years ORDER BY year DESC")
years = [row['year'] for row in cursor.fetchall()]
conn.close()
return years
def get_all_engines():
"""Get all unique engines from the database"""
conn = get_db_connection()
cursor = conn.cursor()
cursor.execute("SELECT DISTINCT name FROM engines ORDER BY name")
engines = [row['name'] for row in cursor.fetchall()]
conn.close()
return engines
def get_models_by_brand(brand_name=None):
"""Get all models, optionally filtered by brand"""
conn = get_db_connection()
cursor = conn.cursor()
if brand_name:
cursor.execute("""
SELECT DISTINCT m.name
FROM models m
JOIN brands b ON m.brand_id = b.id
WHERE b.name = ?
ORDER BY m.name
""", (brand_name,))
else:
cursor.execute("SELECT DISTINCT name FROM models ORDER BY name")
models = [row['name'] for row in cursor.fetchall()]
conn.close()
return models
def search_vehicles(brand=None, model=None, year=None, engine=None):
"""Search for vehicles based on filters"""
conn = get_db_connection()
cursor = conn.cursor()
query = """
SELECT
b.name AS brand,
m.name AS model,
y.year,
e.name AS engine,
e.power_hp,
e.displacement_cc,
e.cylinders,
e.fuel_type,
mye.trim_level,
mye.drivetrain,
mye.transmission
FROM model_year_engine mye
JOIN models m ON mye.model_id = m.id
JOIN brands b ON m.brand_id = b.id
JOIN years y ON mye.year_id = y.id
JOIN engines e ON mye.engine_id = e.id
WHERE 1=1
"""
params = []
if brand:
query += " AND b.name = ?"
params.append(brand)
if model:
query += " AND m.name = ?"
params.append(model)
if year:
query += " AND y.year = ?"
params.append(int(year))
if engine:
query += " AND e.name = ?"
params.append(engine)
query += " ORDER BY b.name, m.name, y.year"
cursor.execute(query, params)
results = cursor.fetchall()
conn.close()
# Convert to list of dictionaries
vehicles = []
for row in results:
vehicle = {
'brand': row['brand'],
'model': row['model'],
'year': row['year'],
'engine': row['engine'],
'power_hp': row['power_hp'] or 0,
'displacement_cc': row['displacement_cc'] or 0,
'cylinders': row['cylinders'] or 0,
'fuel_type': row['fuel_type'] or 'unknown',
'trim_level': row['trim_level'] or 'unknown',
'drivetrain': row['drivetrain'] or 'unknown',
'transmission': row['transmission'] or 'unknown'
}
vehicles.append(vehicle)
return vehicles
@app.route('/')
def index():
"""Serve the main dashboard page"""
return send_from_directory('.', 'index.html')
@app.route('/<path:path>')
def static_files(path):
"""Serve static files"""
return send_from_directory('.', path)
@app.route('/api/brands')
def api_brands():
"""API endpoint to get all brands"""
brands = get_all_brands()
return jsonify(brands)
@app.route('/api/years')
def api_years():
"""API endpoint to get years, optionally filtered by brand and/or model"""
brand = request.args.get('brand')
model = request.args.get('model')
conn = get_db_connection()
cursor = conn.cursor()
query = """
SELECT DISTINCT y.year
FROM years y
JOIN model_year_engine mye ON y.id = mye.year_id
JOIN models m ON mye.model_id = m.id
JOIN brands b ON m.brand_id = b.id
WHERE 1=1
"""
params = []
if brand:
query += " AND b.name = ?"
params.append(brand)
if model:
query += " AND m.name = ?"
params.append(model)
query += " ORDER BY y.year DESC"
cursor.execute(query, params)
results = cursor.fetchall()
conn.close()
years = [row['year'] for row in results]
return jsonify(years)
@app.route('/api/engines')
def api_engines():
"""API endpoint to get engines, optionally filtered by brand, model, and/or year"""
brand = request.args.get('brand')
model = request.args.get('model')
year = request.args.get('year')
conn = get_db_connection()
cursor = conn.cursor()
query = """
SELECT DISTINCT e.name
FROM engines e
JOIN model_year_engine mye ON e.id = mye.engine_id
JOIN models m ON mye.model_id = m.id
JOIN brands b ON m.brand_id = b.id
JOIN years y ON mye.year_id = y.id
WHERE 1=1
"""
params = []
if brand:
query += " AND b.name = ?"
params.append(brand)
if model:
query += " AND m.name = ?"
params.append(model)
if year:
query += " AND y.year = ?"
params.append(int(year))
query += " ORDER BY e.name"
cursor.execute(query, params)
results = cursor.fetchall()
conn.close()
engines = [row['name'] for row in results]
return jsonify(engines)
@app.route('/api/models')
def api_models():
"""API endpoint to get models, optionally filtered by brand"""
brand = request.args.get('brand')
models = get_models_by_brand(brand)
return jsonify(models)
@app.route('/api/vehicles')
def api_vehicles():
"""API endpoint to search for vehicles"""
brand = request.args.get('brand')
model = request.args.get('model')
year = request.args.get('year')
engine = request.args.get('engine')
vehicles = search_vehicles(brand, model, year, engine)
return jsonify(vehicles)
if __name__ == '__main__':
# Check if database exists
if not os.path.exists(DATABASE_PATH):
print(f"Database not found at {DATABASE_PATH}")
print("Please make sure the vehicle database is created first.")
exit(1)
print("Starting Vehicle Dashboard Server...")
print("Visit http://localhost:5000 to access the dashboard locally")
print("Visit http://192.168.10.198:5000 to access the dashboard from other computers on the network")
app.run(debug=True, host='0.0.0.0', port=5000)

30
dashboard/start_dashboard.sh Executable file
View File

@@ -0,0 +1,30 @@
#!/bin/bash
# Startup script for Vehicle Dashboard
echo "Vehicle Dashboard Startup Script"
echo "================================"
# Check if the vehicle database exists
if [ ! -f "../vehicle_database/vehicle_database.db" ]; then
echo "Error: Vehicle database not found!"
echo "Please make sure you have created the vehicle database first."
exit 1
fi
echo "Vehicle database found."
# Check if Flask is available
if python3 -c "import flask" &> /dev/null; then
echo "Flask is available."
else
echo "Installing Flask..."
sudo apt-get update
sudo apt-get install -y python3-flask
fi
echo "Starting Vehicle Dashboard Server..."
echo "Access the dashboard at: http://localhost:5000"
echo "Press Ctrl+C to stop the server."
cd /home/Autopartes/dashboard
python3 server.py

270
docs/API.md Normal file
View File

@@ -0,0 +1,270 @@
# API Reference - Autoparts DB
Documentación completa de la API REST del sistema Autoparts DB.
## Base URL
```
http://localhost:5000/api
```
## Endpoints
### GET /api/brands
Obtiene la lista de todas las marcas de vehículos disponibles.
**Request:**
```bash
curl http://localhost:5000/api/brands
```
**Response:**
```json
{
"brands": [
{
"id": 1,
"name": "Toyota",
"country": "Japan",
"founded_year": 1937
},
{
"id": 2,
"name": "Honda",
"country": "Japan",
"founded_year": 1948
}
]
}
```
---
### GET /api/models
Obtiene modelos de vehículos, opcionalmente filtrados por marca.
**Parámetros:**
| Parámetro | Tipo | Requerido | Descripción |
|-----------|------|-----------|-------------|
| brand | string | No | Nombre de la marca para filtrar |
**Request:**
```bash
# Todos los modelos
curl http://localhost:5000/api/models
# Modelos de Toyota
curl "http://localhost:5000/api/models?brand=Toyota"
```
**Response:**
```json
{
"models": [
{
"id": 1,
"name": "Camry",
"brand": "Toyota",
"body_type": "Sedan",
"generation": "XV70",
"production_start_year": 2017,
"production_end_year": null
}
]
}
```
---
### GET /api/years
Obtiene todos los años disponibles en la base de datos.
**Request:**
```bash
curl http://localhost:5000/api/years
```
**Response:**
```json
{
"years": [1990, 1991, 1992, ..., 2024, 2025]
}
```
---
### GET /api/engines
Obtiene todos los motores disponibles.
**Request:**
```bash
curl http://localhost:5000/api/engines
```
**Response:**
```json
{
"engines": [
{
"id": 1,
"name": "2.5L 4-Cylinder",
"displacement_cc": 2500,
"cylinders": 4,
"fuel_type": "Gasoline",
"power_hp": 203,
"torque_nm": 250,
"engine_code": "A25A-FKS"
}
]
}
```
---
### GET /api/vehicles
Búsqueda de vehículos con múltiples filtros.
**Parámetros:**
| Parámetro | Tipo | Requerido | Descripción |
|-----------|------|-----------|-------------|
| brand | string | No | Marca del vehículo |
| model | string | No | Modelo del vehículo |
| year | integer | No | Año del vehículo |
| engine | string | No | Nombre/código del motor |
| limit | integer | No | Límite de resultados (default: 100) |
**Request:**
```bash
# Búsqueda completa
curl "http://localhost:5000/api/vehicles?brand=Toyota&model=Camry&year=2020"
# Solo por marca
curl "http://localhost:5000/api/vehicles?brand=Honda"
# Con límite
curl "http://localhost:5000/api/vehicles?brand=Ford&limit=50"
```
**Response:**
```json
{
"vehicles": [
{
"brand": "Toyota",
"model": "Camry",
"year": 2020,
"body_type": "Sedan",
"generation": "XV70",
"engine_name": "2.5L 4-Cylinder",
"displacement_cc": 2500,
"cylinders": 4,
"fuel_type": "Gasoline",
"power_hp": 203,
"torque_nm": 250,
"engine_code": "A25A-FKS",
"trim_level": "LE",
"drivetrain": "FWD",
"transmission": "8-Speed Automatic"
}
],
"total": 1
}
```
---
## Códigos de Respuesta
| Código | Descripción |
|--------|-------------|
| 200 | OK - Solicitud exitosa |
| 400 | Bad Request - Parámetros inválidos |
| 404 | Not Found - Recurso no encontrado |
| 500 | Internal Server Error - Error del servidor |
## Manejo de Errores
Todas las respuestas de error siguen el formato:
```json
{
"error": "Descripción del error",
"code": 400
}
```
## Ejemplos de Uso
### Python
```python
import requests
BASE_URL = "http://localhost:5000/api"
# Obtener marcas
response = requests.get(f"{BASE_URL}/brands")
brands = response.json()["brands"]
# Buscar vehículos
params = {
"brand": "Toyota",
"year": 2020,
"limit": 50
}
response = requests.get(f"{BASE_URL}/vehicles", params=params)
vehicles = response.json()["vehicles"]
```
### JavaScript
```javascript
const BASE_URL = 'http://localhost:5000/api';
// Obtener marcas
async function getBrands() {
const response = await fetch(`${BASE_URL}/brands`);
const data = await response.json();
return data.brands;
}
// Buscar vehículos
async function searchVehicles(filters) {
const params = new URLSearchParams(filters);
const response = await fetch(`${BASE_URL}/vehicles?${params}`);
const data = await response.json();
return data.vehicles;
}
// Uso
const vehicles = await searchVehicles({
brand: 'Toyota',
year: 2020
});
```
### cURL
```bash
# Obtener todas las marcas
curl -X GET http://localhost:5000/api/brands
# Buscar vehículos Toyota del 2020
curl -X GET "http://localhost:5000/api/vehicles?brand=Toyota&year=2020"
# Obtener modelos de Honda
curl -X GET "http://localhost:5000/api/models?brand=Honda"
```
## Rate Limiting
Actualmente no hay límites de tasa implementados. Para uso en producción, se recomienda implementar rate limiting.
## CORS
El servidor está configurado para aceptar solicitudes desde cualquier origen (CORS habilitado). Para producción, configure los orígenes permitidos apropiadamente.

425
docs/DATABASE.md Normal file
View File

@@ -0,0 +1,425 @@
# Documentación de Base de Datos - Autoparts DB
## Resumen
La base de datos utiliza SQLite 3 y está diseñada con un esquema normalizado para gestionar información de vehículos de manera eficiente.
**Archivo:** `vehicle_database/vehicle_database.db`
## Estadísticas Actuales
| Tabla | Registros |
|-------|-----------|
| brands | 12 |
| models | 10,923 |
| engines | 10,919 |
| years | ~35 |
| model_year_engine | 12,075 |
---
## Diagrama Entidad-Relación
```
┌──────────────┐
│ brands │
├──────────────┤
│ id (PK) │
│ name │
│ country │
│ founded_year │
│ created_at │
└──────┬───────┘
│ 1:N
┌──────▼───────────────┐
│ models │
├──────────────────────┤
│ id (PK) │
│ brand_id (FK) │───────────────────────┐
│ name │ │
│ body_type │ │
│ generation │ │
│ production_start_year│ │
│ production_end_year │ │
│ created_at │ │
└──────────────────────┘ │
┌──────────────────────┐ │
│ years │ │
├──────────────────────┤ │
│ id (PK) │───────────────┐ │
│ year │ │ │
│ created_at │ │ │
└──────────────────────┘ │ │
│ │
┌──────────────────────┐ │ │
│ engines │ │ │
├──────────────────────┤ │ │
│ id (PK) │───────┐ │ │
│ name │ │ │ │
│ displacement_cc │ │ │ │
│ cylinders │ │ │ │
│ fuel_type │ │ │ │
│ power_hp │ │ │ │
│ torque_nm │ │ │ │
│ engine_code │ │ │ │
│ created_at │ │ │ │
└──────────────────────┘ │ │ │
│ │ │
│ N:1 │ N:1 │ N:1
│ │ │
┌──────▼───────▼───────▼──────┐
│ model_year_engine │
├─────────────────────────────┤
│ id (PK) │
│ model_id (FK) │
│ year_id (FK) │
│ engine_id (FK) │
│ trim_level │
│ drivetrain │
│ transmission │
│ created_at │
└─────────────────────────────┘
```
---
## Definición de Tablas
### Tabla: brands
Almacena información de los fabricantes de vehículos.
```sql
CREATE TABLE brands (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL UNIQUE,
country TEXT,
founded_year INTEGER,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
```
| Campo | Tipo | Restricciones | Descripción |
|-------|------|---------------|-------------|
| id | INTEGER | PK, AUTO | Identificador único |
| name | TEXT | NOT NULL, UNIQUE | Nombre de la marca |
| country | TEXT | - | País de origen |
| founded_year | INTEGER | - | Año de fundación |
| created_at | TIMESTAMP | DEFAULT NOW | Fecha de creación |
**Índices:**
- `idx_brands_name` en `name`
---
### Tabla: models
Almacena información de los modelos de vehículos.
```sql
CREATE TABLE models (
id INTEGER PRIMARY KEY AUTOINCREMENT,
brand_id INTEGER NOT NULL,
name TEXT NOT NULL,
body_type TEXT,
generation TEXT,
production_start_year INTEGER,
production_end_year INTEGER,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (brand_id) REFERENCES brands(id),
UNIQUE(brand_id, name, generation)
);
```
| Campo | Tipo | Restricciones | Descripción |
|-------|------|---------------|-------------|
| id | INTEGER | PK, AUTO | Identificador único |
| brand_id | INTEGER | FK, NOT NULL | Referencia a brands |
| name | TEXT | NOT NULL | Nombre del modelo |
| body_type | TEXT | - | Tipo de carrocería |
| generation | TEXT | - | Generación del modelo |
| production_start_year | INTEGER | - | Año inicio producción |
| production_end_year | INTEGER | - | Año fin producción |
| created_at | TIMESTAMP | DEFAULT NOW | Fecha de creación |
**Valores de body_type:**
- Sedan, Coupe, Hatchback, SUV, Crossover, Truck, Van, Wagon, Convertible
**Índices:**
- `idx_models_brand_id` en `brand_id`
- `idx_models_name` en `name`
---
### Tabla: engines
Almacena especificaciones técnicas de los motores.
```sql
CREATE TABLE engines (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
displacement_cc INTEGER,
cylinders INTEGER,
fuel_type TEXT,
power_hp INTEGER,
torque_nm INTEGER,
engine_code TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE(name, engine_code)
);
```
| Campo | Tipo | Restricciones | Descripción |
|-------|------|---------------|-------------|
| id | INTEGER | PK, AUTO | Identificador único |
| name | TEXT | NOT NULL | Nombre descriptivo |
| displacement_cc | INTEGER | - | Cilindrada en cc |
| cylinders | INTEGER | - | Número de cilindros |
| fuel_type | TEXT | - | Tipo de combustible |
| power_hp | INTEGER | - | Potencia en HP |
| torque_nm | INTEGER | - | Torque en Nm |
| engine_code | TEXT | - | Código del fabricante |
| created_at | TIMESTAMP | DEFAULT NOW | Fecha de creación |
**Valores de fuel_type:**
- Gasoline, Diesel, Hybrid, Electric, Plug-in Hybrid, Flex Fuel
**Índices:**
- `idx_engines_name` en `name`
- `idx_engines_code` en `engine_code`
---
### Tabla: years
Tabla de referencia para años de producción.
```sql
CREATE TABLE years (
id INTEGER PRIMARY KEY AUTOINCREMENT,
year INTEGER NOT NULL UNIQUE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
```
| Campo | Tipo | Restricciones | Descripción |
|-------|------|---------------|-------------|
| id | INTEGER | PK, AUTO | Identificador único |
| year | INTEGER | NOT NULL, UNIQUE | Año |
| created_at | TIMESTAMP | DEFAULT NOW | Fecha de creación |
---
### Tabla: model_year_engine
Tabla de unión que relaciona modelos, años y motores.
```sql
CREATE TABLE model_year_engine (
id INTEGER PRIMARY KEY AUTOINCREMENT,
model_id INTEGER NOT NULL,
year_id INTEGER NOT NULL,
engine_id INTEGER NOT NULL,
trim_level TEXT,
drivetrain TEXT,
transmission TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (model_id) REFERENCES models(id),
FOREIGN KEY (year_id) REFERENCES years(id),
FOREIGN KEY (engine_id) REFERENCES engines(id),
UNIQUE(model_id, year_id, engine_id, trim_level)
);
```
| Campo | Tipo | Restricciones | Descripción |
|-------|------|---------------|-------------|
| id | INTEGER | PK, AUTO | Identificador único |
| model_id | INTEGER | FK, NOT NULL | Referencia a models |
| year_id | INTEGER | FK, NOT NULL | Referencia a years |
| engine_id | INTEGER | FK, NOT NULL | Referencia a engines |
| trim_level | TEXT | - | Nivel de equipamiento |
| drivetrain | TEXT | - | Tipo de tracción |
| transmission | TEXT | - | Tipo de transmisión |
| created_at | TIMESTAMP | DEFAULT NOW | Fecha de creación |
**Valores de drivetrain:**
- FWD (Front-Wheel Drive), RWD (Rear-Wheel Drive), AWD (All-Wheel Drive), 4WD (Four-Wheel Drive)
**Valores de transmission:**
- Manual, Automatic, CVT, DCT, AMT
**Índices:**
- `idx_mye_model_id` en `model_id`
- `idx_mye_year_id` en `year_id`
- `idx_mye_engine_id` en `engine_id`
---
## Consultas Comunes
### Obtener todos los vehículos de una marca
```sql
SELECT
b.name AS brand,
m.name AS model,
y.year,
e.name AS engine,
mye.trim_level,
mye.drivetrain,
mye.transmission
FROM model_year_engine mye
JOIN models m ON mye.model_id = m.id
JOIN brands b ON m.brand_id = b.id
JOIN years y ON mye.year_id = y.id
JOIN engines e ON mye.engine_id = e.id
WHERE b.name = 'Toyota'
ORDER BY m.name, y.year;
```
### Buscar vehículos por año
```sql
SELECT
b.name AS brand,
m.name AS model,
e.name AS engine,
e.power_hp,
mye.trim_level
FROM model_year_engine mye
JOIN models m ON mye.model_id = m.id
JOIN brands b ON m.brand_id = b.id
JOIN years y ON mye.year_id = y.id
JOIN engines e ON mye.engine_id = e.id
WHERE y.year = 2020;
```
### Obtener especificaciones de motor
```sql
SELECT
name,
displacement_cc,
cylinders,
fuel_type,
power_hp,
torque_nm,
engine_code
FROM engines
WHERE cylinders = 6
ORDER BY power_hp DESC;
```
### Contar modelos por marca
```sql
SELECT
b.name AS brand,
COUNT(DISTINCT m.id) AS model_count
FROM brands b
LEFT JOIN models m ON b.id = m.brand_id
GROUP BY b.id
ORDER BY model_count DESC;
```
### Buscar motores por potencia
```sql
SELECT *
FROM engines
WHERE power_hp >= 300
ORDER BY power_hp DESC;
```
---
## Mantenimiento
### Backup de la Base de Datos
```bash
# Crear backup
sqlite3 vehicle_database.db ".backup 'backup.db'"
# O usando cp
cp vehicle_database.db vehicle_database_backup_$(date +%Y%m%d).db
```
### Optimización
```sql
-- Analizar tablas para optimizar consultas
ANALYZE;
-- Reconstruir índices
REINDEX;
-- Compactar base de datos
VACUUM;
```
### Verificar Integridad
```sql
PRAGMA integrity_check;
PRAGMA foreign_key_check;
```
---
## Conexión desde Python
```python
import sqlite3
# Conectar a la base de datos
conn = sqlite3.connect('vehicle_database/vehicle_database.db')
conn.row_factory = sqlite3.Row # Permite acceso por nombre de columna
# Crear cursor
cursor = conn.cursor()
# Ejecutar consulta
cursor.execute("""
SELECT b.name, m.name, y.year
FROM model_year_engine mye
JOIN models m ON mye.model_id = m.id
JOIN brands b ON m.brand_id = b.id
JOIN years y ON mye.year_id = y.id
WHERE b.name = ?
""", ('Toyota',))
# Obtener resultados
for row in cursor.fetchall():
print(f"{row['name']} - {row['name']} ({row['year']})")
# Cerrar conexión
conn.close()
```
---
## Migración de Datos
### Exportar a CSV
```bash
sqlite3 -header -csv vehicle_database.db "SELECT * FROM brands;" > brands_export.csv
sqlite3 -header -csv vehicle_database.db "SELECT * FROM models;" > models_export.csv
sqlite3 -header -csv vehicle_database.db "SELECT * FROM engines;" > engines_export.csv
```
### Importar desde CSV
```bash
sqlite3 vehicle_database.db <<EOF
.mode csv
.import brands.csv brands
.import models.csv models
.import engines.csv engines
EOF
```

326
docs/INSTALLATION.md Normal file
View File

@@ -0,0 +1,326 @@
# Guía de Instalación - Autoparts DB
## Requisitos del Sistema
### Software Requerido
| Software | Versión Mínima | Propósito |
|----------|----------------|-----------|
| Python | 3.8+ | Lenguaje principal |
| pip | 20.0+ | Gestor de paquetes |
| Git | 2.0+ | Control de versiones |
### Sistema Operativo
El proyecto es compatible con:
- Linux (Ubuntu, Debian, CentOS, etc.)
- macOS
- Windows 10/11
### Espacio en Disco
- Mínimo: 50 MB
- Recomendado: 100 MB (para crecimiento de la base de datos)
---
## Instalación Rápida
```bash
# 1. Clonar el repositorio
git clone https://git.consultoria-as.com/[usuario]/Autoparts-DB.git
# 2. Entrar al directorio
cd Autoparts-DB
# 3. Instalar dependencias
pip install -r requirements.txt
# 4. Iniciar el dashboard
cd dashboard
python3 server.py
```
---
## Instalación Detallada
### Paso 1: Clonar el Repositorio
```bash
git clone https://git.consultoria-as.com/[usuario]/Autoparts-DB.git
cd Autoparts-DB
```
### Paso 2: Crear Entorno Virtual (Recomendado)
```bash
# Crear entorno virtual
python3 -m venv venv
# Activar entorno virtual
# Linux/macOS:
source venv/bin/activate
# Windows:
venv\Scripts\activate
```
### Paso 3: Instalar Dependencias
```bash
# Instalar todas las dependencias
pip install flask requests beautifulsoup4 lxml
# O usando requirements.txt
pip install -r requirements.txt
```
### Paso 4: Verificar la Base de Datos
La base de datos viene pre-poblada con datos. Para verificar:
```bash
cd vehicle_database
sqlite3 vehicle_database.db "SELECT COUNT(*) FROM brands;"
```
### Paso 5: Inicializar (Opcional)
Si necesitas reiniciar la base de datos:
```bash
cd vehicle_database
./setup.sh
```
---
## Dependencias de Python
### Archivo requirements.txt
```
flask==2.3.3
requests>=2.28.0
beautifulsoup4>=4.11.0
lxml>=4.9.0
```
### Instalación Individual
```bash
# Flask - Framework web
pip install flask
# Requests - Cliente HTTP
pip install requests
# BeautifulSoup4 - Parser HTML
pip install beautifulsoup4
# lxml - Parser XML/HTML rápido
pip install lxml
```
---
## Configuración
### Variables de Entorno (Opcional)
```bash
# Puerto del servidor (default: 5000)
export FLASK_PORT=5000
# Modo debug (solo desarrollo)
export FLASK_DEBUG=1
# Ruta de la base de datos
export DATABASE_PATH=/path/to/vehicle_database.db
```
### Configuración del Servidor
Editar `dashboard/server.py`:
```python
# Cambiar puerto
app.run(host='0.0.0.0', port=5000, debug=False)
# Para producción
app.run(host='0.0.0.0', port=8080, debug=False)
```
---
## Verificación de la Instalación
### 1. Verificar Python
```bash
python3 --version
# Debería mostrar: Python 3.8.x o superior
```
### 2. Verificar Dependencias
```bash
python3 -c "import flask; print(f'Flask: {flask.__version__}')"
python3 -c "import requests; print(f'Requests: {requests.__version__}')"
python3 -c "import bs4; print(f'BeautifulSoup: {bs4.__version__}')"
```
### 3. Verificar Base de Datos
```bash
cd vehicle_database
python3 -c "
import sqlite3
conn = sqlite3.connect('vehicle_database.db')
cursor = conn.execute('SELECT COUNT(*) FROM brands')
print(f'Marcas en BD: {cursor.fetchone()[0]}')
conn.close()
"
```
### 4. Probar el Dashboard
```bash
cd dashboard
python3 server.py &
curl http://localhost:5000/api/brands
```
---
## Solución de Problemas
### Error: ModuleNotFoundError
```bash
# Verificar que el entorno virtual está activado
which python3
# Reinstalar dependencias
pip install --force-reinstall flask requests beautifulsoup4 lxml
```
### Error: Database is locked
```bash
# Cerrar todas las conexiones a la base de datos
# Reiniciar el servidor
pkill -f server.py
python3 dashboard/server.py
```
### Error: Port already in use
```bash
# Encontrar proceso usando el puerto
lsof -i :5000
# Matar el proceso
kill -9 [PID]
# O usar otro puerto
python3 server.py --port 5001
```
### Error: Permission denied
```bash
# Dar permisos de ejecución a scripts
chmod +x vehicle_database/setup.sh
chmod +x dashboard/start_dashboard.sh
chmod +x QUICK_START.sh
```
---
## Instalación en Producción
### Usando Gunicorn (Recomendado)
```bash
# Instalar Gunicorn
pip install gunicorn
# Iniciar servidor
cd dashboard
gunicorn -w 4 -b 0.0.0.0:8080 server:app
```
### Usando systemd
Crear archivo `/etc/systemd/system/autoparts-db.service`:
```ini
[Unit]
Description=Autoparts DB Dashboard
After=network.target
[Service]
User=www-data
WorkingDirectory=/path/to/Autoparts-DB/dashboard
ExecStart=/usr/bin/python3 server.py
Restart=always
[Install]
WantedBy=multi-user.target
```
Habilitar e iniciar:
```bash
sudo systemctl enable autoparts-db
sudo systemctl start autoparts-db
```
### Usando Docker (Opcional)
```dockerfile
FROM python:3.11-slim
WORKDIR /app
COPY . /app
RUN pip install flask requests beautifulsoup4 lxml
EXPOSE 5000
CMD ["python3", "dashboard/server.py"]
```
```bash
docker build -t autoparts-db .
docker run -p 5000:5000 autoparts-db
```
---
## Actualizaciones
```bash
# Obtener últimos cambios
git pull origin main
# Actualizar dependencias
pip install --upgrade -r requirements.txt
```
---
## Desinstalación
```bash
# Desactivar entorno virtual
deactivate
# Eliminar directorio del proyecto
rm -rf Autoparts-DB
# Eliminar entorno virtual (si está separado)
rm -rf venv
```

180
fix_arra_data.py Normal file
View File

@@ -0,0 +1,180 @@
"""
Script to fix the ARRA vehicle data in the database.
This will remove the incorrect entry under Aston Martin and add the correct ARRA entry.
"""
import sqlite3
def connect_db(db_path: str = "vehicle_database/vehicle_database.db") -> sqlite3.Connection:
"""Connect to the vehicle database."""
conn = sqlite3.connect(db_path)
conn.execute("PRAGMA foreign_keys = ON") # Enable foreign key constraints
return conn
def get_or_insert_brand(conn: sqlite3.Connection, brand_name: str) -> int:
"""Get brand ID or insert if it doesn't exist."""
cursor = conn.cursor()
# Check if brand already exists
cursor.execute("SELECT id FROM brands WHERE name = ?", (brand_name,))
result = cursor.fetchone()
if result:
return result[0] # Return existing ID
# Insert new brand
cursor.execute("INSERT INTO brands (name) VALUES (?)", (brand_name,))
conn.commit()
return cursor.lastrowid
def get_or_insert_model(conn: sqlite3.Connection, brand_id: int, model_name: str) -> int:
"""Get model ID or insert if it doesn't exist."""
cursor = conn.cursor()
# Check if model already exists for this brand
cursor.execute(
"SELECT id FROM models WHERE brand_id = ? AND name = ?",
(brand_id, model_name)
)
result = cursor.fetchone()
if result:
return result[0] # Return existing ID
# Insert new model
cursor.execute(
"INSERT INTO models (brand_id, name) VALUES (?, ?)",
(brand_id, model_name)
)
conn.commit()
return cursor.lastrowid
def get_or_insert_engine(conn: sqlite3.Connection, engine_name: str) -> int:
"""Get engine ID or insert if it doesn't exist."""
cursor = conn.cursor()
# Check if engine already exists
cursor.execute("SELECT id FROM engines WHERE name = ?", (engine_name,))
result = cursor.fetchone()
if result:
return result[0] # Return existing ID
# Insert new engine
cursor.execute("INSERT INTO engines (name) VALUES (?)", (engine_name,))
conn.commit()
return cursor.lastrowid
def get_or_insert_year(conn: sqlite3.Connection, year: int) -> int:
"""Get year ID or insert if it doesn't exist."""
cursor = conn.cursor()
# Check if year already exists
cursor.execute("SELECT id FROM years WHERE year = ?", (year,))
result = cursor.fetchone()
if result:
return result[0] # Return existing ID
# Insert new year
cursor.execute("INSERT INTO years (year) VALUES (?)", (year,))
conn.commit()
return cursor.lastrowid
def remove_incorrect_arr_entry(conn: sqlite3.Connection) -> None:
"""Remove the incorrect ARRA entry under Aston Martin."""
cursor = conn.cursor()
# Find the model ID for ARRA under Aston Martin
cursor.execute("""
SELECT m.id
FROM models m
JOIN brands b ON m.brand_id = b.id
WHERE b.name = 'ASTON MARTIN' AND m.name = 'ARRA'
""")
arra_model_result = cursor.fetchone()
if arra_model_result:
arra_model_id = arra_model_result[0]
# Remove the incorrect relationship from model_year_engine
cursor.execute(
"DELETE FROM model_year_engine WHERE model_id = ?",
(arra_model_id,)
)
# Remove the ARRA model from models table
cursor.execute(
"DELETE FROM models WHERE id = ?",
(arra_model_id,)
)
print(f"Removed incorrect ARRA model with ID {arra_model_id} from Aston Martin")
conn.commit()
def insert_correct_arr_entry(conn: sqlite3.Connection) -> None:
"""Insert the correct ARRA EW-1 entry."""
cursor = conn.cursor()
# Get or create ARRA brand
arra_brand_id = get_or_insert_brand(conn, "ARRA")
print(f"ARRA brand ID: {arra_brand_id}")
# Get or create EW-1 model under ARRA brand
ew1_model_id = get_or_insert_model(conn, arra_brand_id, "EW-1")
print(f"EW-1 model ID: {ew1_model_id}")
# Get or create Electric engine
engine_id = get_or_insert_engine(conn, "Electric")
print(f"Electric engine ID: {engine_id}")
# Get or create 2024 year
year_id = get_or_insert_year(conn, 2024)
print(f"Year 2024 ID: {year_id}")
# Check if the correct relationship already exists
cursor.execute(
"SELECT id FROM model_year_engine WHERE model_id = ? AND year_id = ? AND engine_id = ?",
(ew1_model_id, year_id, engine_id)
)
result = cursor.fetchone()
if not result:
# Insert the correct relationship
cursor.execute(
"INSERT INTO model_year_engine (model_id, year_id, engine_id) VALUES (?, ?, ?)",
(ew1_model_id, year_id, engine_id)
)
conn.commit()
print("Added correct ARRA EW-1 2024 Electric entry")
else:
print("Correct ARRA EW-1 2024 Electric entry already exists")
def main():
"""Main function to fix ARRA data."""
print("Fixing ARRA vehicle data...")
# Connect to database
conn = connect_db()
# Remove the incorrect entry
remove_incorrect_arr_entry(conn)
# Insert the correct entry
insert_correct_arr_entry(conn)
# Close connection
conn.close()
print("ARRA data fixed successfully!")
if __name__ == "__main__":
main()

95
integration_demo.py Normal file
View File

@@ -0,0 +1,95 @@
#!/usr/bin/env python3
"""
RockAuto Data Integration Demo
Shows how to integrate manually extracted RockAuto data into the vehicle database
"""
from vehicle_scraper.manual_input_simple import ManualDataInput
import sqlite3
def demonstrate_integration():
"""Demonstrate the integration of RockAuto data into the database"""
print("RockAuto Data Integration Demo")
print("==============================")
# Create input tool with correct database path
input_tool = ManualDataInput(db_path="vehicle_database/vehicle_database.db")
# Example of data you might extract from RockAuto manually
print("\nExample: Adding data that could be extracted from RockAuto")
# Add some example vehicles that might be found on RockAuto
rockauto_vehicles = [
{"make": "Toyota", "model": "RAV4", "year": 2019, "engine": "2.5L 4-Cylinder"},
{"make": "Honda", "model": "CR-V", "year": 2020, "engine": "1.5L Turbo"},
{"make": "Ford", "model": "Escape", "year": 2021, "engine": "2.0L Turbo"},
{"make": "Nissan", "model": "Rogue", "year": 2018, "engine": "2.5L 4-Cylinder"},
{"make": "Chevrolet", "model": "Equinox", "year": 2020, "engine": "1.5L Turbo"},
]
print(f"\nAdding {len(rockauto_vehicles)} vehicles to database:")
for vehicle in rockauto_vehicles:
print(f" - {vehicle['year']} {vehicle['make']} {vehicle['model']} ({vehicle['engine']})")
input_tool.add_multiple_vehicles(rockauto_vehicles)
# Show the data in the database
print("\nCurrent data in database:")
conn = sqlite3.connect("vehicle_database/vehicle_database.db")
cursor = conn.cursor()
cursor.execute('''
SELECT b.name as brand, m.name as model, y.year, e.name as engine
FROM model_year_engine mye
JOIN models m ON mye.model_id = m.id
JOIN brands b ON m.brand_id = b.id
JOIN years y ON mye.year_id = y.id
JOIN engines e ON mye.engine_id = e.id
ORDER BY b.name, m.name, y.year
LIMIT 15
''')
results = cursor.fetchall()
for i, (brand, model, year, engine) in enumerate(results, 1):
print(f" {i:2d}. {year} {brand} {model} - {engine}")
if len(results) == 15:
print(" ... (showing first 15 results)")
conn.close()
print(f"\nDatabase contains {len(results)} vehicle entries")
# Show how to query specific data
print("\nExample queries you can perform:")
print("1. Find all Toyota models:")
print(" In query interface: Search brand='Toyota'")
print("2. Find all 2020 model year vehicles:")
print(" In query interface: Search year=2020")
print("3. Find all vehicles with 'Turbo' engines:")
print(" In query interface: Search engine='Turbo'")
print("\nTo continue adding RockAuto data:")
print("1. Visit https://www.rockauto.com/catalog/")
print("2. Browse manufacturers and note models/years/engines")
print("3. Use ManualDataInput to add to your database")
def main():
demonstrate_integration()
print("\n" + "="*50)
print("INTEGRATION DEMO COMPLETE")
print("="*50)
print("\nNext steps:")
print("1. Manually browse RockAuto.com for vehicle data")
print("2. Use the ManualDataInput class to add data")
print("3. Query your database using the query interface")
print("4. Build your comprehensive vehicle database")
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,141 @@
#!/usr/bin/env python3
"""
Script para eliminar vehículos de marcas específicas y ocultar marcas sin vehículos
"""
import sqlite3
import os
def remove_brands_and_cleanup():
# Verificar que la base de datos exista
db_path = "vehicle_database/vehicle_database.db"
if not os.path.exists(db_path):
print(f"Error: Base de datos no encontrada en {db_path}")
return
conn = sqlite3.connect(db_path)
cursor = conn.cursor()
print("Eliminando vehículos de marcas específicas y limpiando marcas sin vehículos...")
try:
# Marcas a eliminar
brands_to_remove = ['FORD', 'TOYOTA', 'NISSAN', 'HONDA', 'CHEVROLET']
print(f"Marcas a eliminar: {', '.join(brands_to_remove)}")
# Contar cuántos vehículos vamos a eliminar antes de hacerlo
placeholders = ','.join(['?' for _ in brands_to_remove])
cursor.execute(f"""
SELECT COUNT(*)
FROM model_year_engine mye
JOIN models m ON mye.model_id = m.id
JOIN brands b ON m.brand_id = b.id
WHERE b.name IN ({placeholders})
""", brands_to_remove)
count_to_delete = cursor.fetchone()[0]
print(f"Se eliminarán {count_to_delete} vehículos de las marcas especificadas")
if count_to_delete > 0:
print("Procediendo con la eliminación...")
# Eliminar las combinaciones modelo-año-motor para los modelos de las marcas especificadas
cursor.execute(f"""
DELETE FROM model_year_engine
WHERE model_id IN (
SELECT m.id FROM models m
JOIN brands b ON m.brand_id = b.id
WHERE b.name IN ({placeholders})
)
""", brands_to_remove)
# Eliminar los modelos de las marcas especificadas
cursor.execute(f"""
DELETE FROM models
WHERE brand_id IN (
SELECT id FROM brands WHERE name IN ({placeholders})
)
""", brands_to_remove)
# Eliminar las marcas especificadas
cursor.execute(f"""
DELETE FROM brands
WHERE name IN ({placeholders})
""", brands_to_remove)
conn.commit()
print(f"Se eliminaron {count_to_delete} registros de vehículos de las marcas especificadas")
else:
print("No hay vehículos de las marcas especificadas para eliminar")
# Ahora vamos a limpiar las marcas sin vehículos (aunque en este caso ya se eliminaron)
# pero también limpiaremos cualquier marca que haya quedado sin vehículos
print("\nLimpiando marcas sin vehículos...")
# Encontrar marcas que no tienen modelos asociados
cursor.execute("""
SELECT b.id, b.name
FROM brands b
LEFT JOIN models m ON b.id = m.brand_id
WHERE m.brand_id IS NULL
""")
brands_without_models = cursor.fetchall()
if brands_without_models:
print(f"Marcas sin modelos para eliminar: {[brand[1] for brand in brands_without_models]}")
brand_ids = [str(brand[0]) for brand in brands_without_models]
placeholders = ','.join(brand_ids)
# Eliminar estas marcas
cursor.execute(f"""
DELETE FROM brands
WHERE id IN ({placeholders})
""")
else:
print("No hay marcas sin modelos para eliminar")
# Mostrar un resumen de la base de datos actualizada
print("\nResumen de la base de datos actualizada:")
# Contar vehículos restantes
cursor.execute("""
SELECT COUNT(*)
FROM model_year_engine mye
JOIN models m ON mye.model_id = m.id
JOIN brands b ON m.brand_id = b.id
""")
total_vehicles = cursor.fetchone()[0]
print(f"Total de vehículos restantes: {total_vehicles}")
# Contar marcas restantes
cursor.execute("SELECT COUNT(*) FROM brands")
total_brands = cursor.fetchone()[0]
print(f"Total de marcas restantes: {total_brands}")
# Mostrar marcas restantes
cursor.execute("SELECT name FROM brands ORDER BY name")
remaining_brands = cursor.fetchall()
print(f"Marcas restantes: {[brand[0] for brand in remaining_brands]}")
# Mostrar rango de años actual
cursor.execute("""
SELECT MIN(y.year), MAX(y.year)
FROM years y
JOIN model_year_engine mye ON y.id = mye.year_id
""")
min_year, max_year = cursor.fetchone()
if min_year and max_year:
print(f"Rango de años actual: {min_year} - {max_year}")
else:
print("No hay años con vehículos registrados")
except Exception as e:
print(f"Error al eliminar marcas y limpiar la base de datos: {e}")
conn.rollback()
finally:
conn.close()
if __name__ == "__main__":
remove_brands_and_cleanup()

View File

@@ -0,0 +1,105 @@
#!/usr/bin/env python3
"""
Script para eliminar marcas específicas y limpiar marcas sin vehículos
"""
import sqlite3
import os
def remove_brands_and_cleanup():
# Verificar que la base de datos exista
db_path = "vehicle_database/vehicle_database.db"
if not os.path.exists(db_path):
print(f"Error: Base de datos no encontrada en {db_path}")
return
conn = sqlite3.connect(db_path)
cursor = conn.cursor()
print("Eliminando marcas específicas y limpiando marcas sin vehículos...")
try:
# Marcas a eliminar
brands_to_remove = ['FORD', 'TOYOTA', 'NISSAN', 'HONDA', 'CHEVROLET']
print(f"Marcas a eliminar: {', '.join(brands_to_remove)}")
# Eliminar modelos y combinaciones modelo-año-motor para las marcas especificadas
placeholders = ','.join(['?' for _ in brands_to_remove])
cursor.execute(f"""
DELETE FROM model_year_engine
WHERE model_id IN (
SELECT m.id FROM models m
JOIN brands b ON m.brand_id = b.id
WHERE b.name IN ({placeholders})
)
""", brands_to_remove)
# Eliminar modelos de las marcas especificadas
cursor.execute(f"""
DELETE FROM models
WHERE brand_id IN (
SELECT id FROM brands WHERE name IN ({placeholders})
)
""", brands_to_remove)
# Eliminar las marcas especificadas
cursor.execute(f"""
DELETE FROM brands
WHERE name IN ({placeholders})
""", brands_to_remove)
# También eliminar marcas que no tienen modelos asociados
print("Eliminando marcas sin vehículos...")
cursor.execute("""
DELETE FROM brands
WHERE id NOT IN (
SELECT DISTINCT brand_id FROM models
)
""")
conn.commit()
# Mostrar un resumen de la base de datos actualizada
print("\nResumen de la base de datos actualizada:")
# Contar vehículos restantes
cursor.execute("""
SELECT COUNT(*)
FROM model_year_engine mye
JOIN models m ON mye.model_id = m.id
JOIN brands b ON m.brand_id = b.id
""")
total_vehicles = cursor.fetchone()[0]
print(f"Total de vehículos restantes: {total_vehicles}")
# Contar marcas restantes
cursor.execute("SELECT COUNT(*) FROM brands")
total_brands = cursor.fetchone()[0]
print(f"Total de marcas restantes: {total_brands}")
# Mostrar marcas restantes
cursor.execute("SELECT name FROM brands ORDER BY name")
remaining_brands = cursor.fetchall()
print(f"Marcas restantes: {[brand[0] for brand in remaining_brands]}")
# Mostrar rango de años actual
cursor.execute("""
SELECT MIN(y.year), MAX(y.year)
FROM years y
JOIN model_year_engine mye ON y.id = mye.year_id
""")
min_year, max_year = cursor.fetchone()
if min_year and max_year:
print(f"Rango de años actual: {min_year} - {max_year}")
else:
print("No hay años con vehículos registrados")
except Exception as e:
print(f"Error al eliminar marcas y limpiar la base de datos: {e}")
conn.rollback()
finally:
conn.close()
if __name__ == "__main__":
remove_brands_and_cleanup()

102
remove_old_vehicles.py Normal file
View File

@@ -0,0 +1,102 @@
#!/usr/bin/env python3
"""
Script para eliminar vehículos de 1975 hacia abajo de la base de datos
"""
import sqlite3
import os
def remove_old_vehicles():
# Verificar que la base de datos exista
db_path = "vehicle_database/vehicle_database.db"
if not os.path.exists(db_path):
print(f"Error: Base de datos no encontrada en {db_path}")
return
conn = sqlite3.connect(db_path)
cursor = conn.cursor()
print("Eliminando vehículos de 1975 hacia abajo de la base de datos...")
try:
# Contar cuántos vehículos vamos a eliminar antes de hacerlo
cursor.execute("""
SELECT COUNT(*)
FROM model_year_engine mye
JOIN years y ON mye.year_id = y.id
WHERE y.year <= 1975
""")
count_to_delete = cursor.fetchone()[0]
print(f"Se eliminarán {count_to_delete} vehículos de 1975 hacia abajo")
if count_to_delete > 0:
# Confirmar antes de eliminar
confirm = input("¿Deseas continuar con la eliminación? (s/N): ")
if confirm.lower() != 's':
print("Operación cancelada.")
return
# Eliminar las combinaciones modelo-año-motor para años <= 1975
cursor.execute("""
DELETE FROM model_year_engine
WHERE year_id IN (
SELECT id FROM years WHERE year <= 1975
)
""")
# Eliminar los años <= 1975 que ya no tienen registros asociados
cursor.execute("""
DELETE FROM years
WHERE year <= 1975
AND id NOT IN (
SELECT DISTINCT year_id FROM model_year_engine
)
""")
conn.commit()
print(f"Se eliminaron {count_to_delete} registros de vehículos de 1975 hacia abajo")
# Mostrar algunos de los años que se eliminaron
print("\nAños eliminados:")
cursor.execute("""
SELECT DISTINCT y.year
FROM years y
WHERE y.year <= 1975
ORDER BY y.year DESC
""")
deleted_years = cursor.fetchall()
if deleted_years:
for year in deleted_years:
print(f" - {year[0]}")
else:
print(" (No quedan años <= 1975 en la base de datos)")
else:
print("No hay vehículos de 1975 hacia abajo para eliminar")
# Mostrar un resumen de la base de datos actualizada
print("\nResumen de la base de datos actualizada:")
# Contar vehículos restantes
cursor.execute("""
SELECT COUNT(*)
FROM model_year_engine mye
JOIN years y ON mye.year_id = y.id
""")
total_vehicles = cursor.fetchone()[0]
print(f"Total de vehículos restantes: {total_vehicles}")
# Mostrar rango de años actual
cursor.execute("SELECT MIN(year), MAX(year) FROM years")
min_year, max_year = cursor.fetchone()
print(f"Rango de años actual: {min_year} - {max_year}")
except Exception as e:
print(f"Error al eliminar vehículos antiguos: {e}")
conn.rollback()
finally:
conn.close()
if __name__ == "__main__":
remove_old_vehicles()

View File

@@ -0,0 +1,98 @@
#!/usr/bin/env python3
"""
Script para eliminar vehículos de 1975 hacia abajo de la base de datos
"""
import sqlite3
import os
def remove_old_vehicles():
# Verificar que la base de datos exista
db_path = "vehicle_database/vehicle_database.db"
if not os.path.exists(db_path):
print(f"Error: Base de datos no encontrada en {db_path}")
return
conn = sqlite3.connect(db_path)
cursor = conn.cursor()
print("Eliminando vehículos de 1975 hacia abajo de la base de datos...")
try:
# Contar cuántos vehículos vamos a eliminar antes de hacerlo
cursor.execute("""
SELECT COUNT(*)
FROM model_year_engine mye
JOIN years y ON mye.year_id = y.id
WHERE y.year <= 1975
""")
count_to_delete = cursor.fetchone()[0]
print(f"Se eliminarán {count_to_delete} vehículos de 1975 hacia abajo")
if count_to_delete > 0:
print("Procediendo con la eliminación...")
# Eliminar las combinaciones modelo-año-motor para años <= 1975
cursor.execute("""
DELETE FROM model_year_engine
WHERE year_id IN (
SELECT id FROM years WHERE year <= 1975
)
""")
# Eliminar los años <= 1975 que ya no tienen registros asociados
cursor.execute("""
DELETE FROM years
WHERE year <= 1975
AND id NOT IN (
SELECT DISTINCT year_id FROM model_year_engine
)
""")
conn.commit()
print(f"Se eliminaron {count_to_delete} registros de vehículos de 1975 hacia abajo")
# Mostrar algunos de los años que se eliminaron
print("\nAños eliminados:")
cursor.execute("""
SELECT DISTINCT y.year
FROM years y
WHERE y.year <= 1975
ORDER BY y.year DESC
""")
deleted_years = cursor.fetchall()
if deleted_years:
for year in deleted_years:
print(f" - {year[0]}")
else:
print(" (No quedan años <= 1975 en la base de datos)")
else:
print("No hay vehículos de 1975 hacia abajo para eliminar")
# Mostrar un resumen de la base de datos actualizada
print("\nResumen de la base de datos actualizada:")
# Contar vehículos restantes
cursor.execute("""
SELECT COUNT(*)
FROM model_year_engine mye
JOIN years y ON mye.year_id = y.id
""")
total_vehicles = cursor.fetchone()[0]
print(f"Total de vehículos restantes: {total_vehicles}")
# Mostrar rango de años actual
cursor.execute("SELECT MIN(year), MAX(year) FROM years")
min_year, max_year = cursor.fetchone()
print(f"Rango de años actual: {min_year} - {max_year}")
except Exception as e:
print(f"Error al eliminar vehículos antiguos: {e}")
conn.rollback()
finally:
conn.close()
if __name__ == "__main__":
remove_old_vehicles()

4
requirements.txt Normal file
View File

@@ -0,0 +1,4 @@
flask==2.3.3
requests>=2.28.0
beautifulsoup4>=4.11.0
lxml>=4.9.0

185
scrape_toyota_windows.py Normal file
View File

@@ -0,0 +1,185 @@
import requests
from bs4 import BeautifulSoup
import sqlite3
import time
import re
import os
from urllib.parse import unquote
# Base de datos - ruta directa desde C:\Autopartes
DB_PATH = "vehicle_database/vehicle_database.db"
BASE_URL = "https://www.rockauto.com/en/catalog"
MISSING_YEARS = [
2003, 2002, 2001, 2000, 1999, 1998, 1997, 1996, 1995, 1994,
1993, 1992, 1991, 1990, 1989, 1988, 1987, 1986, 1985, 1984,
1983, 1982, 1981, 1980, 1979, 1978, 1977, 1976, 1975
]
session = requests.Session()
session.headers.update({
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
'Accept': 'text/html,application/xhtml+xml',
})
def clean_name(name):
name = unquote(name.replace('+', ' '))
return re.sub(r'\s+', ' ', name).strip().upper()
def get_soup(url, retries=3):
for attempt in range(retries):
try:
time.sleep(0.5)
response = session.get(url, timeout=15)
if response.status_code == 200:
return BeautifulSoup(response.content, 'html.parser')
elif response.status_code == 403:
print("\n [!] BLOQUEADO (403) - Cambia el VPN!")
return None
except Exception as e:
if attempt < retries - 1:
time.sleep(3)
else:
print(f"\n Error: {e}")
return None
def get_models(brand, year):
brand_url = brand.lower()
soup = get_soup(f"{BASE_URL}/{brand_url},{year}")
if not soup:
return []
models = set()
for link in soup.find_all('a', href=True):
match = re.search(rf'/catalog/{brand_url},{year},([^,/]+)', link['href'], re.I)
if match:
model = clean_name(match.group(1))
if model and not model.isdigit() and len(model) > 1:
models.add(model)
return sorted(models)
def get_engines(brand, year, model):
brand_url = brand.lower()
model_url = model.lower().replace(' ', '+')
soup = get_soup(f"{BASE_URL}/{brand_url},{year},{model_url}")
if not soup:
return ['STANDARD']
engines = set()
for link in soup.find_all('a', href=True):
match = re.search(rf'/catalog/{brand_url},{year},{re.escape(model_url)},([^,/]+)', link['href'], re.I)
if match:
engine = clean_name(match.group(1))
if engine and re.search(r'\d+\.?\d*L|V\d|I\d|HYBRID|ELECTRIC|DIESEL', engine, re.I):
engines.add(engine)
return sorted(engines) if engines else ['STANDARD']
def save_to_db(conn, brand, year, model, engine):
cursor = conn.cursor()
try:
cursor.execute("INSERT OR IGNORE INTO brands (name) VALUES (?)", (brand,))
cursor.execute("SELECT id FROM brands WHERE name = ?", (brand,))
brand_id = cursor.fetchone()[0]
cursor.execute("INSERT OR IGNORE INTO years (year) VALUES (?)", (year,))
cursor.execute("SELECT id FROM years WHERE year = ?", (year,))
year_id = cursor.fetchone()[0]
cursor.execute("INSERT OR IGNORE INTO engines (name) VALUES (?)", (engine,))
cursor.execute("SELECT id FROM engines WHERE name = ?", (engine,))
engine_id = cursor.fetchone()[0]
cursor.execute("INSERT OR IGNORE INTO models (brand_id, name) VALUES (?, ?)", (brand_id, model))
cursor.execute("SELECT id FROM models WHERE brand_id = ? AND name = ?", (brand_id, model))
model_id = cursor.fetchone()[0]
cursor.execute(
"INSERT OR IGNORE INTO model_year_engine (model_id, year_id, engine_id) VALUES (?, ?, ?)",
(model_id, year_id, engine_id)
)
return cursor.rowcount > 0
except:
return False
def get_existing_years(conn, brand):
cursor = conn.cursor()
cursor.execute("""
SELECT DISTINCT y.year FROM years y
JOIN model_year_engine mye ON y.id = mye.year_id
JOIN models m ON mye.model_id = m.id
JOIN brands b ON m.brand_id = b.id
WHERE b.name = ?
""", (brand,))
return set(row[0] for row in cursor.fetchall())
def main():
brand = "TOYOTA"
print("=" * 50)
print(" SCRAPER TOYOTA - WINDOWS")
print(" 3 anos por lote, 60 seg pausa para VPN")
print("=" * 50)
if not os.path.exists(DB_PATH):
print(f"\n[ERROR] No encuentro: {DB_PATH}")
print("Asegurate de correr desde C:\\Autopartes")
input("Presiona ENTER para salir...")
return
conn = sqlite3.connect(DB_PATH)
existing = get_existing_years(conn, brand)
years_to_do = [y for y in MISSING_YEARS if y not in existing]
if not years_to_do:
print("\nTodos los anos ya estan!")
conn.close()
return
print(f"\nFaltan {len(years_to_do)} anos: {years_to_do[0]} a {years_to_do[-1]}")
batches = [years_to_do[i:i+3] for i in range(0, len(years_to_do), 3)]
print(f"Lotes: {len(batches)}")
input("\nPresiona ENTER para comenzar...")
total_saved = 0
for batch_num, batch in enumerate(batches, 1):
print(f"\n{'='*50}")
print(f"LOTE {batch_num}/{len(batches)}: {batch}")
print("="*50)
for year in batch:
print(f"\n[{year}] ", end="", flush=True)
models = get_models(brand, year)
print(f"{len(models)} modelos")
for model in models:
engines = get_engines(brand, year, model)
for engine in engines:
if save_to_db(conn, brand, year, model, engine):
total_saved += 1
print(f" {model} - {engine}")
conn.commit()
print(f"\n>> Guardado! Total nuevos: {total_saved}")
if batch_num < len(batches):
print(f"\n{'*'*50}")
print(" PAUSA 60 SEG - CAMBIA EL VPN AHORA!")
print(f" Faltan {len(batches) - batch_num} lotes")
print("*"*50)
for s in range(60, 0, -1):
print(f"\r Continua en {s}s... ", end="", flush=True)
time.sleep(1)
print()
conn.close()
print(f"\n{'='*50}")
print(f" LISTO! Guardados: {total_saved} vehiculos nuevos")
print("="*50)
input("Presiona ENTER para salir...")
if __name__ == "__main__":
main()

54
test_dashboard.sh Executable file
View File

@@ -0,0 +1,54 @@
#!/bin/bash
# Test script for the Vehicle Dashboard
echo "Testing Vehicle Dashboard Setup"
echo "================================"
# Check if the dashboard directory exists
if [ ! -d "/home/Autopartes/dashboard" ]; then
echo "Error: Dashboard directory not found!"
exit 1
fi
echo "Dashboard directory found."
# Check if required files exist
files=("index.html" "dashboard.js" "server.py" "requirements.txt")
for file in "${files[@]}"; do
if [ ! -f "/home/Autopartes/dashboard/$file" ]; then
echo "Error: $file not found in dashboard directory!"
exit 1
fi
done
echo "All required files found."
# Check if the vehicle database exists
if [ ! -f "/home/Autopartes/vehicle_database/vehicle_database.db" ]; then
echo "Error: Vehicle database not found!"
exit 1
fi
echo "Vehicle database found."
# Check if Flask is available
if python3 -c "import flask" &> /dev/null; then
echo "Flask is available."
else
echo "Flask is not available. Installing..."
sudo apt-get update
sudo apt-get install -y python3-flask
fi
# Check if the server is running
if pgrep -f "server.py" > /dev/null; then
echo "Dashboard server is running on http://localhost:5000"
echo "You can access the dashboard now!"
else
echo "Dashboard server is not running."
echo "To start it, run: cd /home/Autopartes/dashboard && python3 server.py"
fi
echo ""
echo "Dashboard Test Complete!"
echo "Access the dashboard at: http://localhost:5000"

View File

@@ -0,0 +1,82 @@
# Vehicle Database - Getting Started Guide
## Overview
This project provides a comprehensive database system for storing information about vehicle brands, models, years, and engines. The database is built using SQLite and managed through Python scripts.
## Database Structure
The database consists of five main tables:
- **brands**: Vehicle manufacturers (Toyota, Ford, etc.)
- **models**: Vehicle models (Camry, F-150, etc.)
- **engines**: Engine specifications (2JZ-GTE, EcoBoost, etc.)
- **years**: Calendar years for vehicle production
- **model_year_engine**: Junction table linking all entities with trim levels and specifications
## Setup and Usage
### 1. Initial Setup
Run the setup script to initialize the database:
```bash
cd vehicle_database
./setup.sh
```
### 2. Querying the Database
Use the interactive query interface:
```bash
python3 scripts/query_interface.py
```
The query interface allows you to:
- Search for vehicles by brand, model, year, or engine
- Browse all available brands
- View models for specific brands
- See production years for specific models
### 3. Managing the Database
Use the database manager for programmatic access:
```bash
python3 scripts/database_manager.py
```
### 4. Importing Data
To import data from CSV files:
1. Prepare your data in the required CSV format
2. Use the CSV importer functionality in your own scripts
Sample CSV files are provided in the `data/` directory.
## Example Queries
The system supports various search options:
- Find all vehicles by a specific brand
- Search for a specific model across all years
- Filter by engine type or specifications
- Look up trim levels and drivetrain configurations
## Extending the Database
To add more data:
1. Use the Python API in `scripts/database_manager.py`
2. Directly execute SQL commands on the SQLite database
3. Import data from CSV files using the structure provided
## File Structure
```
vehicle_database/
├── sql/
│ └── schema.sql # Database schema
├── scripts/
│ ├── database_manager.py # Main database manager
│ ├── query_interface.py # Interactive query interface
│ └── csv_importer.py # CSV import functionality
├── data/ # Sample CSV data files
├── vehicle_database.db # SQLite database file
├── setup.sh # Setup script
└── README.md # Project documentation
```
## Next Steps
1. Explore the database using the query interface
2. Add your own vehicle data
3. Customize the schema if needed for your specific requirements
4. Extend the Python scripts with additional functionality

106
vehicle_database/README.md Normal file
View File

@@ -0,0 +1,106 @@
# Vehicle Database
A comprehensive database system for storing information about vehicle brands, models, years, and engines.
## Overview
This project provides a structured database for vehicle information with the following entities:
- **Brands**: Vehicle manufacturers with details like country of origin and founding year
- **Models**: Vehicle models with body type, generation, and production years
- **Years**: Calendar years for vehicle production
- **Engines**: Engine specifications including displacement, cylinders, power, and fuel type
- **Model-Year-Engine**: Junction table linking all entities with trim levels and specifications
## Database Schema
The database uses SQLite and consists of the following tables:
### `brands`
- `id`: Primary key
- `name`: Brand name (e.g., Toyota, Ford)
- `country`: Country of origin
- `founded_year`: Year the company was founded
### `engines`
- `id`: Primary key
- `name`: Engine name
- `displacement_cc`: Engine displacement in cubic centimeters
- `cylinders`: Number of cylinders
- `fuel_type`: Type of fuel (gasoline, diesel, electric, hybrid)
- `power_hp`: Horsepower
- `torque_nm`: Torque in Newton meters
- `engine_code`: Manufacturer engine code
### `models`
- `id`: Primary key
- `brand_id`: Foreign key to brands table
- `name`: Model name (e.g., Camry, Civic)
- `body_type`: Body style (sedan, SUV, truck, etc.)
- `generation`: Model generation
- `production_start_year`: Year production started
- `production_end_year`: Year production ended (NULL if still in production)
### `years`
- `id`: Primary key
- `year`: Calendar year
### `model_year_engine`
- `id`: Primary key
- `model_id`: Foreign key to models table
- `year_id`: Foreign key to years table
- `engine_id`: Foreign key to engines table
- `trim_level`: Trim level (e.g., base, luxury, sport)
- `drivetrain`: Drive system (FWD, RWD, AWD, 4WD)
- `transmission`: Transmission type (manual, automatic, CVT)
## Setup
1. Install Python 3.x if not already installed
2. Clone or download this repository
3. Run the database manager script:
```bash
cd vehicle_database
python scripts/database_manager.py
```
This will create the database, populate it with sample data, and run example queries.
## Usage
The `VehicleDatabaseManager` class provides methods to:
- Create and manage the database schema
- Insert new brands, models, engines, and years
- Query vehicle information
- Link models, years, and engines with trim levels and specifications
## Sample Queries
The script demonstrates several query patterns:
- Get all brands
- Get models for a specific brand
- Search for specific vehicles by brand, model, year, or engine
- Retrieve comprehensive vehicle information
## Extending the Database
To add more data, you can:
1. Use the provided Python API
2. Directly execute SQL commands on the SQLite database
3. Import data from CSV files using the provided structure
## File Structure
```
vehicle_database/
├── sql/
│ └── schema.sql # Database schema
├── scripts/
│ └── database_manager.py # Python database manager
├── data/ # Directory for data files
└── README.md # This file
```

View File

@@ -0,0 +1,6 @@
name,country,founded_year
Mercedes-Benz,Germany,1926
Audi,Germany,1909
Nissan,Japan,1933
Chevrolet,USA,1911
Volkswagen,Germany,1937
1 name country founded_year
2 Mercedes-Benz Germany 1926
3 Audi Germany 1909
4 Nissan Japan 1933
5 Chevrolet USA 1911
6 Volkswagen Germany 1937

View File

@@ -0,0 +1,5 @@
name,displacement_cc,cylinders,fuel_type,power_hp,torque_nm,engine_code
VQ35DE,3500,6,gasoline,280,260,VQ35DE
LS3,6200,8,gasoline,430,424,LS3
EA888,2000,4,gasoline,228,258,EA888
M274,2000,4,gasoline,241,273,M274
1 name displacement_cc cylinders fuel_type power_hp torque_nm engine_code
2 VQ35DE 3500 6 gasoline 280 260 VQ35DE
3 LS3 6200 8 gasoline 430 424 LS3
4 EA888 2000 4 gasoline 228 258 EA888
5 M274 2000 4 gasoline 241 273 M274

View File

@@ -0,0 +1,5 @@
brand_name,name,body_type,generation,production_start_year,production_end_year
Toyota,Corolla,sedan,E210,2018,
Honda,Accord,sedan,X,2018,
Ford,F-150,truck,13th Gen,2015,
BMW,3 Series,sedan,G20,2018,
1 brand_name name body_type generation production_start_year production_end_year
2 Toyota Corolla sedan E210 2018
3 Honda Accord sedan X 2018
4 Ford F-150 truck 13th Gen 2015
5 BMW 3 Series sedan G20 2018

View File

@@ -0,0 +1,152 @@
#!/usr/bin/env python3
"""
CSV Import Script for Vehicle Database
This script allows importing vehicle data from CSV files
"""
import csv
import sqlite3
import os
from typing import Dict, List
class CSVImporter:
def __init__(self, db_path: str = "vehicle_database.db"):
self.db_path = db_path
def import_brands_from_csv(self, csv_file: str):
"""Import brands from a CSV file"""
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
with open(csv_file, 'r', newline='', encoding='utf-8') as file:
reader = csv.DictReader(file)
for row in reader:
cursor.execute(
"INSERT OR IGNORE INTO brands (name, country, founded_year) VALUES (?, ?, ?)",
(row['name'], row.get('country'), row.get('founded_year'))
)
conn.commit()
conn.close()
print(f"Imported brands from {csv_file}")
def import_engines_from_csv(self, csv_file: str):
"""Import engines from a CSV file"""
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
with open(csv_file, 'r', newline='', encoding='utf-8') as file:
reader = csv.DictReader(file)
for row in reader:
cursor.execute(
"""INSERT OR IGNORE INTO engines
(name, displacement_cc, cylinders, fuel_type, power_hp, torque_nm, engine_code)
VALUES (?, ?, ?, ?, ?, ?, ?)""",
(
row['name'],
row.get('displacement_cc'),
row.get('cylinders'),
row.get('fuel_type'),
row.get('power_hp'),
row.get('torque_nm'),
row.get('engine_code')
)
)
conn.commit()
conn.close()
print(f"Imported engines from {csv_file}")
def import_models_from_csv(self, csv_file: str):
"""Import models from a CSV file"""
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
with open(csv_file, 'r', newline='', encoding='utf-8') as file:
reader = csv.DictReader(file)
# First, create a mapping of brand names to IDs
cursor.execute("SELECT id, name FROM brands")
brand_map = {row[1]: row[0] for row in cursor.fetchall()}
for row in reader:
brand_id = brand_map.get(row['brand_name'])
if brand_id is None:
print(f"Warning: Brand '{row['brand_name']}' not found in database")
continue
cursor.execute(
"""INSERT OR IGNORE INTO models
(brand_id, name, body_type, generation, production_start_year, production_end_year)
VALUES (?, ?, ?, ?, ?, ?)""",
(
brand_id,
row['name'],
row.get('body_type'),
row.get('generation'),
row.get('production_start_year'),
row.get('production_end_year')
)
)
conn.commit()
conn.close()
print(f"Imported models from {csv_file}")
def create_sample_csv_files(self):
"""Create sample CSV files with example data"""
os.makedirs("data", exist_ok=True)
# Sample brands CSV
with open("data/brands.csv", "w", newline="", encoding="utf-8") as csvfile:
fieldnames = ["name", "country", "founded_year"]
writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
writer.writeheader()
writer.writerows([
{"name": "Mercedes-Benz", "country": "Germany", "founded_year": 1926},
{"name": "Audi", "country": "Germany", "founded_year": 1909},
{"name": "Nissan", "country": "Japan", "founded_year": 1933},
{"name": "Chevrolet", "country": "USA", "founded_year": 1911},
{"name": "Volkswagen", "country": "Germany", "founded_year": 1937}
])
# Sample engines CSV
with open("data/engines.csv", "w", newline="", encoding="utf-8") as csvfile:
fieldnames = ["name", "displacement_cc", "cylinders", "fuel_type", "power_hp", "torque_nm", "engine_code"]
writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
writer.writeheader()
writer.writerows([
{"name": "VQ35DE", "displacement_cc": 3500, "cylinders": 6, "fuel_type": "gasoline", "power_hp": 280, "torque_nm": 260, "engine_code": "VQ35DE"},
{"name": "LS3", "displacement_cc": 6200, "cylinders": 8, "fuel_type": "gasoline", "power_hp": 430, "torque_nm": 424, "engine_code": "LS3"},
{"name": "EA888", "displacement_cc": 2000, "cylinders": 4, "fuel_type": "gasoline", "power_hp": 228, "torque_nm": 258, "engine_code": "EA888"},
{"name": "M274", "displacement_cc": 2000, "cylinders": 4, "fuel_type": "gasoline", "power_hp": 241, "torque_nm": 273, "engine_code": "M274"}
])
# Sample models CSV
with open("data/models.csv", "w", newline="", encoding="utf-8") as csvfile:
fieldnames = ["brand_name", "name", "body_type", "generation", "production_start_year", "production_end_year"]
writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
writer.writeheader()
writer.writerows([
{"brand_name": "Toyota", "name": "Corolla", "body_type": "sedan", "generation": "E210", "production_start_year": 2018, "production_end_year": None},
{"brand_name": "Honda", "name": "Accord", "body_type": "sedan", "generation": "X", "production_start_year": 2018, "production_end_year": None},
{"brand_name": "Ford", "name": "F-150", "body_type": "truck", "generation": "13th Gen", "production_start_year": 2015, "production_end_year": None},
{"brand_name": "BMW", "name": "3 Series", "body_type": "sedan", "generation": "G20", "production_start_year": 2018, "production_end_year": None}
])
print("Sample CSV files created in data/ directory")
def main():
importer = CSVImporter()
# Create sample CSV files
importer.create_sample_csv_files()
# Import sample data (these would be imported by the main script, but showing the functionality)
print("CSV import functionality created. Sample CSV files are in the data/ directory.")
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,323 @@
#!/usr/bin/env python3
"""
Vehicle Database Manager
A script to initialize and manage the vehicle database with brands, years, models, and engines
"""
import sqlite3
import os
from datetime import datetime
from typing import List, Tuple
class VehicleDatabaseManager:
def __init__(self, db_path: str = "vehicle_database.db"):
self.db_path = db_path
self.connection = None
def connect(self):
"""Connect to the SQLite database"""
self.connection = sqlite3.connect(self.db_path)
self.connection.row_factory = sqlite3.Row # Enable column access by name
print(f"Connected to database: {self.db_path}")
def disconnect(self):
"""Close the database connection"""
if self.connection:
self.connection.close()
print("Disconnected from database")
def create_tables(self, schema_file: str = "sql/schema.sql"):
"""Create tables from schema file"""
if not os.path.exists(schema_file):
raise FileNotFoundError(f"Schema file not found: {schema_file}")
with open(schema_file, 'r') as f:
schema = f.read()
if self.connection:
cursor = self.connection.cursor()
cursor.executescript(schema)
self.connection.commit()
print("Tables created successfully")
def insert_brand(self, name: str, country: str = None, founded_year: int = None) -> int:
"""Insert a new brand and return its ID"""
cursor = self.connection.cursor()
cursor.execute(
"INSERT OR IGNORE INTO brands (name, country, founded_year) VALUES (?, ?, ?)",
(name, country, founded_year)
)
self.connection.commit()
# Return the ID of the inserted or existing brand
cursor.execute("SELECT id FROM brands WHERE name = ?", (name,))
return cursor.fetchone()[0]
def insert_engine(self, name: str, displacement_cc: float = None, cylinders: int = None,
fuel_type: str = None, power_hp: int = None, torque_nm: int = None,
engine_code: str = None) -> int:
"""Insert a new engine and return its ID"""
cursor = self.connection.cursor()
cursor.execute(
"""INSERT OR IGNORE INTO engines
(name, displacement_cc, cylinders, fuel_type, power_hp, torque_nm, engine_code)
VALUES (?, ?, ?, ?, ?, ?, ?)""",
(name, displacement_cc, cylinders, fuel_type, power_hp, torque_nm, engine_code)
)
self.connection.commit()
# Return the ID of the inserted or existing engine
cursor.execute("SELECT id FROM engines WHERE name = ?", (name,))
return cursor.fetchone()[0]
def insert_model(self, brand_id: int, name: str, body_type: str = None,
generation: str = None, production_start_year: int = None,
production_end_year: int = None) -> int:
"""Insert a new model and return its ID"""
cursor = self.connection.cursor()
cursor.execute(
"""INSERT OR IGNORE INTO models
(brand_id, name, body_type, generation, production_start_year, production_end_year)
VALUES (?, ?, ?, ?, ?, ?)""",
(brand_id, name, body_type, generation, production_start_year, production_end_year)
)
self.connection.commit()
# Return the ID of the inserted or existing model
cursor.execute("SELECT id FROM models WHERE brand_id = ? AND name = ?", (brand_id, name))
return cursor.fetchone()[0]
def insert_year(self, year: int) -> int:
"""Insert a new year and return its ID"""
cursor = self.connection.cursor()
cursor.execute("INSERT OR IGNORE INTO years (year) VALUES (?)", (year,))
self.connection.commit()
# Return the ID of the inserted or existing year
cursor.execute("SELECT id FROM years WHERE year = ?", (year,))
return cursor.fetchone()[0]
def insert_model_year_engine(self, model_id: int, year_id: int, engine_id: int,
trim_level: str = None, drivetrain: str = None,
transmission: str = None):
"""Insert a model-year-engine combination"""
cursor = self.connection.cursor()
cursor.execute(
"""INSERT OR REPLACE INTO model_year_engine
(model_id, year_id, engine_id, trim_level, drivetrain, transmission)
VALUES (?, ?, ?, ?, ?, ?)""",
(model_id, year_id, engine_id, trim_level, drivetrain, transmission)
)
self.connection.commit()
def get_brands(self) -> List[Tuple]:
"""Retrieve all brands"""
cursor = self.connection.cursor()
cursor.execute("SELECT * FROM brands ORDER BY name")
return cursor.fetchall()
def get_models_by_brand(self, brand_id: int) -> List[Tuple]:
"""Retrieve all models for a specific brand"""
cursor = self.connection.cursor()
cursor.execute("""
SELECT m.*, b.name as brand_name
FROM models m
JOIN brands b ON m.brand_id = b.id
WHERE m.brand_id = ?
ORDER BY m.name
""", (brand_id,))
return cursor.fetchall()
def get_vehicle_info(self, brand_name: str = None, model_name: str = None,
year: int = None, engine_name: str = None) -> List[Tuple]:
"""Get comprehensive vehicle information based on filters"""
query = """
SELECT
b.name AS brand,
m.name AS model,
y.year,
e.name AS engine,
e.displacement_cc,
e.cylinders,
e.fuel_type,
e.power_hp,
e.torque_nm,
e.engine_code,
mye.trim_level,
mye.drivetrain,
mye.transmission
FROM model_year_engine mye
JOIN models m ON mye.model_id = m.id
JOIN brands b ON m.brand_id = b.id
JOIN years y ON mye.year_id = y.id
JOIN engines e ON mye.engine_id = e.id
WHERE 1=1
"""
params = []
if brand_name:
query += " AND b.name LIKE ?"
params.append(f"%{brand_name}%")
if model_name:
query += " AND m.name LIKE ?"
params.append(f"%{model_name}%")
if year:
query += " AND y.year = ?"
params.append(year)
if engine_name:
query += " AND e.name LIKE ?"
params.append(f"%{engine_name}%")
query += " ORDER BY b.name, m.name, y.year"
cursor = self.connection.cursor()
cursor.execute(query, params)
return cursor.fetchall()
def populate_sample_data(db_manager: VehicleDatabaseManager):
"""Populate the database with sample data"""
print("Populating sample data...")
# Insert sample brands
toyota_id = db_manager.insert_brand("Toyota", "Japan", 1937)
honda_id = db_manager.insert_brand("Honda", "Japan", 1948)
ford_id = db_manager.insert_brand("Ford", "USA", 1903)
bmw_id = db_manager.insert_brand("BMW", "Germany", 1916)
# Insert sample engines
engine_2jz = db_manager.insert_engine(
"2JZ-GTE",
displacement_cc=3000,
cylinders=6,
fuel_type="gasoline",
power_hp=320,
torque_nm=450,
engine_code="2JZ-GTE"
)
engine_k20 = db_manager.insert_engine(
"K20C1",
displacement_cc=2000,
cylinders=4,
fuel_type="gasoline",
power_hp=280,
torque_nm=260,
engine_code="K20C1"
)
engine_ecoboost = db_manager.insert_engine(
"EcoBoost V6",
displacement_cc=3500,
cylinders=6,
fuel_type="gasoline",
power_hp=375,
torque_nm=470,
engine_code="EcoBoost V6"
)
engine_n52 = db_manager.insert_engine(
"N52B30",
displacement_cc=3000,
cylinders=6,
fuel_type="gasoline",
power_hp=255,
torque_nm=310,
engine_code="N52B30"
)
# Insert sample models
camry_id = db_manager.insert_model(
toyota_id,
"Camry",
body_type="sedan",
generation="XV70",
production_start_year=2017,
production_end_year=None
)
civic_id = db_manager.insert_model(
honda_id,
"Civic",
body_type="sedan",
generation="XI",
production_start_year=2016,
production_end_year=None
)
mustang_id = db_manager.insert_model(
ford_id,
"Mustang",
body_type="coupe",
generation="S550",
production_start_year=2015,
production_end_year=None
)
x3_id = db_manager.insert_model(
bmw_id,
"X3",
body_type="suv",
generation="G01",
production_start_year=2017,
production_end_year=None
)
# Insert years
year_2020 = db_manager.insert_year(2020)
year_2021 = db_manager.insert_year(2021)
year_2022 = db_manager.insert_year(2022)
# Link models, years, and engines
db_manager.insert_model_year_engine(civic_id, year_2020, engine_k20, "Sport", "FWD", "automatic")
db_manager.insert_model_year_engine(mustang_id, year_2020, engine_ecoboost, "GT", "RWD", "automatic")
db_manager.insert_model_year_engine(x3_id, year_2021, engine_n52, "xDrive30i", "AWD", "automatic")
db_manager.insert_model_year_engine(camry_id, year_2022, engine_k20, "SE", "FWD", "automatic")
print("Sample data populated successfully!")
def main():
# Initialize the database manager
db_manager = VehicleDatabaseManager()
try:
# Connect to database
db_manager.connect()
# Create tables
db_manager.create_tables()
# Populate with sample data
populate_sample_data(db_manager)
# Demonstrate queries
print("\n--- All Brands ---")
brands = db_manager.get_brands()
for brand in brands:
print(f"ID: {brand['id']}, Name: {brand['name']}, Country: {brand['country']}")
print(f"\n--- Models for Toyota (ID: {brands[0]['id']}) ---")
toyota_models = db_manager.get_models_by_brand(brands[0]['id'])
for model in toyota_models:
print(f"Model: {model['name']}, Body Type: {model['body_type']}")
print("\n--- All Vehicle Information ---")
all_vehicles = db_manager.get_vehicle_info()
for vehicle in all_vehicles:
print(f"{vehicle['brand']} {vehicle['model']} {vehicle['year']} - "
f"{vehicle['engine']} ({vehicle['power_hp']} HP)")
print("\n--- Search for Honda Civic ---")
honda_civic = db_manager.get_vehicle_info(brand_name="Honda", model_name="Civic")
for vehicle in honda_civic:
print(f"{vehicle['brand']} {vehicle['model']} {vehicle['year']} - "
f"{vehicle['engine']} ({vehicle['power_hp']} HP)")
except Exception as e:
print(f"An error occurred: {e}")
finally:
# Close the connection
db_manager.disconnect()
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,193 @@
#!/usr/bin/env python3
"""
Simple Query Interface for Vehicle Database
Provides a command-line interface for searching the vehicle database
"""
import sqlite3
from typing import List, Tuple
class VehicleQueryInterface:
def __init__(self, db_path: str = "vehicle_database.db"):
self.db_path = db_path
def search_vehicles(self, brand: str = None, model: str = None, year: int = None,
engine: str = None, limit: int = 50) -> List[Tuple]:
"""Search for vehicles based on various criteria"""
conn = sqlite3.connect(self.db_path)
conn.row_factory = sqlite3.Row # Enable column access by name
cursor = conn.cursor()
query = """
SELECT
b.name AS brand,
m.name AS model,
y.year,
e.name AS engine,
e.displacement_cc,
e.cylinders,
e.fuel_type,
e.power_hp,
mye.trim_level,
mye.drivetrain,
mye.transmission
FROM model_year_engine mye
JOIN models m ON mye.model_id = m.id
JOIN brands b ON m.brand_id = b.id
JOIN years y ON mye.year_id = y.id
JOIN engines e ON mye.engine_id = e.id
WHERE 1=1
"""
params = []
if brand:
query += " AND b.name LIKE ?"
params.append(f"%{brand}%")
if model:
query += " AND m.name LIKE ?"
params.append(f"%{model}%")
if year:
query += " AND y.year = ?"
params.append(year)
if engine:
query += " AND e.name LIKE ?"
params.append(f"%{engine}%")
query += f" ORDER BY b.name, m.name, y.year LIMIT {limit}"
cursor.execute(query, params)
results = cursor.fetchall()
conn.close()
return results
def get_all_brands(self) -> List[Tuple]:
"""Get a list of all brands in the database"""
conn = sqlite3.connect(self.db_path)
conn.row_factory = sqlite3.Row
cursor = conn.cursor()
cursor.execute("SELECT DISTINCT name FROM brands ORDER BY name")
results = cursor.fetchall()
conn.close()
return [row[0] for row in results]
def get_models_by_brand(self, brand_name: str) -> List[Tuple]:
"""Get all models for a specific brand"""
conn = sqlite3.connect(self.db_path)
conn.row_factory = sqlite3.Row
cursor = conn.cursor()
cursor.execute("""
SELECT DISTINCT m.name
FROM models m
JOIN brands b ON m.brand_id = b.id
WHERE b.name = ?
ORDER BY m.name
""", (brand_name,))
results = cursor.fetchall()
conn.close()
return [row[0] for row in results]
def get_years_for_model(self, model_name: str) -> List[int]:
"""Get all years for a specific model"""
conn = sqlite3.connect(self.db_path)
conn.row_factory = sqlite3.Row
cursor = conn.cursor()
cursor.execute("""
SELECT DISTINCT y.year
FROM model_year_engine mye
JOIN models m ON mye.model_id = m.id
JOIN years y ON mye.year_id = y.id
WHERE m.name = ?
ORDER BY y.year
""", (model_name,))
results = cursor.fetchall()
conn.close()
return [row[0] for row in results]
def main():
interface = VehicleQueryInterface()
print("Vehicle Database Query Interface")
print("=================================")
while True:
print("\nOptions:")
print("1. Search vehicles")
print("2. List all brands")
print("3. List models for a brand")
print("4. List years for a model")
print("5. Exit")
choice = input("\nEnter your choice (1-5): ").strip()
if choice == "1":
print("\nSearch for vehicles:")
brand = input("Brand (optional): ").strip() or None
model = input("Model (optional): ").strip() or None
year_input = input("Year (optional): ").strip()
year = int(year_input) if year_input else None
engine = input("Engine (optional): ").strip() or None
results = interface.search_vehicles(brand=brand, model=model, year=year, engine=engine)
if results:
print(f"\nFound {len(results)} result(s):")
print("-" * 100)
for i, vehicle in enumerate(results, 1):
print(f"{i:2d}. {vehicle['year']} {vehicle['brand']} {vehicle['model']}")
print(f" Engine: {vehicle['engine']} ({vehicle['power_hp']} HP, {vehicle['displacement_cc']} cc)")
print(f" Trim: {vehicle['trim_level']}, Drivetrain: {vehicle['drivetrain']}, Transmission: {vehicle['transmission']}")
print()
else:
print("No vehicles found matching your criteria.")
elif choice == "2":
brands = interface.get_all_brands()
print(f"\nAll brands ({len(brands)}):")
for i, brand in enumerate(brands, 1):
print(f"{i:2d}. {brand}")
elif choice == "3":
brand = input("Enter brand name: ").strip()
if brand:
models = interface.get_models_by_brand(brand)
if models:
print(f"\nModels for {brand} ({len(models)}):")
for i, model in enumerate(models, 1):
print(f"{i:2d}. {model}")
else:
print(f"No models found for brand: {brand}")
else:
print("Please enter a brand name.")
elif choice == "4":
model = input("Enter model name: ").strip()
if model:
years = interface.get_years_for_model(model)
if years:
print(f"\nYears for {model} ({len(years)}):")
for i, year in enumerate(years, 1):
print(f"{i:2d}. {year}")
else:
print(f"No years found for model: {model}")
else:
print("Please enter a model name.")
elif choice == "5":
print("Thank you for using the Vehicle Database Query Interface!")
break
else:
print("Invalid choice. Please enter 1-5.")
if __name__ == "__main__":
main()

29
vehicle_database/setup.sh Executable file
View File

@@ -0,0 +1,29 @@
#!/bin/bash
# Setup script for Vehicle Database
echo "Vehicle Database Setup"
echo "======================"
# Check if Python3 is available
if ! command -v python3 &> /dev/null; then
echo "Python3 is required but not installed. Please install Python3 first."
exit 1
fi
echo "Python3 is available."
# Check if the database already exists
if [ -f "vehicle_database.db" ]; then
echo "Database already exists."
else
echo "Creating new database with sample data..."
python3 scripts/database_manager.py
fi
echo ""
echo "Setup complete! Available scripts:"
echo "1. Query Interface: python3 scripts/query_interface.py"
echo "2. Database Manager: python3 scripts/database_manager.py"
echo "3. CSV Importer: python3 scripts/csv_importer.py"
echo ""
echo "To start querying the database, run: python3 scripts/query_interface.py"

View File

@@ -0,0 +1,66 @@
-- Vehicle Database Schema
-- Tables for storing vehicle information: brands, years, models, and engines
-- Table for vehicle brands/manufacturers
CREATE TABLE IF NOT EXISTS brands (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL UNIQUE,
country TEXT,
founded_year INTEGER,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
-- Table for engine specifications
CREATE TABLE IF NOT EXISTS engines (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
displacement_cc REAL, -- Engine displacement in cubic centimeters
cylinders INTEGER, -- Number of cylinders
fuel_type TEXT CHECK(fuel_type IN ('gasoline', 'diesel', 'electric', 'hybrid', 'other')),
power_hp INTEGER, -- Horsepower
torque_nm INTEGER, -- Torque in Newton meters
engine_code TEXT, -- Manufacturer engine code
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
-- Table for vehicle models
CREATE TABLE IF NOT EXISTS models (
id INTEGER PRIMARY KEY AUTOINCREMENT,
brand_id INTEGER NOT NULL,
name TEXT NOT NULL,
body_type TEXT CHECK(body_type IN ('sedan', 'hatchback', 'suv', 'truck', 'coupe', 'convertible', 'wagon', 'van', 'other')),
generation TEXT, -- Model generation (e.g., MK1, MK2)
production_start_year INTEGER,
production_end_year INTEGER,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (brand_id) REFERENCES brands(id)
);
-- Table for years (to link with models)
CREATE TABLE IF NOT EXISTS years (
id INTEGER PRIMARY KEY AUTOINCREMENT,
year INTEGER NOT NULL UNIQUE,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
-- Junction table to connect models, years, and engines
CREATE TABLE IF NOT EXISTS model_year_engine (
id INTEGER PRIMARY KEY AUTOINCREMENT,
model_id INTEGER NOT NULL,
year_id INTEGER NOT NULL,
engine_id INTEGER NOT NULL,
trim_level TEXT, -- Trim level (e.g., base, luxury, sport)
drivetrain TEXT CHECK(drivetrain IN ('FWD', 'RWD', 'AWD', '4WD', 'other')),
transmission TEXT CHECK(transmission IN ('manual', 'automatic', 'CVT', 'other')),
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (model_id) REFERENCES models(id),
FOREIGN KEY (year_id) REFERENCES years(id),
FOREIGN KEY (engine_id) REFERENCES engines(id),
UNIQUE(model_id, year_id, engine_id, trim_level) -- Prevent duplicate combinations
);
-- Indexes for better performance
CREATE INDEX IF NOT EXISTS idx_models_brand ON models(brand_id);
CREATE INDEX IF NOT EXISTS idx_model_year_engine_model ON model_year_engine(model_id);
CREATE INDEX IF NOT EXISTS idx_model_year_engine_year ON model_year_engine(year_id);
CREATE INDEX IF NOT EXISTS idx_model_year_engine_engine ON model_year_engine(engine_id);

Binary file not shown.

View File

@@ -0,0 +1,175 @@
"""
Manual Data Extraction Guide for RockAuto.com
Since RockAuto has strong anti-bot measures, here's a manual approach to extract vehicle data:
1. Visit https://www.rockauto.com/
2. Click on "Catalog" in the navigation menu
3. You'll see a list of vehicle manufacturers (makes)
4. For each make, manually note down the models, years, and engines
This script provides a framework to input the manually collected data into your database.
"""
import sqlite3
from typing import List, Dict
class ManualDataInput:
def __init__(self, db_path: str = "../vehicle_database/vehicle_database.db"):
self.db_path = db_path
def add_vehicle_data(self, make: str, model: str, year: int, engine: str = "Unknown"):
"""Add a single vehicle entry to the database"""
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
try:
# Insert brand
cursor.execute(
"INSERT OR IGNORE INTO brands (name) VALUES (?)",
(make,)
)
cursor.execute("SELECT id FROM brands WHERE name = ?", (make,))
brand_id = cursor.fetchone()[0]
# Insert year
cursor.execute(
"INSERT OR IGNORE INTO years (year) VALUES (?)",
(year,)
)
cursor.execute("SELECT id FROM years WHERE year = ?", (year,))
year_id = cursor.fetchone()[0]
# Insert engine
cursor.execute(
"INSERT OR IGNORE INTO engines (name) VALUES (?)",
(engine,)
)
cursor.execute("SELECT id FROM engines WHERE name = ?", (engine,))
engine_id = cursor.fetchone()[0]
# Insert model
cursor.execute(
"INSERT OR IGNORE INTO models (brand_id, name) VALUES (?, ?)",
(brand_id, model)
)
cursor.execute("SELECT id FROM models WHERE brand_id = ? AND name = ?", (brand_id, model))
model_id = cursor.fetchone()[0]
# Link model, year, and engine
cursor.execute(
"""INSERT OR IGNORE INTO model_year_engine
(model_id, year_id, engine_id) VALUES (?, ?, ?)""",
(model_id, year_id, engine_id)
)
conn.commit()
print(f"Added: {year} {make} {model} with {engine}")
except Exception as e:
print(f"Error adding vehicle: {e}")
finally:
conn.close()
def add_multiple_vehicles(self, vehicles: List[Dict]):
"""Add multiple vehicles at once"""
for vehicle in vehicles:
self.add_vehicle_data(
make=vehicle.get('make', ''),
model=vehicle.get('model', ''),
year=vehicle.get('year', 0),
engine=vehicle.get('engine', 'Unknown')
)
def show_extraction_guide(self):
"""Show the manual extraction guide"""
guide = """
================================================
Manual RockAuto Data Extraction Guide
================================================
1. OPEN YOUR WEB BROWSER and go to: https://www.rockauto.com
2. CLICK on the "Catalog" link in the navigation menu
3. YOU WILL SEE a list of vehicle manufacturers (makes) like:
- Acura
- Audi
- BMW
- Chevrolet
- Ford
- Honda
- Toyota
- And many more...
4. FOR EACH MANUFACTURER:
a) Click on the manufacturer name
b) You'll see a page with vehicle models organized by year
c) Note down the models and years you see
d) Example format: 2020 Honda Civic, 2019 Ford F-150, etc.
5. TO FIND ENGINE INFORMATION:
a) Click on a specific model/year combination
b) You'll see parts categories for that vehicle
c) Look for "Engine" or "Engine Mechanical" category
d) Note down the engine type/specifications
6. USE THE FOLLOWING COMMANDS to add data to your database:
Example Python commands:
>>> from manual_input import ManualDataInput
>>> input_tool = ManualDataInput()
>>> input_tool.add_vehicle_data("Toyota", "Camry", 2020, "2.5L 4-Cylinder")
>>> input_tool.add_vehicle_data("Honda", "Civic", 2019, "1.5L Turbo")
Or add multiple at once:
>>> vehicles = [
... {"make": "Ford", "model": "F-150", "year": 2021, "engine": "3.5L V6"},
... {"make": "BMW", "model": "X3", "year": 2020, "engine": "2.0L 4-Cylinder Turbo"}
... ]
>>> input_tool.add_multiple_vehicles(vehicles)
7. TIPS FOR EFFICIENT DATA COLLECTION:
- Focus on popular makes/models first
- Record data in a spreadsheet as you go
- Take screenshots of pages for reference
- Be systematic - go alphabetically or by make popularity
================================================
"""
print(guide)
def main():
print("Manual RockAuto Data Extraction Tool")
print("=====================================")
input_tool = ManualDataInput()
# Show the extraction guide
input_tool.show_extraction_guide()
# Example of how to add data
print("\nExample - Adding sample data:")
sample_vehicles = [
{"make": "Toyota", "model": "Camry", "year": 2020, "engine": "2.5L 4-Cylinder"},
{"make": "Honda", "model": "Civic", "year": 2019, "engine": "1.5L Turbo"},
{"make": "Ford", "model": "F-150", "year": 2021, "engine": "3.5L V6"},
{"make": "BMW", "model": "X3", "year": 2020, "engine": "2.0L 4-Cylinder Turbo"},
{"make": "Chevrolet", "model": "Silverado", "year": 2022, "engine": "5.3L V8"}
]
print("Would you like to add these sample vehicles to your database? (y/n): ", end="")
response = input().lower()
if response == 'y':
input_tool.add_multiple_vehicles(sample_vehicles)
print("\nSample vehicles added to database!")
print("\nYou can now use the ManualDataInput class to add more vehicles manually.")
print("Import it in Python with: from manual_input import ManualDataInput")
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,171 @@
"""
Manual Data Extraction Guide for RockAuto.com
Since RockAuto has strong anti-bot measures, here's a manual approach to extract vehicle data:
1. Visit https://www.rockauto.com/
2. Click on "Catalog" in the navigation menu
3. You'll see a list of vehicle manufacturers (makes)
4. For each make, manually note down the models, years, and engines
This script provides a framework to input the manually collected data into your database.
"""
import sqlite3
from typing import List, Dict
class ManualDataInput:
def __init__(self, db_path: str = "../vehicle_database/vehicle_database.db"):
self.db_path = db_path
def add_vehicle_data(self, make: str, model: str, year: int, engine: str = "Unknown"):
"""Add a single vehicle entry to the database"""
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
try:
# Insert brand
cursor.execute(
"INSERT OR IGNORE INTO brands (name) VALUES (?)",
(make,)
)
cursor.execute("SELECT id FROM brands WHERE name = ?", (make,))
brand_id = cursor.fetchone()[0]
# Insert year
cursor.execute(
"INSERT OR IGNORE INTO years (year) VALUES (?)",
(year,)
)
cursor.execute("SELECT id FROM years WHERE year = ?", (year,))
year_id = cursor.fetchone()[0]
# Insert engine
cursor.execute(
"INSERT OR IGNORE INTO engines (name) VALUES (?)",
(engine,)
)
cursor.execute("SELECT id FROM engines WHERE name = ?", (engine,))
engine_id = cursor.fetchone()[0]
# Insert model
cursor.execute(
"INSERT OR IGNORE INTO models (brand_id, name) VALUES (?, ?)",
(brand_id, model)
)
cursor.execute("SELECT id FROM models WHERE brand_id = ? AND name = ?", (brand_id, model))
model_id = cursor.fetchone()[0]
# Link model, year, and engine
cursor.execute(
"""INSERT OR IGNORE INTO model_year_engine
(model_id, year_id, engine_id) VALUES (?, ?, ?)""",
(model_id, year_id, engine_id)
)
conn.commit()
print(f"Added: {year} {make} {model} with {engine}")
except Exception as e:
print(f"Error adding vehicle: {e}")
finally:
conn.close()
def add_multiple_vehicles(self, vehicles: List[Dict]):
"""Add multiple vehicles at once"""
for vehicle in vehicles:
self.add_vehicle_data(
make=vehicle.get('make', ''),
model=vehicle.get('model', ''),
year=vehicle.get('year', 0),
engine=vehicle.get('engine', 'Unknown')
)
def show_extraction_guide(self):
"""Show the manual extraction guide"""
guide = """
================================================
Manual RockAuto Data Extraction Guide
================================================
1. OPEN YOUR WEB BROWSER and go to: https://www.rockauto.com
2. CLICK on the "Catalog" link in the navigation menu
3. YOU WILL SEE a list of vehicle manufacturers (makes) like:
- Acura
- Audi
- BMW
- Chevrolet
- Ford
- Honda
- Toyota
- And many more...
4. FOR EACH MANUFACTURER:
a) Click on the manufacturer name
b) You'll see a page with vehicle models organized by year
c) Note down the models and years you see
d) Example format: 2020 Honda Civic, 2019 Ford F-150, etc.
5. TO FIND ENGINE INFORMATION:
a) Click on a specific model/year combination
b) You'll see parts categories for that vehicle
c) Look for "Engine" or "Engine Mechanical" category
d) Note down the engine type/specifications
6. USE THE FOLLOWING COMMANDS to add data to your database:
Example Python commands:
>>> from manual_input import ManualDataInput
>>> input_tool = ManualDataInput()
>>> input_tool.add_vehicle_data("Toyota", "Camry", 2020, "2.5L 4-Cylinder")
>>> input_tool.add_vehicle_data("Honda", "Civic", 2019, "1.5L Turbo")
Or add multiple at once:
>>> vehicles = [
... {"make": "Ford", "model": "F-150", "year": 2021, "engine": "3.5L V6"},
... {"make": "BMW", "model": "X3", "year": 2020, "engine": "2.0L 4-Cylinder Turbo"}
... ]
>>> input_tool.add_multiple_vehicles(vehicles)
7. TIPS FOR EFFICIENT DATA COLLECTION:
- Focus on popular makes/models first
- Record data in a spreadsheet as you go
- Take screenshots of pages for reference
- Be systematic - go alphabetically or by make popularity
================================================
"""
print(guide)
def main():
print("Manual RockAuto Data Extraction Tool")
print("=====================================")
input_tool = ManualDataInput()
# Show the extraction guide
input_tool.show_extraction_guide()
# Add sample vehicles to database
print("\nAdding sample vehicles to database:")
sample_vehicles = [
{"make": "Toyota", "model": "Camry", "year": 2020, "engine": "2.5L 4-Cylinder"},
{"make": "Honda", "model": "Civic", "year": 2019, "engine": "1.5L Turbo"},
{"make": "Ford", "model": "F-150", "year": 2021, "engine": "3.5L V6"},
{"make": "BMW", "model": "X3", "year": 2020, "engine": "2.0L 4-Cylinder Turbo"},
{"make": "Chevrolet", "model": "Silverado", "year": 2022, "engine": "5.3L V8"}
]
input_tool.add_multiple_vehicles(sample_vehicles)
print("\nSample vehicles added to database!")
print("\nYou can now use the ManualDataInput class to add more vehicles manually.")
print("Import it in Python with: from manual_input import ManualDataInput")
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,3 @@
requests
beautifulsoup4
lxml

View File

@@ -0,0 +1,292 @@
#!/usr/bin/env python3
"""
RockAuto Vehicle Data Scraper
Extracts vehicle information (brands, models, years, engines) from RockAuto.com
"""
import requests
from bs4 import BeautifulSoup
import time
import random
from urllib.parse import urljoin, urlparse
import json
import sqlite3
from typing import List, Dict, Optional
class RockAutoScraper:
def __init__(self, db_path: str = "../vehicle_database/vehicle_database.db"):
self.base_url = "https://www.rockauto.com"
self.session = requests.Session()
self.session.headers.update({
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
})
self.db_path = db_path
# Create a mapping of RockAuto brand names to standardized names
self.brand_mapping = {
'acura': 'Acura',
'alfa-romeo': 'Alfa Romeo',
'audi': 'Audi',
'bmw': 'BMW',
'buick': 'Buick',
'cadillac': 'Cadillac',
'chevrolet': 'Chevrolet',
'chrysler': 'Chrysler',
'dodge': 'Dodge',
'fiat': 'Fiat',
'ford': 'Ford',
'gmc': 'GMC',
'honda': 'Honda',
'hyundai': 'Hyundai',
'infiniti': 'Infiniti',
'isuzu': 'Isuzu',
'jaguar': 'Jaguar',
'jeep': 'Jeep',
'kia': 'Kia',
'land-rover': 'Land Rover',
'lexus': 'Lexus',
'lincoln': 'Lincoln',
'mazda': 'Mazda',
'mercedes-benz': 'Mercedes-Benz',
'mercury': 'Mercury',
'mitsubishi': 'Mitsubishi',
'nissan': 'Nissan',
'oldsmobile': 'Oldsmobile',
'plymouth': 'Plymouth',
'pontiac': 'Pontiac',
'porsche': 'Porsche',
'ram': 'Ram',
'saab': 'Saab',
'saturn': 'Saturn',
'scion': 'Scion',
'subaru': 'Subaru',
'suzuki': 'Suzuki',
'tesla': 'Tesla',
'toyota': 'Toyota',
'volkswagen': 'Volkswagen',
'volvo': 'Volvo'
}
def get_page(self, url: str) -> Optional[BeautifulSoup]:
"""Get a page and return BeautifulSoup object"""
try:
# Add random delay to be respectful to the server
time.sleep(random.uniform(1, 3))
response = self.session.get(url)
response.raise_for_status()
return BeautifulSoup(response.content, 'html.parser')
except requests.RequestException as e:
print(f"Error fetching {url}: {e}")
return None
def get_makes(self) -> List[str]:
"""Get list of makes from RockAuto"""
print("Fetching list of makes...")
soup = self.get_page(f"{self.base_url}/catalog/catalog.php")
if not soup:
return []
makes = []
# Look for make selection dropdown or similar element
make_elements = soup.find_all('a', href=lambda x: x and '/catalog/' in x and x.count('/') >= 3)
for elem in make_elements:
href = elem.get('href', '')
# Extract make from URL
parts = href.split('/')
for part in parts:
if part in self.brand_mapping:
make = self.brand_mapping[part]
if make not in makes:
makes.append(make)
# Alternative approach: look for common selector patterns
if not makes:
# Look for elements that might contain make information
links = soup.find_all('a', href=True)
for link in links:
href = link['href'].lower()
for key, value in self.brand_mapping.items():
if key in href and value not in makes:
makes.append(value)
print(f"Found {len(makes)} makes: {makes[:10]}{'...' if len(makes) > 10 else ''}")
return makes
def get_models_for_make(self, make: str) -> List[Dict]:
"""Get models for a specific make"""
print(f"Fetching models for {make}...")
# Convert make to RockAuto format
make_key = None
for key, value in self.brand_mapping.items():
if value.lower() == make.lower():
make_key = key
break
if not make_key:
print(f"Make {make} not found in mapping")
return []
models = []
soup = self.get_page(f"{self.base_url}/catalog/catalog.php?c={make_key}")
if not soup:
return models
# Look for model/year combinations
# RockAuto typically has links with year and model info
links = soup.find_all('a', href=True)
for link in links:
href = link['href']
text = link.get_text().strip()
# Look for patterns that indicate year/model/engine info
if any(char.isdigit() for char in text) and len(text) > 2:
# Try to extract year and model info
parts = text.split()
# Look for year (usually 4 digits)
year = None
model_parts = []
for part in parts:
if part.isdigit() and len(part) == 4 and 1900 < int(part) < 2030:
year = int(part)
else:
model_parts.append(part)
if model_parts and year:
model = ' '.join(model_parts)
# Create a record
record = {
'make': make,
'model': model,
'year': year,
'engine': 'Unknown', # Will need to extract from deeper pages
'href': href
}
if record not in models:
models.append(record)
print(f"Found {len(models)} models for {make}")
return models
def scrape_vehicle_data(self) -> List[Dict]:
"""Main method to scrape vehicle data from RockAuto"""
print("Starting RockAuto scraping...")
all_vehicles = []
# Get all makes
makes = self.get_makes()
# Limit to first 5 makes for testing
makes = makes[:5] if len(makes) > 5 else makes
for make in makes:
models = self.get_models_for_make(make)
all_vehicles.extend(models)
# Limit total records for testing
if len(all_vehicles) > 20:
break
print(f"Total vehicles found: {len(all_vehicles)}")
return all_vehicles
def save_to_database(self, vehicles: List[Dict]):
"""Save scraped data to the vehicle database"""
print(f"Saving {len(vehicles)} vehicles to database...")
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
for vehicle in vehicles:
try:
# Insert brand
cursor.execute(
"INSERT OR IGNORE INTO brands (name) VALUES (?)",
(vehicle['make'],)
)
cursor.execute("SELECT id FROM brands WHERE name = ?", (vehicle['make'],))
brand_id = cursor.fetchone()[0]
# Insert year
cursor.execute(
"INSERT OR IGNORE INTO years (year) VALUES (?)",
(vehicle['year'],)
)
cursor.execute("SELECT id FROM years WHERE year = ?", (vehicle['year'],))
year_id = cursor.fetchone()[0]
# Insert engine (with unknown specs for now)
cursor.execute(
"INSERT OR IGNORE INTO engines (name) VALUES (?)",
(vehicle['engine'],)
)
cursor.execute("SELECT id FROM engines WHERE name = ?", (vehicle['engine'],))
engine_id = cursor.fetchone()[0]
# Insert model
cursor.execute(
"INSERT OR IGNORE INTO models (brand_id, name) VALUES (?, ?)",
(brand_id, vehicle['model'])
)
cursor.execute("SELECT id FROM models WHERE brand_id = ? AND name = ?", (brand_id, vehicle['model']))
model_id = cursor.fetchone()[0]
# Link model, year, and engine
cursor.execute(
"""INSERT OR IGNORE INTO model_year_engine
(model_id, year_id, engine_id) VALUES (?, ?, ?)""",
(model_id, year_id, engine_id)
)
except Exception as e:
print(f"Error saving vehicle {vehicle}: {e}")
conn.commit()
conn.close()
print("Data saved to database successfully!")
def main():
scraper = RockAutoScraper()
print("Starting RockAuto data extraction...")
print("Note: This may take several minutes due to rate limiting.")
try:
# Scrape vehicle data
vehicles = scraper.scrape_vehicle_data()
if vehicles:
print(f"\nFound {len(vehicles)} vehicles:")
for i, v in enumerate(vehicles[:10]): # Show first 10
print(f" {i+1}. {v['make']} {v['model']} {v['year']}")
if len(vehicles) > 10:
print(f" ... and {len(vehicles)-10} more")
# Save to database
scraper.save_to_database(vehicles)
print("\nScraping completed successfully!")
else:
print("No vehicles found. This could be due to:")
print("1. RockAuto blocking automated requests")
print("2. Changes in website structure")
print("3. Network connectivity issues")
except Exception as e:
print(f"An error occurred during scraping: {e}")
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,400 @@
#!/usr/bin/env python3
"""
RockAuto Vehicle Data Scraper - Enhanced Version
Extracts vehicle information (brands, models, years, engines) from RockAuto.com
"""
import requests
from bs4 import BeautifulSoup
import time
import random
from urllib.parse import urljoin, urlparse
import json
import sqlite3
from typing import List, Dict, Optional
class RockAutoScraper:
def __init__(self, db_path: str = "../vehicle_database/vehicle_database.db"):
self.base_url = "https://www.rockauto.com"
self.session = requests.Session()
self.session.headers.update({
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
'Accept-Language': 'en-US,en;q=0.5',
'Accept-Encoding': 'gzip, deflate',
'Connection': 'keep-alive',
'Upgrade-Insecure-Requests': '1',
})
self.db_path = db_path
# Create a mapping of RockAuto brand names to standardized names
self.brand_mapping = {
'acura': 'Acura',
'alfa-romeo': 'Alfa Romeo',
'audi': 'Audi',
'bmw': 'BMW',
'buick': 'Buick',
'cadillac': 'Cadillac',
'chevrolet': 'Chevrolet',
'chrysler': 'Chrysler',
'dodge': 'Dodge',
'fiat': 'Fiat',
'ford': 'Ford',
'gmc': 'GMC',
'honda': 'Honda',
'hyundai': 'Hyundai',
'infiniti': 'Infiniti',
'isuzu': 'Isuzu',
'jaguar': 'Jaguar',
'jeep': 'Jeep',
'kia': 'Kia',
'land-rover': 'Land Rover',
'lexus': 'Lexus',
'lincoln': 'Lincoln',
'mazda': 'Mazda',
'mercedes-benz': 'Mercedes-Benz',
'mercury': 'Mercury',
'mitsubishi': 'Mitsubishi',
'nissan': 'Nissan',
'oldsmobile': 'Oldsmobile',
'plymouth': 'Plymouth',
'pontiac': 'Pontiac',
'porsche': 'Porsche',
'ram': 'Ram',
'saab': 'Saab',
'saturn': 'Saturn',
'scion': 'Scion',
'subaru': 'Subaru',
'suzuki': 'Suzuki',
'tesla': 'Tesla',
'toyota': 'Toyota',
'volkswagen': 'Volkswagen',
'volvo': 'Volvo'
}
def get_page(self, url: str) -> Optional[BeautifulSoup]:
"""Get a page and return BeautifulSoup object"""
try:
# Add random delay to be respectful to the server
time.sleep(random.uniform(2, 4))
response = self.session.get(url)
response.raise_for_status()
return BeautifulSoup(response.content, 'html.parser')
except requests.RequestException as e:
print(f"Error fetching {url}: {e}")
return None
def get_makes_enhanced(self) -> List[str]:
"""Enhanced method to get makes from RockAuto"""
print("Fetching list of makes (enhanced)...")
# Try multiple approaches to get makes
makes = []
# Approach 1: Visit the main catalog page
soup = self.get_page(f"{self.base_url}/catalog/catalog.php")
if not soup:
return makes
# Look for links that contain make information in the URL
links = soup.find_all('a', href=True)
for link in links:
href = link.get('href', '').lower()
# Check if the href contains a known make
for key, value in self.brand_mapping.items():
if f"/{key}/" in href and value not in makes:
makes.append(value)
# Approach 2: Look for JavaScript variables or data attributes that might contain makes
scripts = soup.find_all('script')
for script in scripts:
if script.string:
# Look for common patterns in JavaScript
import re
# Look for patterns like make names in quotes
matches = re.findall(r'["\']([a-z-]+)["\']', script.string)
for match in matches:
if match in self.brand_mapping and self.brand_mapping[match] not in makes:
makes.append(self.brand_mapping[match])
print(f"Found {len(makes)} makes: {makes[:10]}{'...' if len(makes) > 10 else ''}")
return makes
def get_detailed_models_for_make(self, make: str) -> List[Dict]:
"""Get detailed models for a specific make by exploring deeper pages"""
print(f"Fetching detailed models for {make}...")
# Convert make to RockAuto format
make_key = None
for key, value in self.brand_mapping.items():
if value.lower() == make.lower():
make_key = key
break
if not make_key:
print(f"Make {make} not found in mapping")
return []
models = []
# Visit the make-specific page
url = f"{self.base_url}/catalog/catalog.php?c={make_key}"
soup = self.get_page(url)
if not soup:
return models
# Look for year links first
year_links = soup.find_all('a', href=lambda x: x and f'/catalog/{make_key}/' in x and any(str(y) in x for y in range(1900, 2030)))
for link in year_links:
href = link.get('href', '')
text = link.get_text().strip()
# Extract year from URL or text
import re
year_match = re.search(r'\b(19|20)\d{2}\b', text)
if not year_match:
year_match = re.search(r'\b(19|20)\d{2}\b', href)
if year_match:
year = int(year_match.group())
# Extract model from text or URL
# Remove year from text to get model
model_text = re.sub(r'\b(19|20)\d{2}\b', '', text).strip()
if model_text:
# Create a record
record = {
'make': make,
'model': model_text,
'year': year,
'engine': 'Unknown', # Will need to extract from deeper pages
'href': href
}
if record not in models:
models.append(record)
# If no year-specific links found, try alternative approach
if not models:
# Look for links that might contain both make and year
all_links = soup.find_all('a', href=True)
for link in all_links:
href = link.get('href', '').lower()
text = link.get_text().strip()
if f"/{make_key}/" in href:
# Look for year in the text or href
year_match = re.search(r'\b(19|20)\d{2}\b', text)
if not year_match:
year_match = re.search(r'\b(19|20)\d{2}\b', href)
if year_match:
year = int(year_match.group())
# Extract model info
model_parts = [part for part in text.split() if not re.match(r'\b(19|20)\d{2}\b', part)]
model = ' '.join(model_parts)
if model:
record = {
'make': make,
'model': model,
'year': year,
'engine': 'Unknown',
'href': link.get('href')
}
if record not in models:
models.append(record)
print(f"Found {len(models)} models for {make}")
return models
def explore_categories(self, make: str) -> List[Dict]:
"""Explore categories for a specific make to find models and years"""
print(f"Exploring categories for {make}...")
# Convert make to RockAuto format
make_key = None
for key, value in self.brand_mapping.items():
if value.lower() == make.lower():
make_key = key
break
if not make_key:
print(f"Make {make} not found in mapping")
return []
models = []
# Visit the make-specific page
url = f"{self.base_url}/catalog/catalog.php?c={make_key}"
soup = self.get_page(url)
if not soup:
return models
# Look for elements that represent vehicle categories
# RockAuto typically organizes by year/model
category_elements = soup.find_all(['div', 'section', 'ul'], class_=lambda x: x and any(keyword in x.lower() for keyword in ['year', 'model', 'catalog', 'vehicle']))
if not category_elements:
# If no categorized elements found, try looking for all links with year info
all_links = soup.find_all('a', href=True)
for link in all_links:
href = link.get('href', '').lower()
text = link.get_text().strip()
if f"/{make_key}/" in href and any(str(year) in href for year in range(1900, 2030)):
# Extract year and model
import re
year_match = re.search(r'\b(19|20)\d{2}\b', href)
if year_match:
year = int(year_match.group())
# Clean up text to extract model
clean_text = re.sub(r'\b(19|20)\d{2}\b', '', text).strip(' -_')
if clean_text and len(clean_text) > 1:
record = {
'make': make,
'model': clean_text,
'year': year,
'engine': 'Unknown',
'href': link.get('href')
}
if record not in models:
models.append(record)
print(f"Found {len(models)} entries for {make} through category exploration")
return models
def scrape_vehicle_data(self) -> List[Dict]:
"""Main method to scrape vehicle data from RockAuto"""
print("Starting enhanced RockAuto scraping...")
all_vehicles = []
# Get all makes using enhanced method
makes = self.get_makes_enhanced()
# Limit to first 3 makes for testing
makes = makes[:3] if len(makes) > 3 else makes
for make in makes:
# Try multiple approaches to get models
models = self.get_detailed_models_for_make(make)
# If still no models, try category exploration
if not models:
models = self.explore_categories(make)
all_vehicles.extend(models)
# Limit total records for testing
if len(all_vehicles) > 15:
break
print(f"Total vehicles found: {len(all_vehicles)}")
return all_vehicles
def save_to_database(self, vehicles: List[Dict]):
"""Save scraped data to the vehicle database"""
print(f"Saving {len(vehicles)} vehicles to database...")
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
for vehicle in vehicles:
try:
# Insert brand
cursor.execute(
"INSERT OR IGNORE INTO brands (name) VALUES (?)",
(vehicle['make'],)
)
cursor.execute("SELECT id FROM brands WHERE name = ?", (vehicle['make'],))
brand_id = cursor.fetchone()[0]
# Insert year
cursor.execute(
"INSERT OR IGNORE INTO years (year) VALUES (?)",
(vehicle['year'],)
)
cursor.execute("SELECT id FROM years WHERE year = ?", (vehicle['year'],))
year_id = cursor.fetchone()[0]
# Insert engine (with unknown specs for now)
engine_name = vehicle['engine'] if vehicle['engine'] != 'Unknown' else f"Engine_{vehicle['year']}_{vehicle['model'][:10]}"
cursor.execute(
"INSERT OR IGNORE INTO engines (name) VALUES (?)",
(engine_name,)
)
cursor.execute("SELECT id FROM engines WHERE name = ?", (engine_name,))
engine_id = cursor.fetchone()[0]
# Insert model
cursor.execute(
"INSERT OR IGNORE INTO models (brand_id, name, body_type) VALUES (?, ?, ?)",
(brand_id, vehicle['model'], 'Unknown')
)
cursor.execute("SELECT id FROM models WHERE brand_id = ? AND name = ?", (brand_id, vehicle['model']))
model_id = cursor.fetchone()[0]
# Link model, year, and engine
cursor.execute(
"""INSERT OR IGNORE INTO model_year_engine
(model_id, year_id, engine_id) VALUES (?, ?, ?)""",
(model_id, year_id, engine_id)
)
except Exception as e:
print(f"Error saving vehicle {vehicle}: {e}")
conn.commit()
conn.close()
print("Data saved to database successfully!")
def main():
scraper = RockAutoScraper()
print("Starting enhanced RockAuto data extraction...")
print("Note: This may take several minutes due to rate limiting.")
try:
# Scrape vehicle data
vehicles = scraper.scrape_vehicle_data()
if vehicles:
print(f"\nFound {len(vehicles)} vehicles:")
for i, v in enumerate(vehicles[:10]): # Show first 10
print(f" {i+1}. {v['make']} {v['model']} {v['year']}")
if len(vehicles) > 10:
print(f" ... and {len(vehicles)-10} more")
# Save to database
scraper.save_to_database(vehicles)
print("\nScraping completed successfully!")
else:
print("No vehicles found. This could be due to:")
print("1. RockAuto blocking automated requests")
print("2. Changes in website structure")
print("3. Network connectivity issues")
print("4. Anti-bot measures implemented by RockAuto")
except Exception as e:
print(f"An error occurred during scraping: {e}")
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,350 @@
#!/usr/bin/env python3
"""
RockAuto Vehicle Data Scraper v2
Extrae información de vehículos (marcas, años, modelos, motores) de RockAuto.com
"""
import requests
from bs4 import BeautifulSoup
import time
import random
import sqlite3
import re
import sys
from typing import List, Dict, Set, Optional
from urllib.parse import unquote
class RockAutoScraperV2:
def __init__(self, db_path: str = "../vehicle_database/vehicle_database.db"):
self.base_url = "https://www.rockauto.com/en/catalog"
self.session = requests.Session()
self.session.headers.update({
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
'Accept-Language': 'en-US,en;q=0.5',
})
self.db_path = db_path
self.delay_range = (1, 2) # Segundos entre peticiones
def _delay(self):
"""Pausa respetuosa entre peticiones"""
time.sleep(random.uniform(*self.delay_range))
def _get_soup(self, url: str) -> Optional[BeautifulSoup]:
"""Obtiene y parsea una página"""
try:
self._delay()
response = self.session.get(url, timeout=30)
response.raise_for_status()
return BeautifulSoup(response.content, 'html.parser')
except Exception as e:
print(f" Error al obtener {url}: {e}")
return None
def _clean_name(self, name: str) -> str:
"""Limpia y formatea un nombre"""
name = unquote(name.replace('+', ' '))
name = re.sub(r'\s+', ' ', name).strip()
return name.upper()
def get_all_brands(self) -> List[str]:
"""Obtiene todas las marcas disponibles"""
print("Obteniendo lista de marcas...")
soup = self._get_soup(f"{self.base_url}/")
if not soup:
return []
brands = set()
links = soup.find_all('a', href=True)
for link in links:
href = link['href']
# Buscar enlaces como /en/catalog/MARCA
match = re.match(r'/en/catalog/([^,/]+)$', href)
if match:
brand = self._clean_name(match.group(1))
if brand and len(brand) > 1 and not brand.isdigit():
brands.add(brand)
brands_list = sorted(brands)
print(f" Encontradas {len(brands_list)} marcas")
return brands_list
def get_years_for_brand(self, brand: str) -> List[int]:
"""Obtiene los años disponibles para una marca"""
brand_url = brand.lower().replace(' ', '+')
soup = self._get_soup(f"{self.base_url}/{brand_url}")
if not soup:
return []
years = set()
links = soup.find_all('a', href=True)
for link in links:
href = link['href']
# Buscar patrones como /catalog/brand,YEAR
match = re.search(rf'/catalog/{re.escape(brand_url)},(\d{{4}})', href, re.IGNORECASE)
if match:
year = int(match.group(1))
if 1900 < year <= 2030:
years.add(year)
return sorted(years, reverse=True)
def get_models_for_brand_year(self, brand: str, year: int) -> List[str]:
"""Obtiene los modelos para una marca y año"""
brand_url = brand.lower().replace(' ', '+')
soup = self._get_soup(f"{self.base_url}/{brand_url},{year}")
if not soup:
return []
models = set()
links = soup.find_all('a', href=True)
for link in links:
href = link['href']
# Buscar patrones como /catalog/brand,year,MODEL
pattern = rf'/catalog/{re.escape(brand_url)},{year},([^,/]+)'
match = re.search(pattern, href, re.IGNORECASE)
if match:
model = self._clean_name(match.group(1))
if model and len(model) > 0 and not model.isdigit():
models.add(model)
return sorted(models)
def get_engines_for_vehicle(self, brand: str, year: int, model: str) -> List[str]:
"""Obtiene los motores para un vehículo específico"""
brand_url = brand.lower().replace(' ', '+')
model_url = model.lower().replace(' ', '+')
soup = self._get_soup(f"{self.base_url}/{brand_url},{year},{model_url}")
if not soup:
return []
engines = set()
links = soup.find_all('a', href=True)
for link in links:
href = link['href']
text = link.get_text().strip()
# Buscar patrones de motor en el href
pattern = rf'/catalog/{re.escape(brand_url)},{year},{re.escape(model_url)},([^,/]+)'
match = re.search(pattern, href, re.IGNORECASE)
if match:
engine = self._clean_name(match.group(1))
# Filtrar solo motores válidos (contienen L, V, cilindros, etc.)
if engine and re.search(r'\d+\.?\d*L|V\d|I\d|HYBRID|ELECTRIC|DIESEL', engine, re.IGNORECASE):
engines.add(engine)
return sorted(engines)
def scrape_brand(self, brand: str, max_years: int = None, max_models_per_year: int = None) -> List[Dict]:
"""Extrae todos los vehículos de una marca"""
print(f"\n{'='*50}")
print(f"Procesando marca: {brand}")
print('='*50)
vehicles = []
# Obtener años
years = self.get_years_for_brand(brand)
if max_years:
years = years[:max_years]
print(f" Años encontrados: {len(years)}")
for year in years:
print(f"\n Año {year}:")
# Obtener modelos
models = self.get_models_for_brand_year(brand, year)
if max_models_per_year:
models = models[:max_models_per_year]
print(f" Modelos: {len(models)}")
for model in models:
# Obtener motores
engines = self.get_engines_for_vehicle(brand, year, model)
if engines:
for engine in engines:
vehicle = {
'brand': brand,
'year': year,
'model': model,
'engine': engine
}
vehicles.append(vehicle)
print(f" {model} - {engine}")
else:
# Si no hay motores específicos, agregar con motor genérico
vehicle = {
'brand': brand,
'year': year,
'model': model,
'engine': 'Standard'
}
vehicles.append(vehicle)
print(f" {model} - (sin motor específico)")
print(f"\n Total vehículos para {brand}: {len(vehicles)}")
return vehicles
def save_to_database(self, vehicles: List[Dict]):
"""Guarda los vehículos en la base de datos"""
if not vehicles:
print("No hay vehículos para guardar")
return
print(f"\nGuardando {len(vehicles)} vehículos en la base de datos...")
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
saved = 0
skipped = 0
for vehicle in vehicles:
try:
# Insertar o obtener marca
cursor.execute(
"INSERT OR IGNORE INTO brands (name) VALUES (?)",
(vehicle['brand'],)
)
cursor.execute("SELECT id FROM brands WHERE name = ?", (vehicle['brand'],))
brand_id = cursor.fetchone()[0]
# Insertar o obtener año
cursor.execute(
"INSERT OR IGNORE INTO years (year) VALUES (?)",
(vehicle['year'],)
)
cursor.execute("SELECT id FROM years WHERE year = ?", (vehicle['year'],))
year_id = cursor.fetchone()[0]
# Insertar o obtener motor
cursor.execute(
"INSERT OR IGNORE INTO engines (name) VALUES (?)",
(vehicle['engine'],)
)
cursor.execute("SELECT id FROM engines WHERE name = ?", (vehicle['engine'],))
engine_id = cursor.fetchone()[0]
# Insertar o obtener modelo
cursor.execute(
"INSERT OR IGNORE INTO models (brand_id, name) VALUES (?, ?)",
(brand_id, vehicle['model'])
)
cursor.execute(
"SELECT id FROM models WHERE brand_id = ? AND name = ?",
(brand_id, vehicle['model'])
)
model_id = cursor.fetchone()[0]
# Insertar relación modelo-año-motor
cursor.execute(
"""INSERT OR IGNORE INTO model_year_engine
(model_id, year_id, engine_id) VALUES (?, ?, ?)""",
(model_id, year_id, engine_id)
)
if cursor.rowcount > 0:
saved += 1
else:
skipped += 1
except Exception as e:
print(f" Error guardando {vehicle}: {e}")
skipped += 1
conn.commit()
conn.close()
print(f" Guardados: {saved}, Omitidos (duplicados): {skipped}")
def scrape_multiple_brands(self, brands: List[str], **kwargs) -> List[Dict]:
"""Extrae vehículos de múltiples marcas"""
all_vehicles = []
for i, brand in enumerate(brands, 1):
print(f"\n[{i}/{len(brands)}] ", end="")
vehicles = self.scrape_brand(brand, **kwargs)
all_vehicles.extend(vehicles)
return all_vehicles
def main():
import argparse
parser = argparse.ArgumentParser(description='Scraper de vehículos de RockAuto')
parser.add_argument('--brands', nargs='+', help='Marcas específicas a extraer')
parser.add_argument('--all-brands', action='store_true', help='Extraer todas las marcas')
parser.add_argument('--max-years', type=int, default=5, help='Máximo de años por marca (default: 5)')
parser.add_argument('--max-models', type=int, help='Máximo de modelos por año')
parser.add_argument('--list-brands', action='store_true', help='Solo listar marcas disponibles')
parser.add_argument('--db', default='../vehicle_database/vehicle_database.db', help='Ruta a la base de datos')
args = parser.parse_args()
scraper = RockAutoScraperV2(db_path=args.db)
if args.list_brands:
brands = scraper.get_all_brands()
print("\nMarcas disponibles en RockAuto:")
for i, brand in enumerate(brands, 1):
print(f" {i:3}. {brand}")
print(f"\nTotal: {len(brands)} marcas")
return
# Determinar qué marcas procesar
if args.brands:
brands_to_scrape = [b.upper() for b in args.brands]
elif args.all_brands:
brands_to_scrape = scraper.get_all_brands()
else:
# Por defecto, algunas marcas populares
brands_to_scrape = ['TOYOTA', 'HONDA', 'FORD', 'CHEVROLET', 'NISSAN']
print(f"\nMarcas a procesar: {', '.join(brands_to_scrape)}")
print(f"Máximo años por marca: {args.max_years}")
if args.max_models:
print(f"Máximo modelos por año: {args.max_models}")
# Extraer datos
vehicles = scraper.scrape_multiple_brands(
brands_to_scrape,
max_years=args.max_years,
max_models_per_year=args.max_models
)
# Guardar en base de datos
if vehicles:
scraper.save_to_database(vehicles)
print(f"\n{'='*50}")
print("RESUMEN")
print('='*50)
print(f"Total de vehículos extraídos: {len(vehicles)}")
# Estadísticas
brands_count = len(set(v['brand'] for v in vehicles))
models_count = len(set(f"{v['brand']}-{v['model']}" for v in vehicles))
years_range = f"{min(v['year'] for v in vehicles)} - {max(v['year'] for v in vehicles)}"
print(f"Marcas: {brands_count}")
print(f"Modelos únicos: {models_count}")
print(f"Rango de años: {years_range}")
else:
print("\nNo se encontraron vehículos")
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,393 @@
#!/usr/bin/env python3
"""
Scraper de Ford y Chevrolet
- Procesa de 5 en 5 años
- Espera 3 minutos (180 segundos) entre lotes para activar VPN
- Presiona ENTER para saltar la espera
- Años: 1975-2026
"""
import requests
from bs4 import BeautifulSoup
import sqlite3
import time
import re
import os
import sys
import threading
from urllib.parse import unquote
# Detectar ruta base del proyecto
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
if os.path.basename(SCRIPT_DIR) == "vehicle_scraper":
BASE_DIR = os.path.dirname(SCRIPT_DIR)
else:
BASE_DIR = SCRIPT_DIR
DB_PATH = os.path.join(BASE_DIR, "vehicle_database", "vehicle_database.db")
BASE_URL = "https://www.rockauto.com/en/catalog"
# Marcas a scrapear (Nissan ya fue procesado)
BRANDS = ["FORD", "CHEVROLET"]
# Años de 1975 a 2026 (orden descendente)
ALL_YEARS = list(range(2026, 1974, -1))
# Configuración de lotes
BATCH_SIZE = 5 # años por lote
WAIT_TIME = 180 # 3 minutos entre lotes
session = requests.Session()
session.headers.update({
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
'Accept': 'text/html,application/xhtml+xml',
'Accept-Language': 'en-US,en;q=0.9',
})
# Variable global para controlar salto de espera
skip_wait = False
def wait_with_skip(seconds, message=""):
"""Espera que se puede saltar presionando ENTER"""
global skip_wait
skip_wait = False
print(f"\n{'*'*60}")
print(f" {message}")
print(f" ACTIVA/CAMBIA EL VPN AHORA")
print(f" >>> Presiona ENTER para saltar la espera <<<")
print(f"{'*'*60}")
# Usar threading para detectar input
def check_input():
global skip_wait
try:
input()
skip_wait = True
except:
pass
input_thread = threading.Thread(target=check_input, daemon=True)
input_thread.start()
for sec in range(seconds, 0, -1):
if skip_wait:
print(f"\n >>> ESPERA SALTADA <<<")
return
mins = sec // 60
secs = sec % 60
print(f"\r Continuando en {mins}:{secs:02d}... (ENTER para saltar) ", end="", flush=True)
time.sleep(1)
print()
def clean_name(name):
name = unquote(name.replace('+', ' '))
return re.sub(r'\s+', ' ', name).strip().upper()
def get_soup(url, retries=3):
for attempt in range(retries):
try:
time.sleep(0.5)
response = session.get(url, timeout=15)
if response.status_code == 200:
return BeautifulSoup(response.content, 'html.parser')
elif response.status_code == 403:
print(f"\n [!] Bloqueado (403) - Cambia el VPN")
return None
except Exception as e:
if attempt < retries - 1:
time.sleep(3)
else:
print(f"\n Error: {e}")
return None
def get_models(brand, year):
brand_url = brand.lower().replace(' ', '+')
soup = get_soup(f"{BASE_URL}/{brand_url},{year}")
if not soup:
return []
models = set()
for link in soup.find_all('a', href=True):
pattern = rf'/catalog/{re.escape(brand_url)},{year},([^,/]+)'
match = re.search(pattern, link['href'], re.I)
if match:
model = clean_name(match.group(1))
if model and not model.isdigit() and len(model) > 1:
models.add(model)
return sorted(models)
def get_engines(brand, year, model):
brand_url = brand.lower().replace(' ', '+')
model_url = model.lower().replace(' ', '+')
soup = get_soup(f"{BASE_URL}/{brand_url},{year},{model_url}")
if not soup:
return ['STANDARD']
engines = set()
for link in soup.find_all('a', href=True):
pattern = rf'/catalog/{re.escape(brand_url)},{year},{re.escape(model_url)},([^,/]+)'
match = re.search(pattern, link['href'], re.I)
if match:
engine = clean_name(match.group(1))
if engine and re.search(r'\d+\.?\d*L|V\d|I\d|H\d|HYBRID|ELECTRIC|DIESEL', engine, re.I):
engines.add(engine)
return sorted(engines) if engines else ['STANDARD']
def save_to_db(conn, brand, year, model, engine):
cursor = conn.cursor()
try:
cursor.execute("INSERT OR IGNORE INTO brands (name) VALUES (?)", (brand,))
cursor.execute("SELECT id FROM brands WHERE name = ?", (brand,))
brand_id = cursor.fetchone()[0]
cursor.execute("INSERT OR IGNORE INTO years (year) VALUES (?)", (year,))
cursor.execute("SELECT id FROM years WHERE year = ?", (year,))
year_id = cursor.fetchone()[0]
cursor.execute("INSERT OR IGNORE INTO engines (name) VALUES (?)", (engine,))
cursor.execute("SELECT id FROM engines WHERE name = ?", (engine,))
engine_id = cursor.fetchone()[0]
cursor.execute("INSERT OR IGNORE INTO models (brand_id, name) VALUES (?, ?)", (brand_id, model))
cursor.execute("SELECT id FROM models WHERE brand_id = ? AND name = ?", (brand_id, model))
model_id = cursor.fetchone()[0]
cursor.execute(
"INSERT OR IGNORE INTO model_year_engine (model_id, year_id, engine_id) VALUES (?, ?, ?)",
(model_id, year_id, engine_id)
)
return cursor.rowcount > 0
except Exception as e:
print(f" DB Error: {e}")
return False
def get_existing_years(conn, brand):
"""Obtiene los años que ya existen para esta marca"""
cursor = conn.cursor()
cursor.execute("""
SELECT DISTINCT y.year
FROM years y
JOIN model_year_engine mye ON y.id = mye.year_id
JOIN models m ON mye.model_id = m.id
JOIN brands b ON m.brand_id = b.id
WHERE b.name = ?
""", (brand,))
return set(row[0] for row in cursor.fetchall())
def process_batch(conn, brand, years_batch, batch_num, total_batches):
"""Procesa un lote de 5 años"""
print(f"\n{'='*60}")
print(f"[{brand}] LOTE {batch_num}/{total_batches}: Años {years_batch}")
print('='*60)
batch_saved = 0
batch_total = 0
for year in years_batch:
print(f"\n[{brand} - Año {year}] Obteniendo modelos... ", end="", flush=True)
models = get_models(brand, year)
print(f"{len(models)} modelos encontrados")
if not models:
print(f" No se encontraron modelos para {year}")
continue
for model in models:
engines = get_engines(brand, year, model)
for engine in engines:
batch_total += 1
if save_to_db(conn, brand, year, model, engine):
batch_saved += 1
print(f" {model} - {engine}")
# Guardar cambios del lote
conn.commit()
print(f"\n>> Lote {batch_num} completado: {batch_saved} nuevos de {batch_total} encontrados")
return batch_saved, batch_total
def get_brand_batches(conn, brand):
"""Obtiene los lotes disponibles para una marca"""
existing = get_existing_years(conn, brand)
years_to_process = [y for y in ALL_YEARS if y not in existing]
if not years_to_process:
return [], existing
batches = [years_to_process[i:i+BATCH_SIZE] for i in range(0, len(years_to_process), BATCH_SIZE)]
return batches, existing
def process_brand(conn, brand, start_batch=1):
"""Procesa una marca completa desde un lote específico"""
print(f"\n{'#'*60}")
print(f" PROCESANDO MARCA: {brand}")
print(f"{'#'*60}")
# Verificar qué años ya existen
existing = get_existing_years(conn, brand)
print(f"Años existentes de {brand}: {len(existing)} años")
if existing:
print(f" Rango existente: {min(existing)}-{max(existing)}")
# Filtrar solo los que faltan
years_to_process = [y for y in ALL_YEARS if y not in existing]
if not years_to_process:
print(f"\n[OK] {brand}: Todos los años ya están en la base de datos!")
return 0, 0
print(f"\nAños por procesar para {brand}: {len(years_to_process)}")
print(f" De {max(years_to_process)} a {min(years_to_process)}")
# Dividir en lotes de 5
batches = [years_to_process[i:i+BATCH_SIZE] for i in range(0, len(years_to_process), BATCH_SIZE)]
total_batches = len(batches)
print(f"Lotes de {BATCH_SIZE} años: {total_batches} lotes")
if start_batch > 1:
print(f"\n>>> Comenzando desde el lote {start_batch} <<<")
total_saved = 0
total_found = 0
for i, batch in enumerate(batches, 1):
# Saltar lotes anteriores al inicial
if i < start_batch:
continue
saved, found = process_batch(conn, brand, batch, i, total_batches)
total_saved += saved
total_found += found
# Si no es el último lote, esperar para cambiar VPN
if i < total_batches:
wait_with_skip(WAIT_TIME, f"PAUSA DE {WAIT_TIME//60} MINUTOS - [{brand}] Lotes restantes: {total_batches - i}")
return total_saved, total_found
def show_batch_menu(conn):
"""Muestra menú para seleccionar marca y lote inicial"""
print("\n" + "="*60)
print(" MENÚ DE SELECCIÓN DE LOTES")
print("="*60)
brand_info = {}
for i, brand in enumerate(BRANDS, 1):
batches, existing = get_brand_batches(conn, brand)
brand_info[brand] = {'batches': batches, 'existing': existing}
if batches:
print(f"\n {i}. {brand}")
print(f" Años existentes: {len(existing)}")
print(f" Lotes pendientes: {len(batches)}")
for j, batch in enumerate(batches, 1):
print(f" Lote {j}: años {batch[0]}-{batch[-1]}")
else:
print(f"\n {i}. {brand} - [COMPLETO]")
print(f"\n 0. Procesar todo desde el inicio")
print("="*60)
# Seleccionar marca
while True:
try:
choice = input("\nSelecciona marca (0 para todo): ").strip()
if choice == '0' or choice == '':
return None, 1 # Procesar todo
brand_idx = int(choice) - 1
if 0 <= brand_idx < len(BRANDS):
selected_brand = BRANDS[brand_idx]
break
print("Opción inválida")
except ValueError:
print("Ingresa un número válido")
batches = brand_info[selected_brand]['batches']
if not batches:
print(f"\n{selected_brand} ya está completo!")
return selected_brand, 1
# Seleccionar lote
print(f"\n--- Lotes de {selected_brand} ---")
for j, batch in enumerate(batches, 1):
print(f" {j}. Lote {j}: años {batch[0]}-{batch[-1]}")
while True:
try:
batch_choice = input(f"\nComenzar desde lote (1-{len(batches)}): ").strip()
if batch_choice == '':
return selected_brand, 1
batch_num = int(batch_choice)
if 1 <= batch_num <= len(batches):
return selected_brand, batch_num
print(f"Ingresa un número entre 1 y {len(batches)}")
except ValueError:
print("Ingresa un número válido")
def main():
print("="*60)
print(" SCRAPER FORD, CHEVROLET")
print(f" Años: 1975-2026 | Lotes de {BATCH_SIZE} años")
print(f" Pausa entre lotes: {WAIT_TIME//60} minutos")
print(" >>> Presiona ENTER para saltar esperas <<<")
print("="*60)
# Verificar base de datos
if not os.path.exists(DB_PATH):
print(f"\n[ERROR] Base de datos no encontrada: {DB_PATH}")
print("Verifica que la ruta sea correcta.")
sys.exit(1)
print(f"\nBase de datos: {DB_PATH}")
conn = sqlite3.connect(DB_PATH)
# Mostrar estado inicial
print(f"\nMarcas a procesar: {', '.join(BRANDS)}")
print(f"Rango de años: {min(ALL_YEARS)}-{max(ALL_YEARS)} ({len(ALL_YEARS)} años)")
# Menú de selección de lotes
selected_brand, start_batch = show_batch_menu(conn)
grand_total_saved = 0
grand_total_found = 0
brand_stats = {}
# Determinar qué marcas procesar
if selected_brand:
# Solo procesar la marca seleccionada desde el lote indicado
brands_to_process = [selected_brand]
start_batches = {selected_brand: start_batch}
else:
# Procesar todas las marcas desde el inicio
brands_to_process = BRANDS
start_batches = {brand: 1 for brand in BRANDS}
for brand in brands_to_process:
saved, found = process_brand(conn, brand, start_batches.get(brand, 1))
brand_stats[brand] = {'saved': saved, 'found': found}
grand_total_saved += saved
grand_total_found += found
# Pausa entre marcas (si hay otra marca por procesar)
if brand != brands_to_process[-1]:
wait_with_skip(WAIT_TIME, f"PAUSA ENTRE MARCAS - Siguiente: {brands_to_process[brands_to_process.index(brand)+1]}")
conn.close()
print("\n" + "="*60)
print(" RESUMEN FINAL")
print("="*60)
for brand, stats in brand_stats.items():
print(f" {brand}:")
print(f" Encontrados: {stats['found']}")
print(f" Nuevos guardados: {stats['saved']}")
print("-"*60)
print(f" TOTAL:")
print(f" Vehículos encontrados: {grand_total_found}")
print(f" Nuevos guardados: {grand_total_saved}")
print("="*60)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,163 @@
#!/usr/bin/env python3
"""
Script optimizado para extraer todos los vehículos Toyota de RockAuto
Guarda datos incrementalmente para no perder progreso
"""
import requests
from bs4 import BeautifulSoup
import sqlite3
import time
import re
import sys
from urllib.parse import unquote
DB_PATH = "/home/Autopartes/vehicle_database/vehicle_database.db"
BASE_URL = "https://www.rockauto.com/en/catalog"
session = requests.Session()
session.headers.update({
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
'Accept': 'text/html,application/xhtml+xml',
'Accept-Language': 'en-US,en;q=0.9',
})
def clean_name(name):
name = unquote(name.replace('+', ' '))
return re.sub(r'\s+', ' ', name).strip().upper()
def get_soup(url, retries=3):
for attempt in range(retries):
try:
time.sleep(0.3) # Delay corto
response = session.get(url, timeout=10)
if response.status_code == 200:
return BeautifulSoup(response.content, 'html.parser')
except Exception as e:
if attempt < retries - 1:
time.sleep(2)
else:
print(f" Error: {e}")
return None
def get_years(brand):
brand_url = brand.lower().replace(' ', '+')
soup = get_soup(f"{BASE_URL}/{brand_url}")
if not soup:
return []
years = set()
for link in soup.find_all('a', href=True):
match = re.search(rf'/catalog/{re.escape(brand_url)},(\d{{4}})', link['href'], re.I)
if match:
year = int(match.group(1))
if 1950 < year <= 2030:
years.add(year)
return sorted(years, reverse=True)
def get_models(brand, year):
brand_url = brand.lower().replace(' ', '+')
soup = get_soup(f"{BASE_URL}/{brand_url},{year}")
if not soup:
return []
models = set()
for link in soup.find_all('a', href=True):
pattern = rf'/catalog/{re.escape(brand_url)},{year},([^,/]+)'
match = re.search(pattern, link['href'], re.I)
if match:
model = clean_name(match.group(1))
if model and not model.isdigit() and len(model) > 1:
models.add(model)
return sorted(models)
def get_engines(brand, year, model):
brand_url = brand.lower().replace(' ', '+')
model_url = model.lower().replace(' ', '+')
soup = get_soup(f"{BASE_URL}/{brand_url},{year},{model_url}")
if not soup:
return []
engines = set()
for link in soup.find_all('a', href=True):
pattern = rf'/catalog/{re.escape(brand_url)},{year},{re.escape(model_url)},([^,/]+)'
match = re.search(pattern, link['href'], re.I)
if match:
engine = clean_name(match.group(1))
if engine and re.search(r'\d+\.?\d*L|V\d|I\d|H\d|HYBRID|ELECTRIC|DIESEL', engine, re.I):
engines.add(engine)
return sorted(engines) if engines else ['Standard']
def save_to_db(conn, brand, year, model, engine):
cursor = conn.cursor()
try:
cursor.execute("INSERT OR IGNORE INTO brands (name) VALUES (?)", (brand,))
cursor.execute("SELECT id FROM brands WHERE name = ?", (brand,))
brand_id = cursor.fetchone()[0]
cursor.execute("INSERT OR IGNORE INTO years (year) VALUES (?)", (year,))
cursor.execute("SELECT id FROM years WHERE year = ?", (year,))
year_id = cursor.fetchone()[0]
cursor.execute("INSERT OR IGNORE INTO engines (name) VALUES (?)", (engine,))
cursor.execute("SELECT id FROM engines WHERE name = ?", (engine,))
engine_id = cursor.fetchone()[0]
cursor.execute("INSERT OR IGNORE INTO models (brand_id, name) VALUES (?, ?)", (brand_id, model))
cursor.execute("SELECT id FROM models WHERE brand_id = ? AND name = ?", (brand_id, model))
model_id = cursor.fetchone()[0]
cursor.execute(
"INSERT OR IGNORE INTO model_year_engine (model_id, year_id, engine_id) VALUES (?, ?, ?)",
(model_id, year_id, engine_id)
)
return cursor.rowcount > 0
except Exception as e:
print(f" DB Error: {e}")
return False
def main():
brand = "TOYOTA"
print(f"Obteniendo años disponibles para {brand}...")
years = get_years(brand)
print(f"Encontrados {len(years)} años: {years[0]} - {years[-1]}")
# Filtrar solo 1975-2026
years = [y for y in years if 1975 <= y <= 2026]
print(f"Procesando años 1975-2026: {len(years)} años")
print("=" * 60)
conn = sqlite3.connect(DB_PATH)
total_saved = 0
total_vehicles = 0
for i, year in enumerate(years, 1):
print(f"\n[{i}/{len(years)}] Año {year}: ", end="", flush=True)
models = get_models(brand, year)
print(f"{len(models)} modelos")
year_count = 0
for model in models:
engines = get_engines(brand, year, model)
for engine in engines:
total_vehicles += 1
if save_to_db(conn, brand, year, model, engine):
total_saved += 1
year_count += 1
print(f" {model}: {engine}")
conn.commit()
print(f" -> Guardados: {year_count} nuevos")
conn.close()
print("\n" + "=" * 60)
print(f"RESUMEN TOYOTA")
print(f" Años procesados: {len(years)}")
print(f" Total vehículos encontrados: {total_vehicles}")
print(f" Nuevos guardados: {total_saved}")
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,240 @@
#!/usr/bin/env python3
"""
Scraper de Toyota para Windows
- Procesa de 3 en 3 años
- Espera 60 segundos entre lotes para activar VPN
- Años faltantes: 1975-2003
"""
import requests
from bs4 import BeautifulSoup
import sqlite3
import time
import re
import os
import sys
from urllib.parse import unquote
# Detectar ruta base del proyecto
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
# Si estamos en vehicle_scraper, subir un nivel
if os.path.basename(SCRIPT_DIR) == "vehicle_scraper":
BASE_DIR = os.path.dirname(SCRIPT_DIR)
else:
BASE_DIR = SCRIPT_DIR
DB_PATH = os.path.join(BASE_DIR, "vehicle_database", "vehicle_database.db")
BASE_URL = "https://www.rockauto.com/en/catalog"
# Años que faltan por scrapear
MISSING_YEARS = [
2003, 2002, 2001, 2000, 1999, 1998, 1997, 1996, 1995, 1994,
1993, 1992, 1991, 1990, 1989, 1988, 1987, 1986, 1985, 1984,
1983, 1982, 1981, 1980, 1979, 1978, 1977, 1976, 1975
]
session = requests.Session()
session.headers.update({
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
'Accept': 'text/html,application/xhtml+xml',
'Accept-Language': 'en-US,en;q=0.9',
})
def clean_name(name):
name = unquote(name.replace('+', ' '))
return re.sub(r'\s+', ' ', name).strip().upper()
def get_soup(url, retries=3):
for attempt in range(retries):
try:
time.sleep(0.5)
response = session.get(url, timeout=15)
if response.status_code == 200:
return BeautifulSoup(response.content, 'html.parser')
elif response.status_code == 403:
print(f"\n [!] Bloqueado (403) - Cambia el VPN")
return None
except Exception as e:
if attempt < retries - 1:
time.sleep(3)
else:
print(f"\n Error: {e}")
return None
def get_models(brand, year):
brand_url = brand.lower().replace(' ', '+')
soup = get_soup(f"{BASE_URL}/{brand_url},{year}")
if not soup:
return []
models = set()
for link in soup.find_all('a', href=True):
pattern = rf'/catalog/{re.escape(brand_url)},{year},([^,/]+)'
match = re.search(pattern, link['href'], re.I)
if match:
model = clean_name(match.group(1))
if model and not model.isdigit() and len(model) > 1:
models.add(model)
return sorted(models)
def get_engines(brand, year, model):
brand_url = brand.lower().replace(' ', '+')
model_url = model.lower().replace(' ', '+')
soup = get_soup(f"{BASE_URL}/{brand_url},{year},{model_url}")
if not soup:
return ['STANDARD']
engines = set()
for link in soup.find_all('a', href=True):
pattern = rf'/catalog/{re.escape(brand_url)},{year},{re.escape(model_url)},([^,/]+)'
match = re.search(pattern, link['href'], re.I)
if match:
engine = clean_name(match.group(1))
if engine and re.search(r'\d+\.?\d*L|V\d|I\d|H\d|HYBRID|ELECTRIC|DIESEL', engine, re.I):
engines.add(engine)
return sorted(engines) if engines else ['STANDARD']
def save_to_db(conn, brand, year, model, engine):
cursor = conn.cursor()
try:
cursor.execute("INSERT OR IGNORE INTO brands (name) VALUES (?)", (brand,))
cursor.execute("SELECT id FROM brands WHERE name = ?", (brand,))
brand_id = cursor.fetchone()[0]
cursor.execute("INSERT OR IGNORE INTO years (year) VALUES (?)", (year,))
cursor.execute("SELECT id FROM years WHERE year = ?", (year,))
year_id = cursor.fetchone()[0]
cursor.execute("INSERT OR IGNORE INTO engines (name) VALUES (?)", (engine,))
cursor.execute("SELECT id FROM engines WHERE name = ?", (engine,))
engine_id = cursor.fetchone()[0]
cursor.execute("INSERT OR IGNORE INTO models (brand_id, name) VALUES (?, ?)", (brand_id, model))
cursor.execute("SELECT id FROM models WHERE brand_id = ? AND name = ?", (brand_id, model))
model_id = cursor.fetchone()[0]
cursor.execute(
"INSERT OR IGNORE INTO model_year_engine (model_id, year_id, engine_id) VALUES (?, ?, ?)",
(model_id, year_id, engine_id)
)
return cursor.rowcount > 0
except Exception as e:
print(f" DB Error: {e}")
return False
def get_existing_years(conn, brand):
"""Obtiene los años que ya existen para esta marca"""
cursor = conn.cursor()
cursor.execute("""
SELECT DISTINCT y.year
FROM years y
JOIN model_year_engine mye ON y.id = mye.year_id
JOIN models m ON mye.model_id = m.id
JOIN brands b ON m.brand_id = b.id
WHERE b.name = ?
""", (brand,))
return set(row[0] for row in cursor.fetchall())
def process_batch(conn, brand, years_batch, batch_num, total_batches):
"""Procesa un lote de 3 años"""
print(f"\n{'='*60}")
print(f"LOTE {batch_num}/{total_batches}: Años {years_batch}")
print('='*60)
batch_saved = 0
batch_total = 0
for year in years_batch:
print(f"\n[Año {year}] Obteniendo modelos... ", end="", flush=True)
models = get_models(brand, year)
print(f"{len(models)} modelos encontrados")
if not models:
print(f" No se encontraron modelos para {year}")
continue
for model in models:
engines = get_engines(brand, year, model)
for engine in engines:
batch_total += 1
if save_to_db(conn, brand, year, model, engine):
batch_saved += 1
print(f" {model} - {engine}")
# Guardar cambios del lote
conn.commit()
print(f"\n>> Lote {batch_num} completado: {batch_saved} nuevos de {batch_total} encontrados")
return batch_saved, batch_total
def main():
brand = "TOYOTA"
print("="*60)
print(" SCRAPER TOYOTA - WINDOWS")
print(" Procesa 3 años, guarda, espera 60s para VPN")
print("="*60)
# Verificar base de datos
if not os.path.exists(DB_PATH):
print(f"\n[ERROR] Base de datos no encontrada: {DB_PATH}")
print("Verifica que la ruta sea correcta.")
sys.exit(1)
print(f"\nBase de datos: {DB_PATH}")
conn = sqlite3.connect(DB_PATH)
# Verificar qué años ya existen
existing = get_existing_years(conn, brand)
print(f"Años existentes de {brand}: {sorted(existing)}")
# Filtrar solo los que faltan
years_to_process = [y for y in MISSING_YEARS if y not in existing]
if not years_to_process:
print("\n[OK] Todos los años ya están en la base de datos!")
conn.close()
return
print(f"\nAños por procesar: {years_to_process}")
print(f"Total: {len(years_to_process)} años")
# Dividir en lotes de 3
batches = [years_to_process[i:i+3] for i in range(0, len(years_to_process), 3)]
total_batches = len(batches)
print(f"Lotes de 3 años: {total_batches} lotes")
input("\nPresiona ENTER para comenzar...")
total_saved = 0
total_found = 0
for i, batch in enumerate(batches, 1):
saved, found = process_batch(conn, brand, batch, i, total_batches)
total_saved += saved
total_found += found
# Si no es el último lote, esperar para cambiar VPN
if i < total_batches:
print(f"\n{'*'*60}")
print(f" PAUSA DE 60 SEGUNDOS - ACTIVA/CAMBIA EL VPN AHORA")
print(f" Lotes restantes: {total_batches - i}")
print(f"{'*'*60}")
for sec in range(60, 0, -1):
print(f"\r Continuando en {sec} segundos... ", end="", flush=True)
time.sleep(1)
print()
conn.close()
print("\n" + "="*60)
print(" RESUMEN FINAL - TOYOTA")
print("="*60)
print(f" Años procesados: {len(years_to_process)}")
print(f" Vehículos encontrados: {total_found}")
print(f" Nuevos guardados: {total_saved}")
print("="*60)
if __name__ == "__main__":
main()