Skip to content

Playfast โšก

Lightning-Fast Google Play Store Scraper

Playfast is a high-performance Google Play Store scraper built with Rust + PyO3, delivering 5-10x faster performance with true parallel batch processing.

โœจ Features

  • ๐Ÿš€ Blazingly Fast: Batch API is 5-10x faster than sequential processing
  • โšก True Parallel: Rust core completely releases GIL for real parallelism
  • ๐Ÿฆ€ Pure Rust Performance: HTTP + parsing all in Rust
  • ๐Ÿ”’ Type Safe: Full Pydantic validation and type hints
  • ๐Ÿ’พ Memory Efficient: Only 1.5 KB per app, linear scaling
  • ๐ŸŒ Multi-Country: 247 countries, 93 unique Play Stores
  • ๐Ÿ“ฆ Batch API: High-level functions for easy parallel processing
  • ๐ŸŽฏ Python 3.11+: Full support for modern Python

๐Ÿ“Š Performance

Batch Processing makes bulk operations 5-10x faster through true Rust parallelism!

Benchmark Results

Batch Apps (3 apps ร— 3 countries = 9 requests):

Method Time Speedup
Batch API ~3s 6-8x ๐Ÿš€
RustClient + ThreadPool ~3-4s 6-7x
AsyncClient (concurrent) ~3-5s 5-7x
Sequential ~20-30s 1x (baseline)

Key Findings:

  • โšก Batch API is simplest and fastest
  • ๐ŸŽฏ 5-10x faster than sequential
  • ๐Ÿ’ก True parallel execution (Rust releases GIL)
  • ๐Ÿ”ฎ Linear scaling up to 1000s of requests

๐Ÿš€ Quick Start

Installation

# Using uv (recommended)
uv pip install playfast

# Using pip
pip install playfast
from playfast import fetch_apps, fetch_category_lists

# Fetch multiple apps across countries (parallel!)
apps = fetch_apps(
    app_ids=["com.spotify.music", "com.netflix.mediaclient"],
    countries=["us", "kr", "jp"],
    lang="en",
)
print(f"Fetched {len(apps)} apps in ~3 seconds!")

# Fetch top apps by category (parallel!)
results = fetch_category_lists(
    countries=["us", "kr"],
    categories=["GAME_ACTION", "SOCIAL"],
    collection="topselling_free",
    num_results=50,
)
print(f"Fetched {sum(len(r) for r in results)} apps!")

Option 2: RustClient (Maximum Performance)

from playfast import RustClient

# Synchronous API - simple and fast
client = RustClient(timeout=30)

# Get app information
app = client.get_app("com.spotify.music")
print(f"{app.title}: {app.score}โญ ({app.ratings:,} ratings)")

# Get reviews (paginated)
reviews, next_token = client.get_reviews("com.spotify.music")
for review in reviews:
    print(f"{review.user_name}: {review.content[:100]}")

# Search for apps
results = client.search("music streaming", n_hits=10)
for result in results:
    print(f"{result.title} - {result.score}โญ")

Option 3: AsyncClient (Easy Async Interface)

import asyncio
from playfast import AsyncClient


async def main():
    async with AsyncClient() as client:
        # Get app information
        app = await client.get_app("com.spotify.music")
        print(f"{app.title}: {app.score}โญ")

        # Stream reviews (async generator)
        async for review in client.stream_reviews("com.spotify.music"):
            print(f"{review.user_name}: {review.content[:100]}")


asyncio.run(main())

๐Ÿ—๏ธ Architecture

Playfast uses pure Rust for maximum performance:

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚   Python Layer (High-Level API)     โ”‚
โ”‚   - RustClient (wrapper)            โ”‚
โ”‚   - AsyncClient (async wrapper)     โ”‚
โ”‚   - Batch API (high-level)          โ”‚
โ”‚   - Pydantic Models                 โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
               โ”‚ PyO3 Bindings
               โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚   Rust Core (Maximum Performance)   โ”‚
โ”‚   - HTTP Client (reqwest)           โ”‚
โ”‚   - HTML Parser (scraper)           โ”‚
โ”‚   - Parallel Processing (rayon)     โ”‚
โ”‚   - Complete GIL Release            โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Three Client Options

  1. Batch API (Easiest & Fastest)

  2. High-level functions: fetch_apps(), fetch_category_lists(), etc.

  3. Automatic parallelization
  4. Simplest API
  5. Best for: Multiple items, bulk data collection

  6. RustClient (Maximum Performance)

  7. Rust HTTP + Rust parsing

  8. Complete GIL-free execution
  9. Synchronous API
  10. Best for: Single requests, simple scripts, batch with ThreadPoolExecutor

  11. AsyncClient (Async Interface)

  12. Python async HTTP + Rust parsing

  13. Natural async/await syntax
  14. Easy integration with async code
  15. Best for: Async codebases, I/O-bound tasks

Performance Comparison:

Method Speed Ease of Use Best For
Batch API โšกโšกโšก Fastest โญโญโญ Easiest Multiple items
RustClient โšกโšกโšก Fastest โญโญ Easy Single items
AsyncClient โšกโšก Fast โญโญ Easy Async code

