Created
March 12, 2025 14:08
-
-
Save timendum/c0d6b78602f5c77e157e80b53c939836 to your computer and use it in GitHub Desktop.
Python script to find best prices for gas
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# /// script | |
# requires-python = ">=3.12" | |
# dependencies = [ | |
# "requests", | |
# ] | |
# /// | |
import argparse | |
import csv | |
import shutil | |
from datetime import datetime, timedelta | |
from os.path import getmtime | |
from typing import Iterable | |
import requests | |
def _load_csv(url: str, filename: str) -> Iterable[list[str]]: | |
download = True | |
try: | |
mtime = datetime.fromtimestamp(getmtime(filename)) | |
now = datetime.now() | |
if timedelta(hours=24) > (now - mtime): | |
download = False | |
except FileNotFoundError: | |
pass | |
if download: | |
with requests.get(url, stream=True) as r: | |
r.raw.decode_content = True | |
r.raise_for_status() | |
with open(filename, "wb") as f: | |
shutil.copyfileobj(r.raw, f) | |
with open(filename, newline="") as csvfile: | |
csvfile.read(26) # Header | |
prezzireader = csv.reader(csvfile, delimiter=";") | |
return list(prezzireader) | |
def load_prices() -> Iterable[list[str]]: | |
return _load_csv("https://www.mise.gov.it/images/exportCSV/prezzo_alle_8.csv", "prezzi.csv") | |
def load_stations() -> Iterable[list[str]]: | |
return _load_csv( | |
"https://www.mise.gov.it/images/exportCSV/anagrafica_impianti_attivi.csv", "impianti.csv" | |
) | |
def main_cli() -> None: | |
parser = argparse.ArgumentParser( | |
description="Trova i migliori prezzi di carburante intorno a te." | |
) | |
parser.add_argument( | |
"-c", | |
"--carburante", | |
type=str, | |
dest="fuel_type", | |
help="Tipo di carubrante (benzina, diesel, GPL, ...)", | |
default="benzina", | |
) | |
parser.add_argument( | |
"-r", | |
"--raggio", | |
type=float, | |
dest="radius", | |
help="Raggio di ricerca, in gradi decimali", | |
default=0.015, | |
) | |
parser.add_argument( | |
"-n", | |
"--numero", | |
type=int, | |
dest="limit", | |
help="Numero di risultati desiderati", | |
default=5, | |
) | |
parser.add_argument("lat", type=float, metavar="latitudine", help="Un numero tra i 47 e i 35") | |
parser.add_argument("long", type=float, metavar="longitudine", help="Un numero tra i 8 e i 18") | |
args = parser.parse_args() | |
return main(args) | |
def main(args: argparse.Namespace) -> None: | |
pradius = pow(args.radius, 2) | |
fuel_type = args.fuel_type.lower() | |
def filter_stations(s): | |
try: | |
return ( | |
pow(abs(float(s[8]) - args.lat), 2) + pow(abs(float(s[9]) - args.long), 2) < pradius | |
) | |
except: | |
# invalid rows | |
return False | |
stations = load_stations() | |
stations = [s for s in stations if filter_stations(s)] | |
id_stations = set([s[0] for s in stations]) | |
prices = load_prices() | |
prices = [p for p in prices if p[0] in id_stations] | |
prices = [p for p in prices if fuel_type in p[1].lower()] | |
prices = sorted(prices, key=lambda p: float(p[2])) | |
for price in prices[: args.limit]: | |
station = [s for s in stations if s[0] == price[0]][0] | |
print(station[1], station[5], station[6], price[2]) | |
main_cli() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment