I was the second person on data analytics in Astara's newly launched Move department, a car subscription service with over 1,000 active vehicles. I wrote Python tools for fleet analysis, a scraper that tracked prices across 1,000+ competitors, and an automated weekly report that cut preparation time by over 90%.
The role
Astara is an automotive distributor with over $5 billion in annual revenue. The Move department had just launched a subscription-based alternative to car ownership and needed pricing and fleet data to compete. As the second person on data analytics, I built the tools the department used to price the fleet and report on it.
Main project
I built a web scraper that tracked subscription pricing across 1,000+ competitors. When Astara added a new model to the fleet, it returned the market average, median and range for that model from all tracked competitors.
- BeautifulSoup for static pages, Selenium for pages that render with JavaScript.
- Error handling and retries so a single failed site did not stop the run.
- Results stored in a database so price history could be plotted.
- Alerts when a competitor changed a price.
from selenium import webdriver
from selenium.webdriver.common.by import By
from bs4 import BeautifulSoup
import requests
import pandas as pd
class CompetitorPriceScraper:
def __init__(self, competitors_list):
self.competitors = competitors_list
self.driver = webdriver.Chrome()
def scrape_competitor(self, url, vehicle_model):
try:
self.driver.get(url)
# Wait for dynamic content to load
self.driver.implicitly_wait(5)
# Extract pricing data
price_element = self.driver.find_element(
By.CLASS_NAME, 'subscription-price'
)
price = float(price_element.text.replace('€', '').replace(',', ''))
return {
'vehicle': vehicle_model,
'competitor': url,
'price': price,
'timestamp': datetime.now()
}
except Exception as e:
print(f"Error scraping {url}: {e}")
return None
def get_market_average(self, vehicle_model):
prices = []
for competitor in self.competitors:
data = self.scrape_competitor(competitor, vehicle_model)
if data:
prices.append(data['price'])
return {
'average': np.mean(prices),
'median': np.median(prices),
'min': min(prices),
'max': max(prices)
}Other work
Alongside the scraper I worked on fleet analytics, the weekly executive report and bugs on the platform itself.
Fleet analytics and demand forecasting
Astara Move needed to know which vehicles to buy next. I analysed subscription data to find which models were most popular and fed that into fleet purchasing decisions.
- Compared demand across vehicle categories (sedans, SUVs, luxury, economy).
- Found seasonal demand patterns and peak subscription periods.
- Wrote up recommendations on fleet composition and expansion priorities.
- Pandas and NumPy for the analysis.
import pandas as pd
import numpy as np
from datetime import datetime
# Load subscription data from database
def analyze_vehicle_popularity(df):
# Group by vehicle model and calculate key metrics
popularity = df.groupby('vehicle_model').agg({
'subscription_id': 'count',
'subscription_duration': 'mean',
'revenue': 'sum'
})
# Calculate utilization rate
popularity['utilization_rate'] = (
popularity['subscription_id'] /
df.groupby('vehicle_model')['available_units'].first()
)
return popularity.sort_values('utilization_rate', ascending=False)
# Identify peak seasons
def find_peak_seasons(df):
df['month'] = pd.to_datetime(df['start_date']).dt.month
monthly_demand = df.groupby('month')['subscription_id'].count()
return monthly_demandAutomated weekly report
The weekly executive report used to take hours of manual data entry. I replaced it with a script that queries the databases, builds the charts and writes the PowerPoint, which cut preparation time by over 90%.
- SQL queries from Python against the company databases.
- Extraction, cleaning and aggregation in Pandas.
- Charts with Matplotlib and Seaborn.
- Slides generated with python-pptx.
import sqlite3
import pandas as pd
import matplotlib.pyplot as plt
from pptx import Presentation
from datetime import datetime, timedelta
class WeeklyReportGenerator:
def __init__(self, db_path):
self.conn = sqlite3.connect(db_path)
def fetch_weekly_metrics(self):
# Calculate date range for past week
end_date = datetime.now()
start_date = end_date - timedelta(days=7)
query = """
SELECT
DATE(subscription_start) as date,
COUNT(*) as new_subscriptions,
SUM(revenue) as daily_revenue,
AVG(customer_rating) as avg_rating
FROM subscriptions
WHERE subscription_start BETWEEN ? AND ?
GROUP BY DATE(subscription_start)
"""
return pd.read_sql_query(query, self.conn,
params=(start_date, end_date))
def generate_charts(self, data):
# Create revenue trend chart
plt.figure(figsize=(10, 6))
plt.plot(data['date'], data['daily_revenue'], marker='o')
plt.title('Weekly Revenue Trend')
plt.xlabel('Date')
plt.ylabel('Revenue (€)')
plt.savefig('weekly_revenue.png')
def create_presentation(self):
prs = Presentation()
# Add title slide
title_slide = prs.slides.add_slide(prs.slide_layouts[0])
title_slide.shapes.title.text = "Weekly Performance Report"
# Add data slides automatically...
# (Additional slide generation code)
prs.save('weekly_report.pptx')Platform bugs
While working with the platform data I found and reported pricing bugs on the Astara Move site.
- Prices that differed between the mobile and desktop versions of the site.
- Calculation errors in subscription renewal pricing.
- Documented and reported both to the department head.
Tools
Python (Pandas, NumPy, Matplotlib, Seaborn, python-pptx), BeautifulSoup, Selenium, Requests, and SQL.
Results
- The scraper tracked pricing across 1,000+ competitors and returned the market average, median and range for any new model.
- The automated weekly report cut preparation time by over 90%.
- The fleet analysis fed the department's decisions on which vehicles to buy next.
- Two pricing bugs on the Astara Move site were found, documented and reported.
- The scraper and analytics scripts kept being used after I left as the fleet grew past 1,000 vehicles.
What I learned
A small team can run a fast-growing operation if the routine work is automated. Replacing the manual weekly report and the manual price checks freed the team for the analysis itself, and the scraper and analytics scripts kept being used after I left as the fleet grew past 1,000 vehicles.
Working inside a $5 billion distributor also showed me how a new business unit gets set up in an established company, and how fleet purchasing decisions get made from the data.