Repository navigation
Expand file tree
/
Copy pathmain.py
More file actions
87 lines (69 loc) · 2.7 KB
/
Copy pathmain.py
File metadata and controls
87 lines (69 loc) · 2.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
"""CLI entry point for the web scraper."""
import time
from typing import Literal
import typer
from rich.console import Console
from rich.table import Table
from scraper import DEFAULT_DELAY, scrape_pages
from scraper.exporter import export_books
from scraper.logging_setup import setup_logging
setup_logging()
app = typer.Typer(help="Extract catalog data from books.toscrape.com into CSV/Excel.")
console = Console()
@app.callback()
def callback() -> None:
"""Production-grade web scraper template."""
@app.command()
def scrape(
pages: int = typer.Option(1, "--pages", "-p", help="Number of listing pages to scrape"),
output: str = typer.Option(
"data/products", "--output", "-o", help="Output file path (extension optional)"
),
format: Literal["csv", "xlsx", "both"] = typer.Option(
"csv", "--format", "-f", help="Output format"
),
delay: float = typer.Option(
DEFAULT_DELAY, "--delay", "-d", help="Delay between requests in seconds"
),
enrich: bool = typer.Option(
True,
"--enrich/--no-enrich",
help="Fetch detail pages to fill fields missing from listings (e.g. category)",
),
) -> None:
"""Scrape books from books.toscrape.com and export to CSV/Excel.
Example:
python main.py scrape --pages 5 --output data/products --format both
"""
start_time = time.time()
try:
console.print(f"[bold]Scraping {pages} page(s) from books.toscrape.com[/bold]")
console.print(f"Format: {format} | Delay: {delay}s | Enrichment: {enrich}\n")
books = scrape_pages(max_pages=pages, delay=delay, enrich_details=enrich)
if not books:
console.print("[red]No books were scraped. Check the logs for errors.[/red]")
raise typer.Exit(1)
export_books(books, output, format=format)
elapsed_time = time.time() - start_time
table = Table(title="Scrape summary")
table.add_column("Metric", style="cyan")
table.add_column("Value", style="green")
table.add_row("Books scraped", str(len(books)))
table.add_row("Elapsed time", f"{elapsed_time:.2f}s")
if format == "csv":
table.add_row("Output", f"{output}.csv")
elif format == "xlsx":
table.add_row("Output", f"{output}.xlsx")
else:
table.add_row("Output", f"{output}.csv, {output}.xlsx")
console.print(table)
except typer.Exit:
raise
except KeyboardInterrupt:
console.print("\n[yellow]Scrape interrupted by user[/yellow]")
raise typer.Exit(1)
except Exception as e:
console.print(f"[red]Error during scrape: {e}[/red]")
raise typer.Exit(1)
if __name__ == "__main__":
app()