Scraping Car Rental Platform Data (Grab Rentals, Turo, Getaround)
The car rental industry in Southeast Asia is undergoing a transformation. Traditional rental companies now compete with peer-to-peer platforms, ride-hailing rental services, and subscription-based mobility providers. For businesses operating in this space, understanding competitive pricing, fleet availability, and market dynamics requires systematic data collection from multiple platforms.
This guide covers how to scrape car rental data from major platforms operating in Southeast Asia, including Grab Rentals, Turo, Getaround, and regional providers, using proxy infrastructure to ensure reliable access.
The Car Rental Data Landscape in Southeast Asia
Platform Categories
Ride-Hailing Rentals:
- Grab Rentals (Singapore, Malaysia, Thailand, Indonesia, Philippines)
- Gojek car rental partnerships (Indonesia)
Peer-to-Peer Rentals:
- Turo (expanding into SEA markets)
- Getaround (select SEA cities)
- Drive Lah (Singapore)
- TREVO (Malaysia)
- Haupcar (Thailand)
Traditional Rental Companies:
- Avis, Budget, Hertz (regional operations)
- Local operators in each country
Subscription Services:
- Carro subscription
- Flux (Singapore)
Valuable Data Points
Car rental data includes:
- Daily, weekly, and monthly rental rates
- Vehicle availability by date and location
- Fleet composition (makes, models, years)
- Surge pricing patterns
- Insurance and add-on pricing
- Host/provider ratings and reviews
- Pickup and dropoff locations
- Mileage limits and excess charges
Proxy Setup for Rental Platform Scraping
Why Proxies Are Essential
Car rental platforms are particularly vigilant about scraping because pricing data is their competitive advantage. Rate comparison is core to consumer decision-making, so platforms invest heavily in preventing competitors from systematically collecting their prices.
DataResearchTools mobile proxies are especially effective for rental platform scraping because:
- Rental platforms see heavy mobile traffic from travelers and commuters
- Mobile IPs match expected user behavior on these platforms
- Geographic targeting is essential since rental prices vary by city
- Session management supports the multi-step booking flow simulation needed to see final prices
class RentalProxyManager:
def __init__(self, api_key):
self.api_key = api_key
self.endpoint = "proxy.dataresearchtools.com"
def get_proxy(self, country, city=None):
params = f"country-{country}-type-mobile"
if city:
params += f"-city-{city}"
session_id = uuid4().hex[:8]
params += f"-session-{session_id}"
return {
"http": f"http://{self.api_key}:{params}@{self.endpoint}:8080",
"https": f"http://{self.api_key}:{params}@{self.endpoint}:8080"
}Scraping Grab Rentals
Understanding Grab’s Rental Service
Grab Rentals allows users to rent vehicles through the Grab app, often for use as ride-hailing vehicles but also for personal use. The service is deeply integrated into Grab’s mobile app ecosystem.
Data Collection Strategy
Grab’s rental data is primarily available through their mobile app API. Mobile proxies are mandatory for accessing these endpoints:
class GrabRentalScraper:
def __init__(self, proxy_manager):
self.proxy_manager = proxy_manager
self.base_url = "https://api.grab.com"
self.headers = {
"User-Agent": "Grab/5.200.0 (Android 13; SM-S908B)",
"Accept": "application/json",
"X-Platform": "android",
}
def search_rentals(self, country, city, pickup_date, return_date):
proxy = self.proxy_manager.get_proxy(country, city)
params = {
"city": city,
"pickupDate": pickup_date,
"returnDate": return_date,
"vehicleType": "all",
}
response = requests.get(
f"{self.base_url}/rental/v1/vehicles",
params=params,
headers=self.headers,
proxies=proxy,
timeout=30
)
if response.status_code == 200:
return self.parse_rental_results(response.json())
return []
def parse_rental_results(self, data):
rentals = []
for vehicle in data.get("vehicles", []):
rentals.append({
"platform": "grab_rentals",
"vehicle_make": vehicle.get("make"),
"vehicle_model": vehicle.get("model"),
"vehicle_year": vehicle.get("year"),
"daily_rate": vehicle.get("dailyRate"),
"weekly_rate": vehicle.get("weeklyRate"),
"monthly_rate": vehicle.get("monthlyRate"),
"currency": vehicle.get("currency"),
"availability": vehicle.get("isAvailable"),
"location": vehicle.get("pickupLocation"),
"insurance_included": vehicle.get("insuranceIncluded"),
"mileage_limit": vehicle.get("dailyMileageLimit"),
"deposit": vehicle.get("securityDeposit"),
})
return rentalsScraping Peer-to-Peer Rental Platforms
Drive Lah (Singapore)
class DriveLahScraper:
def __init__(self, proxy_manager):
self.proxy_manager = proxy_manager
def search_vehicles(self, pickup_date, return_date, location="Singapore"):
proxy = self.proxy_manager.get_proxy("SG")
with sync_playwright() as p:
browser = p.chromium.launch(proxy={"server": proxy["http"]})
context = browser.new_context(
user_agent=get_random_mobile_ua(),
viewport={"width": 390, "height": 844}
)
page = context.new_page()
# Navigate to search
page.goto("https://www.drivelah.sg/search")
page.wait_for_load_state("networkidle")
# Fill search form
page.fill('[name="pickupDate"]', pickup_date)
page.fill('[name="returnDate"]', return_date)
page.click('[type="submit"]')
page.wait_for_selector('.vehicle-card')
# Extract listings
listings = page.evaluate("""
() => {
const cards = document.querySelectorAll('.vehicle-card');
return Array.from(cards).map(card => ({
title: card.querySelector('.vehicle-title')?.textContent?.trim(),
price: card.querySelector('.vehicle-price')?.textContent?.trim(),
rating: card.querySelector('.rating')?.textContent?.trim(),
trips: card.querySelector('.trip-count')?.textContent?.trim(),
location: card.querySelector('.location')?.textContent?.trim(),
features: Array.from(card.querySelectorAll('.feature')).map(f => f.textContent.trim()),
}));
}
""")
browser.close()
return listingsTREVO (Malaysia)
class TREVOScraper:
def __init__(self, proxy_manager):
self.proxy_manager = proxy_manager
def search_cars(self, city, pickup_date, return_date):
proxy = self.proxy_manager.get_proxy("MY")
session = requests.Session()
session.proxies.update(proxy)
session.headers.update({
"User-Agent": get_random_mobile_ua(),
"Accept-Language": "en-MY,en;q=0.9"
})
# TREVO search
response = session.get(
"https://www.trevo.my/search",
params={
"city": city,
"start": pickup_date,
"end": return_date,
},
timeout=30
)
if response.status_code == 200:
return self.parse_results(response.text)
return []
def parse_results(self, html):
soup = BeautifulSoup(html, 'html.parser')
cars = []
for card in soup.select('.car-card'):
cars.append({
"platform": "trevo",
"title": safe_text(card, '.car-name'),
"daily_rate": safe_text(card, '.daily-price'),
"rating": safe_text(card, '.host-rating'),
"trips_completed": safe_text(card, '.trip-count'),
"location": safe_text(card, '.car-location'),
"instant_booking": bool(card.select('.instant-badge')),
"features": [f.get_text(strip=True) for f in card.select('.car-feature')],
})
return carsPrice Monitoring and Analysis
Rate Comparison Across Platforms
class RentalRateComparator:
def compare_rates(self, city, vehicle_category, dates, scrapers):
all_rates = []
for scraper_name, scraper in scrapers.items():
try:
listings = scraper.search_vehicles(
pickup_date=dates["start"],
return_date=dates["end"],
location=city
)
for listing in listings:
if self.matches_category(listing, vehicle_category):
all_rates.append({
"platform": scraper_name,
"vehicle": listing.get("title"),
"daily_rate": self.parse_rate(listing.get("daily_rate")),
"total_cost": self.calculate_total(listing, dates),
"rating": listing.get("rating"),
})
except Exception as e:
logger.error(f"Failed to collect from {scraper_name}: {e}")
if all_rates:
rates_sorted = sorted(all_rates, key=lambda x: x["daily_rate"] or float('inf'))
return {
"city": city,
"category": vehicle_category,
"dates": dates,
"cheapest": rates_sorted[0],
"most_expensive": rates_sorted[-1],
"average_daily_rate": statistics.mean([r["daily_rate"] for r in rates_sorted if r["daily_rate"]]),
"all_options": rates_sorted,
"platform_count": len(set(r["platform"] for r in rates_sorted)),
}
return NoneDynamic Pricing Analysis
Rental prices fluctuate based on demand. Track these patterns over time:
class DynamicPricingAnalyzer:
def analyze_pricing_patterns(self, platform, city, vehicle_category):
"""Collect pricing data for different dates to identify patterns"""
pricing_data = []
# Check prices for the next 60 days
base_date = datetime.now()
for days_ahead in range(1, 61):
check_date = base_date + timedelta(days=days_ahead)
pickup = check_date.strftime("%Y-%m-%d")
return_date = (check_date + timedelta(days=1)).strftime("%Y-%m-%d")
rate = self.get_rate_for_date(platform, city, vehicle_category, pickup, return_date)
if rate:
pricing_data.append({
"date": pickup,
"day_of_week": check_date.strftime("%A"),
"days_ahead": days_ahead,
"daily_rate": rate,
"is_weekend": check_date.weekday() >= 5,
"is_holiday": self.is_holiday(check_date, city),
})
return self.identify_patterns(pricing_data)
def identify_patterns(self, data):
if not data:
return None
weekend_rates = [d["daily_rate"] for d in data if d["is_weekend"]]
weekday_rates = [d["daily_rate"] for d in data if not d["is_weekend"]]
holiday_rates = [d["daily_rate"] for d in data if d["is_holiday"]]
return {
"avg_weekday_rate": statistics.mean(weekday_rates) if weekday_rates else None,
"avg_weekend_rate": statistics.mean(weekend_rates) if weekend_rates else None,
"weekend_premium_pct": self.calculate_premium(weekday_rates, weekend_rates),
"holiday_premium_pct": self.calculate_premium(weekday_rates, holiday_rates) if holiday_rates else None,
"advance_booking_discount": self.analyze_advance_pricing(data),
"price_range": {
"min": min(d["daily_rate"] for d in data),
"max": max(d["daily_rate"] for d in data),
}
}Fleet Composition Analysis
Understand what vehicles are available for rent across platforms:
class FleetAnalyzer:
def analyze_fleet(self, platform_data):
all_vehicles = []
for platform, listings in platform_data.items():
for listing in listings:
all_vehicles.append({
"platform": platform,
"make": self.extract_make(listing["title"]),
"model": self.extract_model(listing["title"]),
"year": listing.get("year"),
"category": self.categorize_vehicle(listing),
})
return {
"total_vehicles": len(all_vehicles),
"by_platform": Counter(v["platform"] for v in all_vehicles),
"by_make": Counter(v["make"] for v in all_vehicles).most_common(10),
"by_category": Counter(v["category"] for v in all_vehicles),
"unique_models": len(set(f"{v['make']} {v['model']}" for v in all_vehicles)),
}
def categorize_vehicle(self, listing):
title = listing.get("title", "").lower()
rate = self.parse_rate(listing.get("daily_rate", ""))
if any(word in title for word in ["suv", "fortuner", "cr-v", "rav4", "x-trail"]):
return "SUV"
elif any(word in title for word in ["mpv", "alphard", "vellfire", "innova", "serena"]):
return "MPV"
elif any(word in title for word in ["luxury", "bmw", "mercedes", "audi", "lexus"]):
return "Luxury"
elif rate and rate < 50:
return "Economy"
else:
return "Standard"Building a Rental Rate Database
Storage Design
CREATE TABLE rental_rates (
id SERIAL PRIMARY KEY,
platform VARCHAR(50) NOT NULL,
country VARCHAR(5) NOT NULL,
city VARCHAR(100),
vehicle_make VARCHAR(100),
vehicle_model VARCHAR(200),
vehicle_year INTEGER,
vehicle_category VARCHAR(50),
daily_rate DECIMAL(10, 2),
weekly_rate DECIMAL(10, 2),
monthly_rate DECIMAL(10, 2),
currency VARCHAR(5),
insurance_included BOOLEAN,
mileage_limit_km INTEGER,
deposit_amount DECIMAL(10, 2),
host_rating DECIMAL(3, 2),
total_trips INTEGER,
instant_booking BOOLEAN,
scraped_for_date DATE,
scraped_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_rental_rates_search ON rental_rates(country, city, vehicle_category, scraped_for_date);Practical Applications
For Rental Companies
Use scraped data to price competitively and understand market positioning:
- Benchmark your rates against competitors by vehicle category and city
- Identify pricing gaps where you can be more competitive
- Track how competitors respond to demand fluctuations
- Optimize fleet composition based on demand signals
For Travel Platforms
Aggregate rental data to offer comparison features:
- Display rental options from multiple providers
- Show price trends and best booking windows
- Recommend vehicle categories based on destination and duration
For Fleet Investors
Analyze rental market data to make fleet investment decisions:
- Calculate potential rental income for different vehicle models
- Assess market saturation in specific cities
- Identify underserved vehicle categories with high demand
Conclusion
Car rental platform data is a strategic asset for anyone operating in the mobility space across Southeast Asia. From traditional rental companies to peer-to-peer platforms and ride-hailing rental services, each platform holds valuable pricing and availability data that can inform competitive strategy.
DataResearchTools mobile proxies provide the infrastructure to reliably collect this data from platforms that actively defend against scraping. With mobile IPs from carriers across Singapore, Malaysia, Thailand, Indonesia, and the Philippines, DataResearchTools ensures your rental data collection system can access the right geographic pricing and availability data from every major platform in the region.
Whether you are building a rental price comparison tool, optimizing a fleet operation, or analyzing the mobility market, systematic rental data collection powered by reliable proxy infrastructure gives you the visibility needed to make informed decisions.
- Automotive Inventory Tracking Across Multiple Dealer Websites
- Automotive Review Aggregation Using Proxy Networks
- How to Scrape AliExpress Product Data Without Getting Blocked
- Amazon Buy Box Monitoring: Proxy Setup for Continuous Tracking
- How Anti-Bot Systems Detect Scrapers (Cloudflare, Akamai, PerimeterX)
- API vs Web Scraping: When You Need Proxies (and When You Don’t)
- Automotive Inventory Tracking Across Multiple Dealer Websites
- Automotive Review Aggregation Using Proxy Networks
- aiohttp + BeautifulSoup: Async Python Scraping
- How to Scrape AliExpress Product Data Without Getting Blocked
- Amazon Buy Box Monitoring: Proxy Setup for Continuous Tracking
- How Anti-Bot Systems Detect Scrapers (Cloudflare, Akamai, PerimeterX)
- Automotive Inventory Tracking Across Multiple Dealer Websites
- Automotive Review Aggregation Using Proxy Networks
- aiohttp + BeautifulSoup: Async Python Scraping
- How to Scrape AliExpress Product Data Without Getting Blocked
- Amazon Buy Box Monitoring: Proxy Setup for Continuous Tracking
- How Anti-Bot Systems Detect Scrapers (Cloudflare, Akamai, PerimeterX)
Related Reading
- Automotive Inventory Tracking Across Multiple Dealer Websites
- Automotive Review Aggregation Using Proxy Networks
- aiohttp + BeautifulSoup: Async Python Scraping
- How to Scrape AliExpress Product Data Without Getting Blocked
- Amazon Buy Box Monitoring: Proxy Setup for Continuous Tracking
- How Anti-Bot Systems Detect Scrapers (Cloudflare, Akamai, PerimeterX)