๐Ÿ“š Examples

Batch API - Multi-Country Collection

from playfast import fetch_multi_country_apps

# Fetch Spotify from 8 countries (parallel!)
apps_by_country = fetch_multi_country_apps(
    app_id="com.spotify.music",
    countries=["us", "kr", "jp", "de", "fr", "gb", "br", "in"],
    lang="en",
)

for country, app in apps_by_country.items():
    print(f"{country.upper()}: {app.score}โญ ({app.ratings:,} ratings)")

RustClient - Parallel Batch Processing

from concurrent.futures import ThreadPoolExecutor
from playfast import RustClient

client = RustClient()

app_ids = [
    "com.spotify.music",
    "com.netflix.mediaclient",
    "com.instagram.android",
]

# True parallel execution (GIL-free!)
with ThreadPoolExecutor(max_workers=10) as executor:
    apps = list(executor.map(client.get_app, app_ids))

for app in apps:
    print(f"{app.title}: {app.score}โญ")

Country Optimization

from playfast import get_unique_countries, get_representative_country

# Instead of 247 countries, use 93 unique stores
unique = get_unique_countries()
print(f"Unique stores: {len(unique)}")  # 93

# Get representative for a region
rep = get_representative_country("fi")  # Finland โ†’ Vanuatu store
print(f"Finland uses {rep} store")  # 'vu'

๐Ÿ“– API Documentation

Batch API (High-Level)

# Fetch multiple apps
fetch_apps(app_ids: list[str], countries: list[str], lang: str = "en") -> list[AppInfo]

# Fetch category lists
fetch_category_lists(
    countries: list[str],
    categories: list[str],
    collection: str = "topselling_free",
    num_results: int = 100,
) -> list[list[SearchResult]]

# Search apps
search_apps(queries: list[str], countries: list[str], lang: str = "en") -> list[list[SearchResult]]

# Fetch reviews
fetch_reviews(app_ids: list[str], countries: list[str], sort: int = 1) -> list[tuple[list[Review], str | None]]

# Convenience: Multi-country for single app
fetch_multi_country_apps(app_id: str, countries: list[str], lang: str = "en") -> dict[str, AppInfo]

RustClient

class RustClient:
    def __init__(self, timeout: int = 30, lang: str = "en")

    # Core methods (all GIL-free!)
    def get_app(self, app_id: str, country: str = "us") -> AppInfo
    def get_reviews(self, app_id: str, sort: int = 1) -> tuple[list[Review], str | None]
    def get_all_reviews(self, app_id: str, max_pages: int | None = None) -> list[Review]
    def search(self, query: str, country: str = "us", n_hits: int = 30) -> list[SearchResult]

    # Async wrappers
    async def get_app_async(self, app_id: str, country: str = "us") -> AppInfo
    async def get_apps_parallel(self, app_ids: list[str], countries: list[str]) -> dict[str, list[AppInfo]]

AsyncClient

class AsyncClient:
    def __init__(self, max_concurrent: int = 10, timeout: int = 30)

    async def get_app(self, app_id: str, country: str = "us") -> AppInfo
    async def stream_reviews(self, app_id: str, sort: int = 1) -> AsyncIterator[Review]
    async def search(self, query: str, country: str = "us", n_hits: int = 30) -> list[SearchResult]

Models

  • AppInfo: Complete app information (title, score, ratings, description, permissions, etc.)
  • Review: User reviews with scores, content, timestamps
  • SearchResult: Search/list results with basic app info
  • Permission: Permission groups and individual permissions

See API Reference for complete documentation.

๐ŸŒ Countries & Categories

from playfast.constants import Category, Collection, get_countries, get_unique_countries

# All 247 countries
all_countries = get_countries()

# 93 unique Play Store regions (optimized!)
unique_countries = get_unique_countries()

# Categories
Category.GAME_ACTION
Category.SOCIAL
Category.PRODUCTIVITY

# Collections
Collection.TOP_FREE
Collection.TOP_PAID
Collection.TOP_GROSSING

๐Ÿ”ง Development

Setup

# Clone repository
git clone https://github.com/mixL1nk/playfast.git
cd playfast

# Install dependencies
uv sync

# Build Rust extension
uv run maturin develop --release

# Run tests
uv run pytest

# Run examples
uv run python examples/basic.py

# Run benchmarks
uv run python benchmarks/batch_apps_benchmark.py

See Development Setup for detailed instructions.

๐Ÿ“ License

MIT License - see License for details.

๐Ÿ™ Acknowledgments

โš ๏ธ Disclaimer

This tool is for educational and research purposes only. Please respect Google Play Store's Terms of Service. Use responsibly with appropriate rate limiting.

๐Ÿ“š Next Steps

  • Getting Started - Installation and basics
  • Quick Start - Practical examples
  • Batch API - Batch processing guide
  • See examples/ folder for real-world use cases
  • See benchmarks/ folder for performance tests

Made with โค๏ธ using Rust + Python