Last active
September 2, 2024 04:56
-
-
Save icchan/329ea5202fc96e3e23e3ece27215e12e to your computer and use it in GitHub Desktop.
A basic script read Tesla's current Australian inventory. Intended to set up a price alert for myself.
This file contains 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
"""" Pulls car data from Tesla inventory API """ | |
from datetime import datetime | |
import json | |
import requests | |
from pprint import pprint | |
import argparse | |
def get_cars(model='m3', condition='used', region='NSW'): | |
""" Get cars from Tesla inventory API """ | |
query_template = ( | |
'{"query":{"model":"","condition":"","options":{},' | |
'"arrangeby":"Price","order":"asc","market":"AU","language":"en",' | |
'"super_region":"north america","region":""},' | |
'"offset":0,"count":50,"outsideOffset":0,"outsideSearch":false,' | |
'"isFalconDeliverySelectionEnabled":false,"version":null}') | |
query_data = json.loads(query_template) | |
# override query parameters here | |
query_data['query']['model'] = model | |
query_data['query']['condition'] = condition | |
query_data['query']['region'] = region | |
query_json = json.dumps(query_data) | |
encoded_query = requests.utils.quote(query_json) | |
url = f"https://www.tesla.com/inventory/api/v4/inventory-results?query={encoded_query}" | |
headers = { | |
'sec-fetch-dest': 'document', | |
'sec-fetch-mode': 'navigate', | |
'sec-fetch-site': 'none', | |
'sec-fetch-user': '?1', | |
'user-agent': 'Edg/128.0.0.0', | |
} | |
response = requests.request("GET", url, headers=headers, timeout=3) | |
# Get an array of the results | |
json_data = json.loads(response.text) | |
results = json_data.get("results", []) | |
# Check if results is not a list (api returns an object if no results) | |
if not isinstance(results, list): | |
results = [] | |
cars = [] | |
for result in results: | |
car = {} | |
car["retrieved_date"] = str(datetime.today().date()) | |
car["state"] = region | |
# basic info | |
car["vin"] = result.get("VIN","") | |
car["trim"] = result["TrimName"] | |
car["year"] = result["Year"] | |
car["build_date"] = result["ManufacturingYear"] | |
car["odometer"] = result["Odometer"] | |
car["price"] = result["InventoryPrice"] | |
car["purchase_price"] = result["PurchasePrice"] | |
car["location"] = result["City"] | |
car["factory"] = result["FactoryCode"] | |
car["battery_warranty"] = result["WarrantyBatteryExpDate"] | |
car["car_warranty"] = result["WarrantyVehicleExpDate"] | |
car["colour"] = result["PAINT"][0].lower() | |
# Extract other details from the deeper in the JSON | |
# Registration details | |
if result["RegistrationDetails"] is not None: | |
car["plates"] = result["RegistrationDetails"]["LicensePlateNumber"] | |
car["rego_expiry"] = result["RegistrationDetails"]["Expiration"] | |
else: | |
car["plates"] = "" | |
car["rego_expiry"] = "" | |
# Specs | |
specs = result["OptionCodeSpecs"]["C_SPECS"]["options"] | |
for spec in specs: | |
car[spec["code"].lower()] = spec["name"] | |
# Options | |
options = result["OptionCodeSpecs"]["C_OPTS"]["options"] | |
car["options"] = json.dumps(options) | |
## Note there are many other details in the JSON | |
## However, I didn't need them for my use case | |
cars.append(car) | |
return cars | |
def qprint(printable_cars): | |
""" Simple print function for car details """ | |
printable_cars.sort(key=lambda car: car['price']) | |
for car_detail in printable_cars: | |
print(car_detail['state'].ljust(4, ' ') | |
+ car_detail['vin'] | |
+ ' ' + f"{str(car_detail['plates'])}".ljust(7, ' ') | |
+ ' ' + str(car_detail['year']) | |
+ ' ' + f"{car_detail['odometer']:,}".rjust(6, ' ') + 'km' | |
+ ' $' + f"{car_detail['price']:,}" | |
+ ' ' + car_detail['specs_range'] | |
+ ' ' + car_detail['specs_acceleration'] | |
+ ' ' + car_detail['colour'].ljust(5, ' ') | |
+ ' ' + car_detail['trim']) | |
if __name__ == "__main__": | |
parser = argparse.ArgumentParser(description="Process some car data.") | |
parser.add_argument('--state', type=str, help='State to get car data for, default is ALL') | |
parser.add_argument('--out', type=str, help="Output format, 'short' or 'json'", default='short') | |
args = parser.parse_args() | |
STATES = [args.state] if args.state else ['NSW', 'VIC', 'QLD', 'SA', 'WA', 'TAS', 'NT', 'ACT'] | |
all_cars = [] | |
for state in STATES: | |
# get_region(state) | |
car_list = get_cars(region=state) | |
all_cars.extend(car_list) | |
if args.out == 'short': | |
qprint(all_cars) | |
else: | |
print(json.dumps(all_cars)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment