Skip to content

Instantly share code, notes, and snippets.

@timendum
Created March 12, 2025 14:08
Show Gist options
  • Save timendum/c0d6b78602f5c77e157e80b53c939836 to your computer and use it in GitHub Desktop.
Save timendum/c0d6b78602f5c77e157e80b53c939836 to your computer and use it in GitHub Desktop.
Python script to find best prices for gas
# /// 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