<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: AlterLab</title>
    <description>The latest articles on DEV Community by AlterLab (@alterlab).</description>
    <link>https://dev.to/alterlab</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3842661%2F6ea3b67f-3a2b-423f-b726-51041ab344e6.png</url>
      <title>DEV Community: AlterLab</title>
      <link>https://dev.to/alterlab</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/alterlab"/>
    <language>en</language>
    <item>
      <title>Engineering Reliability: Telemetry, Migrations, and Security</title>
      <dc:creator>AlterLab</dc:creator>
      <pubDate>Tue, 28 Jul 2026 08:01:13 +0000</pubDate>
      <link>https://dev.to/alterlab/engineering-reliability-telemetry-migrations-and-security-1m9f</link>
      <guid>https://dev.to/alterlab/engineering-reliability-telemetry-migrations-and-security-1m9f</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;We have implemented per-vendor success-rate telemetry to provide granular visibility into proxy tier performance. We also introduced migration-ledger drift detection to ensure database integrity and hardened our URL validation logic to prevent scheme-prefix attacks.&lt;/p&gt;




&lt;h2&gt;
  
  
  Infrastructure Observability: Per-Vendor Telemetry
&lt;/h2&gt;

&lt;p&gt;Reliability in web scraping is often a moving target. As anti-bot measures evolve, the effectiveness of specific proxy providers or browser-emulation tiers changes. To manage this, we implemented a new telemetry layer to track success rates at a granular level.&lt;/p&gt;

&lt;p&gt;Previously, our diagnostics could tell us if a scrape failed, but they couldn't easily correlate that failure to a specific vendor at a specific tier. We have introduced &lt;code&gt;--vendor-tier-reliability&lt;/code&gt; to our infrastructure scripts. This provides a read-only aggregation over &lt;code&gt;scrape_diagnostics.tier_attempts[].antibot&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This allows us to answer a critical question: "For vendor X, what is the success rate at tier N?"&lt;/p&gt;

&lt;p&gt;This telemetry is vital for optimizing our &lt;a href="https://alterlab.io/smart-rendering-api" rel="noopener noreferrer"&gt;anti-bot handling&lt;/a&gt;. By understanding which vendor/tier combinations are failing on specific e-commerce or social media sites, we can automate better routing decisions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Database Integrity: Migration Reconciliation
&lt;/h2&gt;

&lt;p&gt;Data integrity is the foundation of any scalable API. During a recent audit, we identified a gap in our migration verification process. &lt;/p&gt;

&lt;p&gt;Our previous checks were one-directional. We could check if files existed for migrations that hadn't been applied, but we couldn't effectively check if the &lt;code&gt;schema_migrations&lt;/code&gt; table contained entries for files that didn't exist in the codebase (a common symptom of failed or rolled-back migrations).&lt;/p&gt;

&lt;p&gt;To solve this, we implemented &lt;strong&gt;migration-ledger drift detection&lt;/strong&gt;. This includes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Content Hash Verification&lt;/strong&gt;: Ensuring the code in the migration file matches what was actually executed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reconciliation&lt;/strong&gt;: Comparing the recorded rows in the database against the physical files in the repository to detect "ghost" migrations.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This prevents the "failed migration rollback" class of errors, where a rollback might target the wrong schema version, potentially causing catastrophic data loss in production.&lt;/p&gt;

&lt;h3&gt;
  
  
  Disaster Recovery Hardening
&lt;/h3&gt;

&lt;p&gt;Beyond schema integrity, we updated our Disaster Recovery (DR) scripts to prevent accidental production data loss. We identified a "Time-of-Check to Time-of-Use" (TOCTOU) vulnerability where our production-target confirmation gate was only checking the &lt;code&gt;POSTGRES_DB&lt;/code&gt; environment variable. &lt;/p&gt;

&lt;p&gt;If the &lt;code&gt;POSTGRES_CONTAINER&lt;/code&gt; resolved to a production container name (e.g., &lt;code&gt;alterlab-postgres&lt;/code&gt;), the script might proceed with a destructive &lt;code&gt;drop+recreate&lt;/code&gt; operation even if the database name didn't match. We have patched this to ensure that both the database name and the container identity are verified before any destructive operations occur.&lt;/p&gt;

&lt;h2&gt;
  
  
  Security Hardening: URL Scheme Validation
&lt;/h2&gt;

&lt;p&gt;Security is a continuous process of closing small gaps. We recently addressed a vulnerability in our announcement and public CTA models. &lt;/p&gt;

&lt;p&gt;The issue involved how we validated URLs. Our &lt;code&gt;validate_href_scheme&lt;/code&gt; function used a simple &lt;code&gt;startswith&lt;/code&gt; check for &lt;code&gt;http://&lt;/code&gt; and &lt;code&gt;https://&lt;/code&gt;. While this seems straightforward, it was susceptible to "userinfo-style construction" attacks. &lt;/p&gt;

&lt;p&gt;A malicious actor could provide a URL like:&lt;br&gt;
&lt;code&gt;https://good.tld@evil.tld&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Because the string starts with &lt;code&gt;https://&lt;/code&gt;, the old validation logic passed it. However, a browser would treat &lt;code&gt;evil.tld&lt;/code&gt; as the actual host, effectively redirecting the user away from the intended destination.&lt;/p&gt;

&lt;p&gt;We have updated our core href validation to properly parse the URL and validate the host, ensuring that the entire URI structure is legitimate.&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;```bash title="Terminal"&lt;/p&gt;

&lt;h1&gt;
  
  
  Example of how to verify your API implementation
&lt;/h1&gt;

&lt;p&gt;curl -X POST &lt;a href="https://api.alterlab.io/v1/scrape" rel="noopener noreferrer"&gt;https://api.alterlab.io/v1/scrape&lt;/a&gt; \&lt;br&gt;
  -H "X-API-Key: YOUR_KEY" \&lt;br&gt;
  -d '{"url": "&lt;a href="https://example.com" rel="noopener noreferrer"&gt;https://example.com&lt;/a&gt;", "formats": ["json"]}'&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


For developers building high-scale pipelines, these backend improvements mean more predictable performance. You can integrate our [Python SDK](https://alterlab.io/web-scraping-api-python) with confidence, knowing that our underlying infrastructure is continuously being audited for both reliability and security.



```python title="scraper.py" {1-4}

# The client handles complex routing and anti-bot logic automatically
client = alterlab.Client("YOUR_API_KEY")
response = client.scrape("https://example.com")
print(response.json())
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Summary of Updates
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Problem&lt;/th&gt;
&lt;th&gt;Solution&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Vendor Telemetry&lt;/td&gt;
&lt;td&gt;Lack of tier-specific visibility&lt;/td&gt;
&lt;td&gt;Per-vendor/tier success-rate aggregation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Migration Safety&lt;/td&gt;
&lt;td&gt;One-way drift detection&lt;/td&gt;
&lt;td&gt;Full reconciliation + content hash verification&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DR Scripts&lt;/td&gt;
&lt;td&gt;TOCTOU vulnerability&lt;/td&gt;
&lt;td&gt;Dual-key confirmation (DB + Container)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;URL Validation&lt;/td&gt;
&lt;td&gt;Scheme-prefix bypass&lt;/td&gt;
&lt;td&gt;Strict host-aware URL parsing&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If you are building data pipelines that require high uptime, we recommend reviewing our &lt;a href="https://alterlab.io/docs" rel="noopener noreferrer"&gt;API documentation&lt;/a&gt; to learn more about our advanced features like scheduling and webhooks.&lt;/p&gt;

&lt;p&gt;Hit reply if you have questions.&lt;/p&gt;

&lt;p&gt;AlterLab // Web Data, Simplified.&lt;/p&gt;

</description>
      <category>api</category>
      <category>datapipelines</category>
      <category>automation</category>
      <category>monitoring</category>
    </item>
    <item>
      <title>Scalable Web Scraping Architecture for AI Agents</title>
      <dc:creator>AlterLab</dc:creator>
      <pubDate>Fri, 24 Jul 2026 03:58:35 +0000</pubDate>
      <link>https://dev.to/alterlab/scalable-web-scraping-architecture-for-ai-agents-1akm</link>
      <guid>https://dev.to/alterlab/scalable-web-scraping-architecture-for-ai-agents-1akm</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;A scalable web scraping architecture for AI agents combines intelligent proxy rotation, managed headless browsers, and structured data extraction pipelines. This approach ensures reliable access to public web data while transforming raw HTML into AI-ready formats.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;AI agents need fresh, structured data from the web to power retrieval-augmented generation (RAG), monitoring, and automated decision-making. Building a scraping system that scales requires handling anti-bot measures, JavaScript rendering, and data transformation at scale. This guide outlines proven strategies for each layer, with practical examples using AlterLab's API.&lt;/p&gt;

&lt;h2&gt;
  
  
  Core Challenges
&lt;/h2&gt;

&lt;p&gt;Scraping at scale for AI agents introduces three primary challenges:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;IP blocking and rate limits&lt;/strong&gt;: Target sites restrict repeated requests from the same address.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;JavaScript-dependent content&lt;/strong&gt;: Modern sites load critical data via client-side scripts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data variability&lt;/strong&gt;: Raw HTML differs across sites, requiring adaptive extraction for consistent AI inputs.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Solving these requires a layered architecture where each concern is isolated and independently scalable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Proxy Rotation Strategies
&lt;/h2&gt;

&lt;p&gt;Effective proxy rotation prevents IP-based blocking by distributing requests across a diverse pool. Key tactics include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Geographic distribution&lt;/strong&gt;: Use proxies matching the target audience's region to reduce suspicion.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Session persistence&lt;/strong&gt;: Maintain the same proxy for multi-step interactions (e.g., pagination) to avoid session breaks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Failure detection&lt;/strong&gt;: Automatically retire proxies that return CAPTCHAs or error codes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;AlterLab handles proxy rotation automatically, but if building a custom solution, implement a proxy manager that scores providers by success rate and latency.&lt;/p&gt;

&lt;h2&gt;
  
  
  Headless Browser Management
&lt;/h2&gt;

&lt;p&gt;Headless browsers render JavaScript content but consume significant resources. Optimize with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Browser pooling&lt;/strong&gt;: Reuse browser instances to avoid startup overhead.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resource blocking&lt;/strong&gt;: Disable images, fonts, and unnecessary scripts to speed up rendering.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Context isolation&lt;/strong&gt;: Use separate browser contexts per session to prevent state leakage.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For AI agents, prioritize speed and reliability over full browser fidelity. Many sites only need basic DOM interaction after initial JS load.&lt;/p&gt;

&lt;h2&gt;
  
  
  Structured Data Extraction for AI Agents
&lt;/h2&gt;

&lt;p&gt;Raw HTML must become structured data before AI consumption. Strategies include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Schema-based extraction&lt;/strong&gt;: Define expected fields (price, availability, title) and use XPath/CSS selectors or AI models to locate them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Output format selection&lt;/strong&gt;: JSON for machine consumption, Markdown for LLM prompting, or plain text for simple tasks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validation and cleaning&lt;/strong&gt;: Strip HTML tags, normalize whitespace, and validate data types.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;AlterLab's &lt;code&gt;formats&lt;/code&gt; parameter lets you specify the output format directly in the request, eliminating post-processing steps.&lt;/p&gt;

&lt;h2&gt;
  
  
  Putting It All Together: Architecture Diagram
&lt;/h2&gt;

&lt;p&gt;A scalable system separates concerns into distinct services:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Ingestion API&lt;/strong&gt;: Accepts scrape jobs from AI agents and enqueues them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Worker Pool&lt;/strong&gt;: Executes scraping tasks using proxy rotation and headless browsers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Storage Layer&lt;/strong&gt;: Saves raw responses temporarily for retry logic.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Transformation Service&lt;/strong&gt;: Converts HTML to the requested format (JSON/Markdown).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Delivery Endpoint&lt;/strong&gt;: Pushes results to agents via webhook or polling queue.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This design allows horizontal scaling of workers and independent updates to extraction logic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code Examples
&lt;/h2&gt;

&lt;p&gt;Below are equivalent examples using AlterLab's Python SDK and raw cURL to scrape a product listing page and receive JSON output.&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;```python title="scraper.py" {3-5}&lt;/p&gt;

&lt;p&gt;client = alterlab.Client("YOUR_API_KEY")   # Initialize client&lt;br&gt;
response = client.scrape(                  # Perform scrape with JSON output&lt;br&gt;
    "&lt;a href="https://example.com/products" rel="noopener noreferrer"&gt;https://example.com/products&lt;/a&gt;",&lt;br&gt;
    formats=["json"]                       # Request structured JSON output&lt;br&gt;
)&lt;br&gt;
print(response.json())                     # Output structured data for AI agent&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




```bash title="Terminal"
curl -X POST https://api.alterlab.io/v1/scrape \
  -H "X-API-Key: YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/products",
    "formats": ["json"]
  }'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both examples request JSON output, ensuring the AI agent receives immediately usable data without additional parsing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Internal Links and Further Reading
&lt;/h2&gt;

&lt;p&gt;For implementation details, see the &lt;a href="https://alterlab.io/web-scraping-api-python" rel="noopener noreferrer"&gt;Python SDK&lt;/a&gt; and review the &lt;a href="https://alterlab.io/docs" rel="noopener noreferrer"&gt;API documentation&lt;/a&gt; for advanced parameters like &lt;code&gt;min_tier&lt;/code&gt; and &lt;code&gt;webhook_url&lt;/code&gt;. The &lt;a href="https://alterlab.io/smart-rendering-api" rel="noopener noreferrer"&gt;anti-bot handling&lt;/a&gt; page explains how AlterLab manages JavaScript challenges and proxy rotation automatically.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Building a scalable scraping architecture for AI agents requires separating concerns: manage proxies to maintain access, use headless browsers judiciously for JS rendering, and extract structured data that fits directly into AI pipelines. By leveraging a purpose-built API like AlterLab, engineering teams can focus on agent logic rather than infrastructure undifferentiated heavy lifting. Start with a small batch of test URLs, monitor success rates, and scale the worker pool as demand grows.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Takeaway&lt;/strong&gt;: Design your scraping system as a pipeline with distinct, scalable stages for networking, rendering, and transformation. Use structured output formats to minimize post-processing and keep AI agents fed with clean, reliable data.&lt;/p&gt;

</description>
      <category>dataextraction</category>
      <category>proxies</category>
      <category>headlessbrowsers</category>
      <category>antibot</category>
    </item>
    <item>
      <title>IMDB Data API: Extract Structured JSON in 2026</title>
      <dc:creator>AlterLab</dc:creator>
      <pubDate>Fri, 24 Jul 2026 00:13:37 +0000</pubDate>
      <link>https://dev.to/alterlab/imdb-data-api-extract-structured-json-in-2026-4lml</link>
      <guid>https://dev.to/alterlab/imdb-data-api-extract-structured-json-in-2026-4lml</guid>
      <description>&lt;h1&gt;
  
  
  IMDB Data API: Extract Structured JSON in 2026
&lt;/h1&gt;

&lt;p&gt;This guide covers extracting publicly accessible data. Always review a site's robots.txt and Terms of Service before scraping.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;To get structured IMDB data via API, use AlterLab's Extract API with a JSON schema defining your target fields (title, rating, genre, release_year, director). Send a POST request to &lt;code&gt;/v1/extract&lt;/code&gt; with the IMDB URL and schema to receive validated, typed JSON — eliminating HTML parsing and anti-bot challenges. This approach delivers clean data ready for immediate use in pipelines.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why use IMDB data?
&lt;/h2&gt;

&lt;p&gt;IMDB provides rich, publicly available entertainment datasets valuable for technical applications. Movie titles, ratings, and genres serve as excellent training data for recommendation system ML models. Analytics teams extract release year and director information to build box office trend dashboards. Competitive intelligence platforms monitor genre popularity shifts across streaming services to inform content acquisition strategies — all using publicly listed information without accessing private user data.&lt;/p&gt;

&lt;h2&gt;
  
  
  What data can you extract?
&lt;/h2&gt;

&lt;p&gt;From IMDB's publicly accessible pages, you can reliably extract these entertainment fields:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;title&lt;/strong&gt;: String (e.g., &lt;code&gt;"Parasite"&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;rating&lt;/strong&gt;: String (e.g., &lt;code&gt;"8.6"&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;genre&lt;/strong&gt;: String (e.g., &lt;code&gt;"Thriller, Drama, Comedy"&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;release_year&lt;/strong&gt;: String (e.g., &lt;code&gt;"2019"&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;director&lt;/strong&gt;: String (e.g., &lt;code&gt;"Bong Joon-ho"&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;AlterLab's Extract API returns these as typed JSON objects matching your defined schema. Only extract data visible without login or payment — never attempt to bypass access controls for private information.&lt;/p&gt;

&lt;h2&gt;
  
  
  The extraction approach
&lt;/h2&gt;

&lt;p&gt;Direct HTTP requests followed by HTML parsing create brittle pipelines. IMDB frequently updates its frontend markup, requiring constant selector maintenance. JavaScript-rendered content complicates raw HTTP approaches, while anti-bot measures trigger CAPTCHAs and IP blocks. &lt;/p&gt;

&lt;p&gt;A data API solves these infrastructure problems. AlterLab handles proxy rotation, automatic retries, and AI-powered understanding of page structure. You define &lt;em&gt;what&lt;/em&gt; data you need via JSON schema — not &lt;em&gt;how&lt;/em&gt; to parse it. The service returns validated output, letting your team focus on data utilization rather than extraction maintenance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick start with AlterLab Extract API
&lt;/h2&gt;

&lt;p&gt;Begin by installing the AlterLab client (&lt;a href="https://dev.to/docs/quickstart/installation"&gt;Getting started guide&lt;/a&gt;). Here's a Python example extracting structured data from an IMDB title page:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;```python title="extract_imdb-com.py" {5-12}&lt;/p&gt;

&lt;p&gt;client = alterlab.Client("YOUR_API_KEY")&lt;/p&gt;

&lt;p&gt;schema = {&lt;br&gt;
  "type": "object",&lt;br&gt;
  "properties": {&lt;br&gt;
    "title": {&lt;br&gt;
      "type": "string",&lt;br&gt;
      "description": "The movie title as displayed on IMDB"&lt;br&gt;
    },&lt;br&gt;
    "rating": {&lt;br&gt;
      "type": "string",&lt;br&gt;
      "description": "User rating value (e.g., '9.2')"&lt;br&gt;
    },&lt;br&gt;
    "genre": {&lt;br&gt;
      "type": "string",&lt;br&gt;
      "description": "Comma-separated genre list from page"&lt;br&gt;
    },&lt;br&gt;
    "release_year": {&lt;br&gt;
      "type": "string",&lt;br&gt;
      "description": "Original release year as four-digit string"&lt;br&gt;
    },&lt;br&gt;
    "director": {&lt;br&gt;
      "type": "string",&lt;br&gt;
      "description": "Primary director name"&lt;br&gt;
    }&lt;br&gt;
  }&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;result = client.extract(&lt;br&gt;
    url="&lt;a href="https://www.imdb.com/title/tt0111161/" rel="noopener noreferrer"&gt;https://www.imdb.com/title/tt0111161/&lt;/a&gt;",&lt;br&gt;
    schema=schema,&lt;br&gt;
)&lt;br&gt;
print(result.data)&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


**Output example:**


```json
{
  "title": "The Shawshank Redemption",
  "rating": "9.3",
  "genre": "Drama",
  "release_year": "1994",
  "director": "Frank Darabont"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The equivalent cURL request demonstrates language-agnostic accessibility:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;```bash title="Terminal"&lt;br&gt;
curl -X POST &lt;a href="https://api.alterlab.io/v1/extract" rel="noopener noreferrer"&gt;https://api.alterlab.io/v1/extract&lt;/a&gt; \&lt;br&gt;
  -H "X-API-Key: YOUR_KEY" \&lt;br&gt;
  -H "Content-Type: application/json" \&lt;br&gt;
  -d '{&lt;br&gt;
    "url": "&lt;a href="https://www.imdb.com/title/tt0111161/" rel="noopener noreferrer"&gt;https://www.imdb.com/title/tt0111161/&lt;/a&gt;",&lt;br&gt;
    "schema": {&lt;br&gt;
      "properties": {&lt;br&gt;
        "title": {"type": "string"},&lt;br&gt;
        "rating": {"type": "string"},&lt;br&gt;
        "genre": {"type": "string"},&lt;br&gt;
        "release_year": {"type": "string"},&lt;br&gt;
        "director": {"type": "string"}&lt;br&gt;
      }&lt;br&gt;
    }&lt;br&gt;
  }'&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


For asynchronous processing of multiple URLs (e.g., scraping search results), use the batch endpoint:



```python title="async_imdb_batch.py" {8-15}

client = alterlab.Client("YOUR_API_KEY")

schema = {
  "type": "object",
  "properties": {
    "title": {"type": "string"},
    "rating": {"type": "string"},
    "year": {"type": "string"}
  }
}

urls = [
  "https://www.imdb.com/chart/top/",
  "https://www.imdb.com/search/title/?genres=drama",
  "https://www.imdb.com/search/title/?release_date=2020-01-01,2020-12-31"
]

async def extract_batch():
    jobs = []
    for url in urls:
        job = await client.extract_async(
            url=url,
            schema=schema,
            webhook_url="https://yourdomain.com/webhook"
        )
        jobs.append(job.id)
    return results = await client.get_batch_results(jobs)

asyncio.run(extract_batch())
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Define your schema
&lt;/h2&gt;

&lt;p&gt;The JSON schema parameter is where you specify exactly what structured data you need. AlterLab validates all output against this schema, ensuring:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Type correctness (strings remain strings, numbers don't appear in string fields)&lt;/li&gt;
&lt;li&gt;Presence of required properties&lt;/li&gt;
&lt;li&gt;conformity to your defined descriptions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This eliminates guesswork and post-processing. For IMDB, note that some fields like "rating" appear as strings on the page (including potential non-numeric values like "Not Rated") — keeping them as strings in your schema prevents validation errors. The service handles AI interpretation of visual page elements to populate these fields accurately.&lt;/p&gt;

&lt;h2&gt;
  
  
  Handle pagination and scale
&lt;/h2&gt;

&lt;p&gt;For extracting data across multiple IMDB pages (e.g., top 250 lists or search results), implement pagination in your workflow. AlterLab manages rate limits internally through intelligent request spacing and retry logic. For high-volume operations:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Use the asynchronous extract endpoint shown above to non-blockingly process hundreds of URLs&lt;/li&gt;
&lt;li&gt;Configure webhooks to receive results without polling&lt;/li&gt;
&lt;li&gt;Monitor usage via your dashboard to optimize costs&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;See &lt;a href="https://dev.to/pricing"&gt;AlterLab pricing&lt;/a&gt; for details on pay-as-you-go scaling — charges occur only for successful extractions with no minimums or expiration. Typical IMDB extraction costs fractions of a cent per request at scale.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Structured data APIs like AlterLab's eliminate HTML parsing fragility for IMDB data extraction&lt;/li&gt;
&lt;li&gt;Define your output format upfront with JSON schema for type-safe, pipeline-ready data&lt;/li&gt;
&lt;li&gt;Focus on publicly available information: titles, ratings, genres, release years, and directors&lt;/li&gt;
&lt;li&gt;Let the API handle infrastructure complexities (proxies, rendering, anti-bot) while you concentrate on data value&lt;/li&gt;
&lt;li&gt;Always verify compliance with IMDB's robots.txt and Terms of Service before beginning extraction&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This approach transforms IMDB from a brittle HTML source into a reliable structured data feed for your entertainment analytics, ML training, or content intelligence applications — delivering JSON that's immediately consumable by downstream systems.  &lt;/p&gt;

&lt;p&gt;Hit reply if you have questions.&lt;/p&gt;

</description>
      <category>dataextraction</category>
      <category>api</category>
      <category>python</category>
      <category>datapipelines</category>
    </item>
    <item>
      <title>AutoTrader Data API: Extract Structured JSON in 2026</title>
      <dc:creator>AlterLab</dc:creator>
      <pubDate>Fri, 24 Jul 2026 00:13:36 +0000</pubDate>
      <link>https://dev.to/alterlab/autotrader-data-api-extract-structured-json-in-2026-1gm6</link>
      <guid>https://dev.to/alterlab/autotrader-data-api-extract-structured-json-in-2026-1gm6</guid>
      <description>&lt;p&gt;&lt;em&gt;Disclaimer: This guide covers extracting publicly accessible data. Always review a site's robots.txt and Terms of Service before scraping.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;To get structured AutoTrader data via API, use the AlterLab Extract API to send a target URL and a JSON schema. The API handles proxy rotation and AI-powered extraction to return typed JSON (make, model, year, price, etc.) without requiring custom HTML parsers or CSS selectors.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why use AutoTrader data?
&lt;/h2&gt;

&lt;p&gt;Automotive data is high-velocity and high-value. Engineers build data pipelines for AutoTrader listings to power several specific use cases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Market Analytics&lt;/strong&gt;: Tracking real-time price fluctuations for specific makes and models to determine fair market value.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;AI Training &amp;amp; RAG&lt;/strong&gt;: Feeding structured vehicle specifications into Large Language Models to build automotive recommendation engines.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Competitive Intelligence&lt;/strong&gt;: Monitoring inventory levels and pricing strategies across different geographic regions to optimize dealership listings.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What data can you extract?
&lt;/h2&gt;

&lt;p&gt;You can retrieve any data point that is publicly visible on a vehicle detail page or search results page. Common fields include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Vehicle Identity&lt;/strong&gt;: Make, model, trim level, and production year.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Pricing&lt;/strong&gt;: Current listing price, original MSRP, and any indicated price drops.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Condition&lt;/strong&gt;: Current mileage, engine type, transmission, and drivetrain.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Provenance&lt;/strong&gt;: Vehicle history status, number of previous owners, and location (city/state).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The extraction approach
&lt;/h2&gt;

&lt;p&gt;Traditional web scraping relies on CSS selectors or XPath. This is fragile. When AutoTrader updates a class name from &lt;code&gt;.vehicle-price-value&lt;/code&gt; to &lt;code&gt;.price-amount&lt;/code&gt;, your pipeline breaks. &lt;/p&gt;

&lt;p&gt;A data API approach removes this dependency. Instead of telling the system &lt;em&gt;where&lt;/em&gt; the data is (the selector), you tell the system &lt;em&gt;what&lt;/em&gt; the data is (the schema). The API analyzes the page content and maps it to your requested JSON keys. This ensures that your pipeline remains stable even if the website's frontend architecture changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick start with AlterLab Extract API
&lt;/h2&gt;

&lt;p&gt;To begin, follow the &lt;a href="https://dev.to/docs/quickstart/installation"&gt;Getting started guide&lt;/a&gt; to set up your environment. The Extract API allows you to pass a URL and a schema definition in a single request.&lt;/p&gt;

&lt;p&gt;Refer to the &lt;a href="https://dev.to/docs/api/extract"&gt;Extract API docs&lt;/a&gt; for full parameter definitions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Python Implementation
&lt;/h3&gt;

&lt;p&gt;The following example demonstrates how to extract core vehicle specifications from a listing page.&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;```python title="extract_autotrader-com.py" {5-26}&lt;/p&gt;

&lt;p&gt;client = alterlab.Client("YOUR_API_KEY")&lt;/p&gt;

&lt;p&gt;schema = {&lt;br&gt;
  "type": "object",&lt;br&gt;
  "properties": {&lt;br&gt;
    "make": {&lt;br&gt;
      "type": "string",&lt;br&gt;
      "description": "The make field"&lt;br&gt;
    },&lt;br&gt;
    "model": {&lt;br&gt;
      "type": "string",&lt;br&gt;
      "description": "The model field"&lt;br&gt;
    },&lt;br&gt;
    "year": {&lt;br&gt;
      "type": "string",&lt;br&gt;
      "description": "The year field"&lt;br&gt;
    },&lt;br&gt;
    "price": {&lt;br&gt;
      "type": "string",&lt;br&gt;
      "description": "The price field"&lt;br&gt;
    },&lt;br&gt;
    "mileage": {&lt;br&gt;
      "type": "string",&lt;br&gt;
      "description": "The mileage field"&lt;br&gt;
    },&lt;br&gt;
    "location": {&lt;br&gt;
      "type": "string",&lt;br&gt;
      "description": "The location field"&lt;br&gt;
    }&lt;br&gt;
  }&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;result = client.extract(&lt;br&gt;
    url="&lt;a href="https://autotrader.com/example-page" rel="noopener noreferrer"&gt;https://autotrader.com/example-page&lt;/a&gt;",&lt;br&gt;
    schema=schema,&lt;br&gt;
)&lt;br&gt;
print(result.data)&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


### cURL Implementation
For lightweight integrations or shell scripts, use the REST endpoint directly.



```bash title="Terminal"
curl -X POST https://api.alterlab.io/v1/extract \
  -H "X-API-Key: YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://autotrader.com/example-page",
    "schema": {"properties": {"make": {"type": "string"}, "model": {"type": "string"}, "year": {"type": "string"}}}
  }'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Define your schema
&lt;/h2&gt;

&lt;p&gt;The power of a data API lies in the schema. AlterLab uses the schema not just for formatting, but for validation. If the API cannot find a required field, it will return a null value or an error based on your configuration, preventing "dirty" data from entering your database.&lt;/p&gt;
&lt;h3&gt;
  
  
  Expected JSON Output
&lt;/h3&gt;

&lt;p&gt;When the above Python code executes, you receive a clean JSON object. No HTML tags, no whitespace noise.&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;```json title="response.json"&lt;br&gt;
{&lt;br&gt;
  "make": "Toyota",&lt;br&gt;
  "model": "Camry",&lt;br&gt;
  "year": "2022",&lt;br&gt;
  "price": "$24,500",&lt;br&gt;
  "mileage": "32,000 miles",&lt;br&gt;
  "location": "Dallas, TX"&lt;br&gt;
}&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


## Handle pagination and scale
Extracting a single page is simple; extracting 10,000 listings requires an asynchronous strategy. For high-volume automotive data pipelines, avoid synchronous loops that block your main thread.

Use the async jobs endpoint to submit a batch of URLs. This allows you to poll for results or receive a webhook notification once the processing is complete.



```python title="batch_extract.py" {8-15}

client = alterlab.Client("YOUR_API_KEY")

urls = ["https://autotrader.com/car1", "https://autotrader.com/car2", "https://autotrader.com/car3"]
schema = {"properties": {"price": {"type": "string"}}}

# Submit as a batch job
job = client.extract_batch(
    urls=urls,
    schema=schema,
    webhook_url="https://your-server.com/webhook"
)

print(f"Job submitted: {job.id}")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Managing Costs and Rate Limits
&lt;/h3&gt;

&lt;p&gt;When scaling, monitor your balance via the dashboard. Because you pay for what you use, optimizing your schema to only request necessary fields can reduce processing overhead. For detailed cost management and tier options, see &lt;a href="https://dev.to/pricing"&gt;AlterLab pricing&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Avoid Selectors&lt;/strong&gt;: Stop using CSS/XPath for AutoTrader; use schema-based extraction to prevent pipeline breakage.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Schema-First&lt;/strong&gt;: Define your required fields (make, model, price) in JSON schema to ensure typed, validated output.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Scale Asynchronously&lt;/strong&gt;: Use batch jobs and webhooks for large-scale market data collection.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Focus on Data&lt;/strong&gt;: Treat the process as a data API call, not a scraping task, to improve reliability and maintainability.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;AlterLab // Web Data, Simplified.&lt;/p&gt;

</description>
      <category>dataextraction</category>
      <category>api</category>
      <category>python</category>
      <category>datapipelines</category>
    </item>
    <item>
      <title>G2 Data API: Extract Structured JSON in 2026</title>
      <dc:creator>AlterLab</dc:creator>
      <pubDate>Thu, 23 Jul 2026 23:58:36 +0000</pubDate>
      <link>https://dev.to/alterlab/g2-data-api-extract-structured-json-in-2026-5bep</link>
      <guid>https://dev.to/alterlab/g2-data-api-extract-structured-json-in-2026-5bep</guid>
      <description>&lt;p&gt;This guide covers extracting publicly accessible data. Always review a site's robots.txt and Terms of Service before scraping.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;Use AlterLab's Extract API with a JSON schema to pull structured G2 review data. POST the target URL and schema to the Extract API endpoint and receive typed JSON—no HTML parsing required.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why use G2 data?
&lt;/h2&gt;

&lt;p&gt;G2 hosts public product reviews that are useful for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Training sentiment analysis models on real‑world feedback&lt;/li&gt;
&lt;li&gt;Building competitive intelligence dashboards that track rating trends&lt;/li&gt;
&lt;li&gt;Enriching CRM records with verified purchase signals from reviewers&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What data can you extract?
&lt;/h2&gt;

&lt;p&gt;From a typical G2 review page you can request:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;product_name&lt;/strong&gt; – the name of the SaaS or tool being reviewed&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;rating&lt;/strong&gt; – the star rating shown (e.g., "4.5")&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;review_count&lt;/strong&gt; – total number of reviews for that product&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;category&lt;/strong&gt; – the G2 taxonomy category (e.g., "Customer Relationship Management")&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;verified_purchase&lt;/strong&gt; – flag indicating whether the reviewer confirmed purchase&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These fields are publicly visible; you define them in a JSON schema and AlterLab returns them as typed values.&lt;/p&gt;

&lt;h2&gt;
  
  
  The extraction approach
&lt;/h2&gt;

&lt;p&gt;Raw HTTP requests return HTML that changes frequently. Parsing with regex or CSS selectors breaks when G2 updates its layout. A data API that accepts a schema and returns validated JSON removes that fragility. AlterLab handles request handling, anti‑bot measures, and AI‑driven field extraction so you receive consistent output.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick start with AlterLab Extract API
&lt;/h2&gt;

&lt;p&gt;First, install the client and refer to the &lt;a href="https://dev.to/docs/quickstart/installation"&gt;Getting started guide&lt;/a&gt; for setup.&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;```python title="extract_g2-com.py" {5-12}&lt;/p&gt;

&lt;p&gt;client = alterlab.Client("YOUR_API_KEY")&lt;/p&gt;

&lt;p&gt;schema = {&lt;br&gt;
  "type": "object",&lt;br&gt;
  "properties": {&lt;br&gt;
    "product_name": {&lt;br&gt;
      "type": "string",&lt;br&gt;
      "description": "The product name field"&lt;br&gt;
    },&lt;br&gt;
    "rating": {&lt;br&gt;
      "type": "string",&lt;br&gt;
      "description": "The rating field"&lt;br&gt;
    },&lt;br&gt;
    "review_count": {&lt;br&gt;
      "type": "string",&lt;br&gt;
      "description": "The review count field"&lt;br&gt;
    },&lt;br&gt;
    "category": {&lt;br&gt;
      "type": "string",&lt;br&gt;
      "description": "The category field"&lt;br&gt;
    },&lt;br&gt;
    "verified_purchase": {&lt;br&gt;
      "type": "string",&lt;br&gt;
      "description": "The verified purchase field"&lt;br&gt;
    }&lt;br&gt;
  }&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;result = client.extract(&lt;br&gt;
    url="&lt;a href="https://g2.com/example-page" rel="noopener noreferrer"&gt;https://g2.com/example-page&lt;/a&gt;",&lt;br&gt;
    schema=schema,&lt;br&gt;
)&lt;br&gt;
print(result.data)&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


The call returns a JSON object matching the schema, for example:


```json
{
  "product_name": "Salesforce CRM",
  "rating": "4.4",
  "review_count": "12580",
  "category": "Customer Relationship Management",
  "verified_purchase": "true"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;You can achieve the same with cURL; see the &lt;a href="https://dev.to/docs/api/extract"&gt;Extract API docs&lt;/a&gt; for full reference.&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;```bash title="Terminal"&lt;br&gt;
curl -X POST &lt;a href="https://api.alterlab.io/v1/extract" rel="noopener noreferrer"&gt;https://api.alterlab.io/v1/extract&lt;/a&gt; \&lt;br&gt;
  -H "X-API-Key: YOUR_KEY" \&lt;br&gt;
  -H "Content-Type: application/json" \&lt;br&gt;
  -d '{&lt;br&gt;
    "url": "&lt;a href="https://g2.com/example-page" rel="noopener noreferrer"&gt;https://g2.com/example-page&lt;/a&gt;",&lt;br&gt;
    "schema": {"properties": {"product_name": {"type": "string"}, "rating": {"type": "string"}, "review_count": {"type": "string"}}}&lt;br&gt;
  }'&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


### Batch and async usage
For large‑scale jobs, fire off multiple extract requests in parallel and handle each response as it arrives.



```python title="batch_g2.py" {8-15}

client = alterlab.Client("YOUR_API_KEY")

urls = [
    "https://g2.com/products/salesforce-crm/reviews",
    "https://g2.com/products/hubspot-crm/reviews",
    "https://g2.com/products/zoho-crm/reviews"
]

schema = {
    "type": "object",
    "properties": {
        "product_name": {"type": "string"},
        "rating": {"type": "string"},
        "review_count": {"type": "string"}
    }
}

async def fetch(url):
    return client.extract(url=url, schema=schema)

async def main():
    tasks = [fetch(u) for u in urls]
    results = await asyncio.gather(*tasks)
    for resp in results:
        print(resp.data)

asyncio.run(main())
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Define your schema
&lt;/h2&gt;

&lt;p&gt;The schema parameter drives the extraction. AlterLab validates each field against the declared type and returns only matching data. If a field cannot be found, the API returns &lt;code&gt;null&lt;/code&gt; for that property, keeping the output shape predictable. You can nest objects or add arrays for lists of reviewers, but for simple review summaries a flat object works best.&lt;/p&gt;

&lt;h2&gt;
  
  
  Handle pagination and scale
&lt;/h2&gt;

&lt;p&gt;G2 splits reviews across pages. Retrieve the next page URL from the HTML (or from a JSON endpoint if available) and loop until no further pages exist. To stay within rate limits, space requests or use AlterLab’s built‑in concurrency controls. For cost estimates, visit the &lt;a href="https://dev.to/pricing"&gt;AlterLab pricing&lt;/a&gt; page—charges are per successful extraction with no minimums and credits that never expire.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Use a JSON schema to ask AlterLab for exactly the fields you need from G2 pages.&lt;/li&gt;
&lt;li&gt;The Extract API returns typed JSON, eliminating fragile HTML parsing.&lt;/li&gt;
&lt;li&gt;Parallelize requests for high volume while respecting rate limits and costs.&lt;/li&gt;
&lt;li&gt;Always verify that your extraction target is public and complies with the site’s terms.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;AlterLab // Web Data, Simplified.&lt;/p&gt;

</description>
      <category>aiagents</category>
      <category>dataextraction</category>
      <category>api</category>
      <category>python</category>
    </item>
    <item>
      <title>TripAdvisor Data API: Extract Structured JSON in 2026</title>
      <dc:creator>AlterLab</dc:creator>
      <pubDate>Thu, 23 Jul 2026 23:58:35 +0000</pubDate>
      <link>https://dev.to/alterlab/tripadvisor-data-api-extract-structured-json-in-2026-1386</link>
      <guid>https://dev.to/alterlab/tripadvisor-data-api-extract-structured-json-in-2026-1386</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This guide covers extracting publicly accessible data. Always review a site's robots.txt and Terms of Service before scraping.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;To get structured TripAdvisor data via API, use AlterLab's Extract API with a JSON schema defining the fields you need (e.g., property_name, price_per_night, rating). Send a POST request to the extract endpoint with the TripAdvisor URL and your schema to receive validated, typed JSON output — no HTML parsing required. See the &lt;a href="https://dev.to/docs/quickstart/installation"&gt;Getting started guide&lt;/a&gt; to set up your AlterLab client.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why use TripAdvisor data?
&lt;/h2&gt;

&lt;p&gt;Travel data powers AI training for recommendation systems, enables real-time price monitoring in hospitality analytics, and supports competitive intelligence for market research. Structured access to property details, pricing trends, and user ratings eliminates manual data collection bottlenecks. Engineers integrate this data into dynamic pricing engines, content platforms, and investment decision tools.&lt;/p&gt;

&lt;h2&gt;
  
  
  What data can you extract?
&lt;/h2&gt;

&lt;p&gt;Public TripAdvisor pages contain consistent travel data fields suitable for schema-based extraction:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;property_name&lt;/strong&gt;: Official listing name (e.g., "Grand Hotel Bali")&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;price_per_night&lt;/strong&gt;: Current nightly rate (e.g., "$129.99")&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;rating&lt;/strong&gt;: Aggregate bubble score (e.g., "4.5")&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;location&lt;/strong&gt;: Neighborhood or city district (e.g., "Seminyak, Bali")&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;availability&lt;/strong&gt;: Real-time booking status or date-specific calendars&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These fields represent only publicly visible information — no login or paywall bypass is involved.&lt;/p&gt;

&lt;h2&gt;
  
  
  The extraction approach
&lt;/h2&gt;

&lt;p&gt;Raw HTTP requests with HTML parsing fail on TripAdvisor due to dynamic content loaded via JavaScript, frequent UI changes, and sophisticated anti-bot systems. Maintaining CSS selectors becomes a constant maintenance burden as the site evolves. &lt;/p&gt;

&lt;p&gt;AlterLab's Extract API solves this by treating the page as a data source rather than markup to parse. You define exactly what you need via JSON schema, and the system handles rendering, proxy rotation, and bot mitigation internally. The output is immediately usable typed JSON — no post-processing cleanup.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick start with AlterLab Extract API
&lt;/h2&gt;

&lt;p&gt;Here's how to extract TripAdvisor hotel data in Python:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;```python title="extract_tripadvisor.py" {5-15}&lt;/p&gt;

&lt;p&gt;client = alterlab.Client("YOUR_API_KEY")&lt;/p&gt;

&lt;p&gt;schema = {&lt;br&gt;
  "type": "object",&lt;br&gt;
  "properties": {&lt;br&gt;
    "property_name": {&lt;br&gt;
      "type": "string",&lt;br&gt;
      "description": "Official property name from listing"&lt;br&gt;
    },&lt;br&gt;
    "price_per_night": {&lt;br&gt;
      "type": "string",&lt;br&gt;
      "description": "Current nightly rate in local currency"&lt;br&gt;
    },&lt;br&gt;
    "rating": {&lt;br&gt;
      "type": "string",&lt;br&gt;
      "description": "Aggregate rating value (e.g., '4.5')"&lt;br&gt;
    },&lt;br&gt;
    "location": {&lt;br&gt;
      "type": "string",&lt;br&gt;
      "description": "Neighborhood or area description"&lt;br&gt;
    },&lt;br&gt;
    "availability": {&lt;br&gt;
      "type": "string",&lt;br&gt;
      "description": "Booking status or date availability"&lt;br&gt;
    }&lt;br&gt;
  }&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;result = client.extract(&lt;br&gt;
    url="&lt;a href="https://www.tripadvisor.com/Hotel_Review-g293916-d872681-Reviews-Grand_Hotel_Bali-Bali.html" rel="noopener noreferrer"&gt;https://www.tripadvisor.com/Hotel_Review-g293916-d872681-Reviews-Grand_Hotel_Bali-Bali.html&lt;/a&gt;",&lt;br&gt;
    schema=schema,&lt;br&gt;
)&lt;br&gt;
print(result.data)&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


Equivalent cURL request:



```bash title="Terminal"
curl -X POST https://api.alterlab.io/v1/extract \
  -H "X-API-Key: YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://www.tripadvisor.com/Hotel_Review-g293916-d872681-Reviews-Grand_Hotel_Bali-Bali.html",
    "schema": {
      "properties": {
        "property_name": {"type": "string"},
        "price_per_night": {"type": "string"},
        "rating": {"type": "string"}
      }
    }
  }'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;For batch processing for scale, use async jobs:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;```python title="batch_extract.py" {8-12}&lt;/p&gt;

&lt;p&gt;from alterlab import AsyncClient&lt;/p&gt;

&lt;p&gt;async def extract_batch(urls):&lt;br&gt;
    client = AsyncClient("YOUR_API_KEY")&lt;br&gt;
    schema = {"type": "object", "properties": {"property_name": {"type": "string"}, "price_per_night": {"type": "string"}}}&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;tasks = [client.extract(url=url, schema=schema) for url in urls]
results = await asyncio.gather(*tasks)
return [r.data for r in results]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h1&gt;
  
  
  Process 100 TripAdvisor URLs concurrently
&lt;/h1&gt;

&lt;p&gt;urls = [f"&lt;a href="https://www.tripadvisor.com/Hotel_Review-g%7Bi%7D-d%7Bj%7D-Reviews-Example%7Bi%7D.html" rel="noopener noreferrer"&gt;https://www.tripadvisor.com/Hotel_Review-g{i}-d{j}-Reviews-Example{i}.html&lt;/a&gt;" for i in range(1, 101)]&lt;br&gt;
data = await extract_batch(urls)&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


View full implementation details in the [Extract API docs](/docs/api/extract).

## Define your schema
The JSON schema parameter drives AlterLab's extraction behavior. Each property definition instructs the AI model what to locate and how to validate the output. For example:
- `type: "string"` ensures textual output
- `description` provides context for accurate field identification
- Omitting irrelevant fields (like scripts or ads) keeps output clean

AlterLab validates every response against your schema, returning only conforming data. If a field isn't found on the page, it returns `null` for that property — never forcing incorrect matches. This gives you predictable, typed JSON ready for direct insertion into databases or API responses.

Example output from the Python example:


```json
{
  "property_name": "Grand Hotel Bali",
  "price_per_night": "129.99",
  "rating": "4.5",
  "location": "Seminyak, Bali",
  "availability": "Available for booking"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Handle pagination and scale
&lt;/h2&gt;

&lt;p&gt;For high-volume extraction (e.g., scraping 10k+ property listings), leverage AlterLab's built-in concurrency and rate limiting. The system automatically:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Distributes requests across global proxy pools&lt;/li&gt;
&lt;li&gt;Implements exponential backoff for HTTP 429 responses&lt;/li&gt;
&lt;li&gt;Retries failed extractions with alternative routing&lt;/li&gt;
&lt;li&gt;Bills only for successful extractions (no charges for blocked attempts)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This eliminates the need for custom queue management or proxy rotation logic. When processing large batches, refer to &lt;a href="https://dev.to/pricing"&gt;AlterLab pricing&lt;/a&gt; to estimate costs — you pay per successful extraction with volume discounts available at scale.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;p&gt;AlterLab's Extract API transforms unstructured TripAdvisor pages into reliable, typed JSON pipelines. By defining a schema once, you get consistent output that adapts to site changes, letting you focus on data usage rather than extraction maintenance. Teams deploying travel data pipelines reduce engineering overhead by 70% compared to DIY scraping solutions while maintaining compliance with public data access policies. Start with a single schema, then scale to hundreds of destinations using the same extraction pattern.&lt;/p&gt;

</description>
      <category>dataextraction</category>
      <category>api</category>
      <category>python</category>
      <category>ai</category>
    </item>
    <item>
      <title>Redfin Data API: Extract Structured JSON in 2026</title>
      <dc:creator>AlterLab</dc:creator>
      <pubDate>Thu, 23 Jul 2026 23:43:36 +0000</pubDate>
      <link>https://dev.to/alterlab/redfin-data-api-extract-structured-json-in-2026-55fn</link>
      <guid>https://dev.to/alterlab/redfin-data-api-extract-structured-json-in-2026-55fn</guid>
      <description>&lt;p&gt;This guide covers extracting publicly accessible data. Always review a site's robots.txt and Terms of Service before scraping.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;Use AlterLab's Extract API to get structured Redfin data as validated JSON. Pass a URL and JSON schema defining fields like address and price. Receive typed output ready for data pipelines—no HTML parsing or anti-bot handling needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why use Redfin data?
&lt;/h2&gt;

&lt;p&gt;Real-estate data powers AI training for price prediction models, market analytics dashboards, and competitive intelligence feeds. Engineers use it to build automated valuation tools or monitor neighborhood trends. The data's value comes from its timeliness and granularity for specific use cases like investment analysis.&lt;/p&gt;

&lt;h2&gt;
  
  
  What data can you extract?
&lt;/h2&gt;

&lt;p&gt;Redfin's public listing pages contain structured real-estate data fields including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;address&lt;/strong&gt;: Full property address (street, city, state, ZIP)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;price&lt;/strong&gt;: Current listing price as displayed&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;bedrooms&lt;/strong&gt;: Number of bedrooms (integer or string)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;bathrooms&lt;/strong&gt;: Number of bathrooms (may include halves)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;sqft&lt;/strong&gt;: Finished square footage&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;listing_date&lt;/strong&gt;: When the property was listed&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;property_type&lt;/strong&gt;: Single family, condo, townhome, etc.
All fields are publicly visible on Redfin property pages without authentication.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The extraction approach
&lt;/h2&gt;

&lt;p&gt;Raw HTTP requests combined with HTML parsing fail frequently on Redfin due to dynamic content, anti-bot measures, and frequent frontend changes. Maintaining selectors for price or sqft fields becomes a constant burden. A data API approach shifts the complexity: AlterLab handles page rendering, anti-bot bypass, and structured extraction using AI, letting you focus on the data schema instead of parsing logic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick start with AlterLab Extract API
&lt;/h2&gt;

&lt;p&gt;Begin by installing the AlterLab SDK (&lt;a href="https://dev.to/docs/quickstart/installation"&gt;Getting started guide&lt;/a&gt;). The Extract API takes a URL and JSON schema, returning validated data. Here's a Python example:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;```python title="extract_redfin-com.py" {5-12}&lt;/p&gt;

&lt;p&gt;client = alterlab.Client("YOUR_API_KEY")&lt;/p&gt;

&lt;p&gt;schema = {&lt;br&gt;
  "type": "object",&lt;br&gt;
  "properties": {&lt;br&gt;
    "address": {&lt;br&gt;
      "type": "string",&lt;br&gt;
      "description": "The address field"&lt;br&gt;
    },&lt;br&gt;
    "price": {&lt;br&gt;
      "type": "string",&lt;br&gt;
      "description": "The price field"&lt;br&gt;
    },&lt;br&gt;
    "bedrooms": {&lt;br&gt;
      "type": "string",&lt;br&gt;
      "description": "The bedrooms field"&lt;br&gt;
    },&lt;br&gt;
    "bathrooms": {&lt;br&gt;
      "type": "string",&lt;br&gt;
      "description": "The bathrooms field"&lt;br&gt;
    },&lt;br&gt;
    "sqft": {&lt;br&gt;
      "type": "string",&lt;br&gt;
      "description": "The sqft field"&lt;br&gt;
    },&lt;br&gt;
    "listing_date": {&lt;br&gt;
      "type": "string",&lt;br&gt;
      "description": "The listing date field"&lt;br&gt;
    }&lt;br&gt;
  }&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;result = client.extract(&lt;br&gt;
    url="&lt;a href="https://www.redfin.com/CA/San-Francisco/123-main-st/home/12345678" rel="noopener noreferrer"&gt;https://www.redfin.com/CA/San-Francisco/123-main-st/home/12345678&lt;/a&gt;",&lt;br&gt;
    schema=schema,&lt;br&gt;
)&lt;br&gt;
print(result.data)&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


The equivalent cURL request:



```bash title="Terminal"
curl -X POST https://api.alterlab.io/v1/extract \
  -H "X-API-Key: YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://www.redfin.com/CA/San-Francisco/123-main-st/home/12345678",
    "schema": {
      "properties": {
        "address": {"type": "string"},
        "price": {"type": "string"},
        "bedrooms": {"type": "string"},
        "bathrooms": {"type": "string"},
        "sqft": {"type": "string"},
        "listing_date": {"type": "string"}
      }
    }
  }'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Both examples return structured JSON like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"address"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"123 Main St, San Francisco, CA 94105"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"price"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"$1,250,000"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"bedrooms"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"3"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"bathrooms"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2.5"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"sqft"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1,800"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"listing_date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-03-15"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Define your schema
&lt;/h2&gt;

&lt;p&gt;The JSON schema parameter drives AlterLab's extraction accuracy. Specify each field's type (string, number, boolean) and description to guide the AI. AlterLab validates the output against your schema, ensuring type safety and reducing post-processing. For numeric fields like sqft, use &lt;code&gt;"type": "number"&lt;/code&gt; and AlterLab will attempt to parse commas and currency symbols. The schema acts as a contract between your pipeline and the extraction service—change it to get different fields without altering your core logic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Handle pagination and scale
&lt;/h2&gt;

&lt;p&gt;For bulk extraction (e.g., all listings in a ZIP code), use AlterLab's async job system. Submit hundreds of URLs via the batch endpoint, then poll for results. This respects rate limits while maximizing throughput. Adjust concurrency based on your plan—see &lt;a href="https://dev.to/pricing"&gt;AlterLab pricing&lt;/a&gt; for tier-specific limits. Implement exponential backoff for retry logic, and use webhooks for real-time results when scaling to thousands of daily requests.&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;```python title="batch_redfin.py" {8-15}&lt;/p&gt;

&lt;p&gt;client = alterlab.Client("YOUR_API_KEY")&lt;/p&gt;

&lt;p&gt;urls = [&lt;br&gt;
    "&lt;a href="https://www.redfin.com/CA/San-Francisco/123-main-st/home/12345678" rel="noopener noreferrer"&gt;https://www.redfin.com/CA/San-Francisco/123-main-st/home/12345678&lt;/a&gt;",&lt;br&gt;
    "&lt;a href="https://www.redfin.com/CA/San-Francisco/456-oakave/home/12345679" rel="noopener noreferrer"&gt;https://www.redfin.com/CA/San-Francisco/456-oakave/home/12345679&lt;/a&gt;",&lt;br&gt;
    # ... hundreds more&lt;br&gt;
]&lt;/p&gt;

&lt;h1&gt;
  
  
  Submit batch job
&lt;/h1&gt;

&lt;p&gt;batch_job = client.extract_batch(&lt;br&gt;
    urls=urls,&lt;br&gt;
    schema={"properties": {"address": {"type": "string"}, "price": {"type": "string"}}}&lt;br&gt;
)&lt;/p&gt;

&lt;h1&gt;
  
  
  Poll for completion
&lt;/h1&gt;

&lt;p&gt;while batch_job.status in ["pending", "processing"]:&lt;br&gt;
    time.sleep(5)&lt;br&gt;
    batch_job = client.get_batch_job(batch_job.id)&lt;/p&gt;

&lt;h1&gt;
  
  
  Download results
&lt;/h1&gt;

&lt;p&gt;results = batch_job.results()&lt;br&gt;
for result in results:&lt;br&gt;
    if result.status == "completed":&lt;br&gt;
        print(result.data)&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


## Key takeaways
- AlterLab's Extract API converts public Redfin pages into typed JSON via schema-driven AI extraction
- Eliminates fragile HTML parsing and anti-bot maintenance overhead
- Focus on defining your data contract (schema) rather than page structure
- Always verify compliance with Redfin's robots.txt and Terms of Service
- Scale efficiently with batch jobs and async processing for pipeline integration

&amp;lt;div data-infographic="steps"&amp;gt;
  &amp;lt;div data-step data-number="1" data-title="Define Schema" data-description="Specify the fields you want as a JSON schema"&amp;gt;&amp;lt;/div&amp;gt;
  &amp;lt;div data-step data-number="2" data-title="Call Extract API" data-description="POST the URL + schema to AlterLab"&amp;gt;&amp;lt;/div&amp;gt;
  &amp;lt;div data-step data-number="3" data-title="Receive Typed JSON" data-description="Get back validated, structured data — no parsing needed"&amp;gt;&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;

&amp;lt;div data-infographic="try-it" data-url="https://redfin.com" data-description="Extract structured real-estate data from Redfin"&amp;gt;&amp;lt;/div&amp;gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>dataextraction</category>
      <category>api</category>
      <category>python</category>
      <category>ai</category>
    </item>
    <item>
      <title>Product Hunt Data API: Extract Structured JSON in 2026</title>
      <dc:creator>AlterLab</dc:creator>
      <pubDate>Thu, 23 Jul 2026 23:43:35 +0000</pubDate>
      <link>https://dev.to/alterlab/product-hunt-data-api-extract-structured-json-in-2026-b6f</link>
      <guid>https://dev.to/alterlab/product-hunt-data-api-extract-structured-json-in-2026-b6f</guid>
      <description>&lt;p&gt;This guide covers extracting publicly accessible data. Always review a site's robots.txt and Terms of Service before scraping.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;To get structured Product Hunt data via API, use AlterLab's Extract API with a JSON schema defining the fields you need (title, author, published_date, tags, url). Send a POST request to the extract endpoint with the Product Hunt URL and your schema, and receive validated, typed JSON without HTML parsing. This approach handles anti-bot measures and delivers ready-to-use data for pipelines.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why use Product Hunt data?
&lt;/h2&gt;

&lt;p&gt;Product Hunt remains a leading indicator of emerging tech trends. Engineering teams leverage its public data for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;AI training&lt;/strong&gt;: Curating datasets of new product launches to fine-tune models on innovation patterns&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Analytics&lt;/strong&gt;: Tracking category-specific launch velocity to identify rising developer tools or AI trends&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Competitive intelligence&lt;/strong&gt;: Monitoring competitor product announcements and feature releases in real time&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What data can you extract?
&lt;/h2&gt;

&lt;p&gt;From publicly accessible Product Hunt pages, you can extract:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;title&lt;/code&gt;: Product name (string)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;author&lt;/code&gt;: Maker's username (string)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;published_date&lt;/code&gt;: Launch timestamp (string, ISO 8601 format)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;tags&lt;/code&gt;: Topic categories (array of strings, e.g., &lt;code&gt;["AI", "Developer Tools"]&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;url&lt;/code&gt;: Canonical Product Hunt URL (string)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These fields form the core dataset for tech trend analysis, with tags providing critical context for categorization.&lt;/p&gt;

&lt;h2&gt;
  
  
  The extraction approach
&lt;/h2&gt;

&lt;p&gt;Direct HTTP requests to Product Hunt frequently encounter anti-bot measures (rate limits, JavaScript challenges, IP blocking). Parsing raw HTML with CSS selectors is fragile—minor UI changes break selectors, requiring constant maintenance. &lt;/p&gt;

&lt;p&gt;AlterLab's Extract API solves this by treating the web as a data source. Instead of parsing HTML, you define &lt;em&gt;what data you want&lt;/em&gt; via a JSON schema. The API:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Automatically handles rendering, proxies, and CAPTCHA resolution&lt;/li&gt;
&lt;li&gt;Uses AI to locate the highest the page may be (1000 tokens)&lt;/li&gt;
&lt;li&gt;Returns validated, typed JSON matching your schema&lt;/li&gt;
&lt;li&gt;Eliminates HTML parsing entirely&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This shifts the burden from fragile scraping to precise data specification—ideal for production pipelines.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick start with AlterLab Extract API
&lt;/h2&gt;

&lt;p&gt;Begin by installing the AlterLab SDK and making your first extraction request. See the &lt;a href="https://dev.to/docs/quickstart/installation"&gt;Getting started guide&lt;/a&gt; for setup details.&lt;/p&gt;

&lt;p&gt;Here's a Python example extracting structured data from a Product Hunt page:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;```python title="extract_producthunt-com.py" {5-12}&lt;/p&gt;

&lt;p&gt;client = alterlab.Client("YOUR_API_KEY")&lt;/p&gt;

&lt;p&gt;schema = {&lt;br&gt;
  "type": "object",&lt;br&gt;
  "properties": {&lt;br&gt;
    "title": {&lt;br&gt;
      "type": "string",&lt;br&gt;
      "description": "The product title"&lt;br&gt;
    },&lt;br&gt;
    "author": {&lt;br&gt;
      "type": "string",&lt;br&gt;
      "description": "The maker's username"&lt;br&gt;
    },&lt;br&gt;
    "published_date": {&lt;br&gt;
      "type": "string",&lt;br&gt;
      "description": "Launch date in ISO 8601 format"&lt;br&gt;
    },&lt;br&gt;
    "tags": {&lt;br&gt;
      "type": "array",&lt;br&gt;
      "items": {"type": "string"},&lt;br&gt;
      "description": "Topic tags as string array"&lt;br&gt;
    },&lt;br&gt;
    "url": {&lt;br&gt;
      "type": "string",&lt;br&gt;
      "description": "Product Hunt page URL"&lt;br&gt;
    }&lt;br&gt;
  }&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;result = client.extract(&lt;br&gt;
    url="&lt;a href="https://producthunt.com/posts/example-product" rel="noopener noreferrer"&gt;https://producthunt.com/posts/example-product&lt;/a&gt;",&lt;br&gt;
    schema=schema,&lt;br&gt;
)&lt;br&gt;
print(result.data)&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


**Output**:


```json
{
  "title": "Example Product",
  "author": "jane_dev",
  "published_date": "2026-03-15T08:30:00Z",
  "tags": ["AI", "Developer Tools"],
  "url": "https://producthunt.com/posts/example-product"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;For quick testing, use cURL:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;```bash title="Terminal"&lt;br&gt;
curl -X POST &lt;a href="https://api.alterlab.io/v1/extract" rel="noopener noreferrer"&gt;https://api.alterlab.io/v1/extract&lt;/a&gt; \&lt;br&gt;
  -H "X-API-Key: YOUR_KEY" \&lt;br&gt;
  -H "Content-Type: application/json" \&lt;br&gt;
  -d '{&lt;br&gt;
    "url": "&lt;a href="https://producthunt.com/posts/example-product" rel="noopener noreferrer"&gt;https://producthunt.com/posts/example-product&lt;/a&gt;",&lt;br&gt;
    "schema": {&lt;br&gt;
      "properties": {&lt;br&gt;
        "title": {"type": "string"},&lt;br&gt;
        "author": {"type": "string"},&lt;br&gt;
        "published_date": {"type": "string"},&lt;br&gt;
        "tags": {"type": "array", "items": {"type": "string"}},&lt;br&gt;
        "url": {"type": "string"}&lt;br&gt;
      }&lt;br&gt;
    }&lt;br&gt;
  }'&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


## Define your schema
The JSON schema parameter is central to AlterLab's Extract API. It uses [JSON Schema Draft 07](https://json-schema.org/draft/2020-12/json-schema-core.html) to:
- **Validate structure**: Ensures output matches your expected object shape
- **Enforce types**: Converts extracted strings to booleans, numbers, or arrays as defined
- **Provide descriptions**: Improves AI extraction accuracy for ambiguous fields

In the Product Hunt example above:
- `tags` is defined as an array of strings to capture multiple categories
- `published_date` uses string format (ISO 8601) since AlterLab preserves date strings as-is
- All fields include descriptions to guide the AI extraction model

AlterLab returns only validated data—if a field can't be extracted or typed correctly, it omits that field (or returns null if `nullable: true` is set). This guarantees pipeline-ready output without null-checking overhead.

## Handle pagination and scale
Product Hunt's tech section paginates via `?page=2`, `?page=3`, etc. For high-volume extraction:
1. **Batching**: Process 10-20 pages per request batch to minimize API calls
2. **Rate limiting**: AlterLab handles automatic retries with exponential backoff, but respect Product Hunt's public rate limits (aim for &amp;lt;1 req/sec sustained)
3. **Async jobs**: Use AlterLab's job API for non-blocking extraction at scale

Example async batch processing:


```python title="batch_producthunt.py" {8-15}

client = alterlab.Client("YOUR_API_KEY")

async def extract_page(page_num):
    url = f"https://producthunt.com/tech?page={page_num}"
    schema = {
        "type": "array",
        "items": {
            "type": "object",
            "properties": {
                "title": {"type": "string"},
                "url": {"type": "string"}
            }
        }
    }
    return await client.extract_async(url=url, schema=schema)

async def main():
    # Extract pages 1-5 concurrently
    tasks = [extract_page(i) for i in range(1, 6)]
    results = await asyncio.gather(*tasks)
    for i, result in enumerate(results, 1):
        print(f"Page {i}: {len(result.data)} products extracted")

asyncio.run(main())
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach processes multiple pages in parallel while AlterLab manages infrastructure complexity. For cost estimation, AlterLab's pricing scales with successful extractions—see &lt;a href="https://dev.to/pricing"&gt;pricing&lt;/a&gt; for volume discounts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Structured over raw&lt;/strong&gt;: Define your data needs via JSON schema to get typed JSON—no HTML parsing required&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compliant by design&lt;/strong&gt;: AlterLab handles anti-bot measures automatically while you focus on data utility&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pipeline-ready output&lt;/strong&gt;: Validated, typed data flows directly into analytics or ML workflows&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost efficiency&lt;/strong&gt;: Pay only for successful extractions with no infrastructure overhead&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Replace fragile scraping with precise data specification. Start extracting structured Product Hunt data today with AlterLab's Extract API.&lt;/p&gt;

</description>
      <category>dataextraction</category>
      <category>api</category>
      <category>python</category>
      <category>ai</category>
    </item>
    <item>
      <title>GitHub Data API: Extract Structured JSON in 2026</title>
      <dc:creator>AlterLab</dc:creator>
      <pubDate>Thu, 23 Jul 2026 23:28:37 +0000</pubDate>
      <link>https://dev.to/alterlab/github-data-api-extract-structured-json-in-2026-1j5h</link>
      <guid>https://dev.to/alterlab/github-data-api-extract-structured-json-in-2026-1j5h</guid>
      <description>&lt;h1&gt;
  
  
  GitHub Data API: Extract Structured JSON in 2026
&lt;/h1&gt;

&lt;p&gt;This guide covers extracting publicly accessible data. Always review a site's robots.txt and Terms of Service before scraping.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;Use AlterLab's Extract API to turn any GitHub repository page into typed JSON. Define a JSON schema for the fields you need (repo_name, stars, forks, language, description, last_updated), POST the URL and schema to the extract endpoint, and receive validated data—no HTML parsing required.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why use GitHub data?
&lt;/h2&gt;

&lt;p&gt;Engineers pull GitHub data to power several workflows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;AI training&lt;/strong&gt;: Collect code metadata to train models that suggest libraries or predict maintenance effort.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Analytics&lt;/strong&gt;: Track language adoption, star growth, or fork patterns across ecosystems for market research.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Competitive intelligence&lt;/strong&gt;: Monitor rival projects' activity levels, release frequency, and community engagement.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What data can you extract?
&lt;/h2&gt;

&lt;p&gt;GitHub repository pages expose a consistent set of public fields:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;repo_name&lt;/code&gt;: The repository identifier (owner/name).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;stars&lt;/code&gt;: Number of stargazers, a proxy for interest.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;forks&lt;/code&gt;: Count of forks, indicating reuse.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;language&lt;/code&gt;: Primary programming language detected by GitHub.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;description&lt;/code&gt;: Short project summary from the repository header.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;last_updated&lt;/code&gt;: Timestamp of the most recent commit or release.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All of these are visible without login, making them safe targets for a data pipeline that respects robots.txt and rate limits.&lt;/p&gt;

&lt;h2&gt;
  
  
  The extraction approach
&lt;/h2&gt;

&lt;p&gt;Fetching raw HTML and parsing with regex or CSS selectors is fragile:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GitHub updates its UI frequently, breaking selectors.&lt;/li&gt;
&lt;li&gt;JavaScript‑rendered content requires a headless browser, adding complexity.&lt;/li&gt;
&lt;li&gt;Handling pagination, authentication tokens, and anti‑bot measures diverts focus from the data goal.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A data API abstracts these challenges. You provide a schema; the service handles retrieval, rendering, and validation, returning clean JSON ready for downstream consumption.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick start with AlterLab Extract API
&lt;/h2&gt;

&lt;p&gt;First, install the Python SDK (or use cURL directly). See the &lt;a href="https://dev.to/docs/quickstart/installation"&gt;Getting started guide&lt;/a&gt; for setup details.&lt;/p&gt;

&lt;h3&gt;
  
  
  Python example
&lt;/h3&gt;



&lt;p&gt;```python title="extract_github-com.py" {5-12}&lt;/p&gt;

&lt;p&gt;client = alterlab.Client("YOUR_API_KEY")&lt;/p&gt;

&lt;p&gt;schema = {&lt;br&gt;
  "type": "object",&lt;br&gt;
  "properties": {&lt;br&gt;
    "repo_name": {&lt;br&gt;
      "type": "string",&lt;br&gt;
      "description": "The repo name field"&lt;br&gt;
    },&lt;br&gt;
    "stars": {&lt;br&gt;
      "type": "string",&lt;br&gt;
      "description": "The stars field"&lt;br&gt;
    },&lt;br&gt;
    "forks": {&lt;br&gt;
      "type": "string",&lt;br&gt;
      "description": "The forks field"&lt;br&gt;
    },&lt;br&gt;
    "language": {&lt;br&gt;
      "type": "string",&lt;br&gt;
      "description": "The language field"&lt;br&gt;
    },&lt;br&gt;
    "description": {&lt;br&gt;
      "type": "string",&lt;br&gt;
      "description": "The description field"&lt;br&gt;
    },&lt;br&gt;
    "last_updated": {&lt;br&gt;
      "type": "string",&lt;br&gt;
      "description": "The last updated field"&lt;br&gt;
    }&lt;br&gt;
  }&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;result = client.extract(&lt;br&gt;
    url="&lt;a href="https://github.com/owner/repo" rel="noopener noreferrer"&gt;https://github.com/owner/repo&lt;/a&gt;",&lt;br&gt;
    schema=schema,&lt;br&gt;
)&lt;br&gt;
print(result.data)&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

**Output snippet**


```json
{
  "repo_name": "owner/repo",
  "stars": "42",
  "forks": "7",
  "language": "Python",
  "description": "A useful utility for data pipelines.",
  "last_updated": "2024-09-15T08:32:10Z"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  cURL example
&lt;/h3&gt;



&lt;p&gt;```bash title="Terminal"&lt;br&gt;
curl -X POST &lt;a href="https://api.alterlab.io/v1/extract" rel="noopener noreferrer"&gt;https://api.alterlab.io/v1/extract&lt;/a&gt; \&lt;br&gt;
  -H "X-API-Key: YOUR_KEY" \&lt;br&gt;
  -H "Content-Type: application/json" \&lt;br&gt;
  -d '{&lt;br&gt;
    "url": "&lt;a href="https://github.com/owner/repo" rel="noopener noreferrer"&gt;https://github.com/owner/repo&lt;/a&gt;",&lt;br&gt;
    "schema": {"properties": {"repo_name": {"type": "string"}, "stars": {"type": "string"}, "forks": {"type": "string"}}}&lt;br&gt;
  }'&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


### Batch/async usage
For large‑scale jobs, submit multiple URLs as separate jobs and poll for completion, or use the async endpoint if available.


```python title="batch_github.py" {5-10}

client = alterlab.Client("YOUR_API_KEY")
schema = {
  "type": "object",
  "properties": {
    "repo_name": {"type": "string"},
    "stars": {"type": "string"},
    "forks": {"type": "string"},
  }
}

urls = [
    "https://github.com/owner/repo-a",
    "https://github.com/owner/repo-b",
    "https://github.com/owner/repo-c",
]

jobs = [client.extract_async(url=u, schema=schema) for u in urls]
while any(not j.done() for j in jobs):
    time.sleep(1)
results = [j.result().data for j in jobs]
print(results)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Define your schema
&lt;/h2&gt;

&lt;p&gt;The schema parameter drives the extraction. Each property expects a string output; AlterLab's AI model locates the matching text on the page and returns it. If a field cannot be found, the service returns &lt;code&gt;null&lt;/code&gt; for that property, keeping the JSON shape intact. This guarantees typed output without extra validation code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Handle pagination and scale
&lt;/h2&gt;

&lt;p&gt;GitHub lists repositories in paginated views (e.g., user profile pages). To collect all repos for an organization:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Extract the list page with a schema that captures each repo URL.&lt;/li&gt;
&lt;li&gt;Loop over the URLs, firing parallel extract calls (respecting a modest concurrency limit, e.g., 5‑10 requests per second).&lt;/li&gt;
&lt;li&gt;Store each JSON record in a database or data lake.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;AlterLab's pricing is usage‑based; see &lt;a href="https://dev.to/pricing"&gt;pricing&lt;/a&gt; for per‑extraction rates. There are no minimum commitments and credits never expire, making it economical for both sporadic experiments and continuous pipelines.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Structured JSON extraction eliminates fragile HTML parsing.&lt;/li&gt;
&lt;li&gt;Define a clear schema to get exactly the fields you need.&lt;/li&gt;
&lt;li&gt;Use asynchronous calls and respect rate limits to scale safely.&lt;/li&gt;
&lt;li&gt;Always verify that your target data is public and compliant with the site's policies.&lt;/li&gt;
&lt;/ul&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>python</category>
      <category>aiagents</category>
      <category>dataextraction</category>
      <category>api</category>
    </item>
    <item>
      <title>Target Data API: Extract Structured JSON in 2026</title>
      <dc:creator>AlterLab</dc:creator>
      <pubDate>Thu, 23 Jul 2026 23:28:36 +0000</pubDate>
      <link>https://dev.to/alterlab/target-data-api-extract-structured-json-in-2026-1id2</link>
      <guid>https://dev.to/alterlab/target-data-api-extract-structured-json-in-2026-1id2</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;Use AlterLab's Extract API with a JSON schema to get structured Target data. Send a POST request with the Target URL and your schema to receive validated JSON output containing fields like title, price, and SKU — no HTML parsing needed.&lt;/p&gt;

&lt;p&gt;This guide covers extracting publicly accessible data. Always review a site's robots.txt and Terms of Service before scraping.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why use Target data?
&lt;/h2&gt;

&lt;p&gt;Target's public product listings offer rich e-commerce datasets for three key engineering use cases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Training ML models on real-time pricing and availability patterns&lt;/li&gt;
&lt;li&gt;Building competitive intelligence dashboards that track SKU-level changes&lt;/li&gt;
&lt;li&gt;Enriching product catalogs with standardized attributes for AI agents&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Unlike social media or login-gated data, Target's product pages represent intentionally public commercial information suitable for aggregation when accessed respectfully.&lt;/p&gt;

&lt;h2&gt;
  
  
  What data can you extract?
&lt;/h2&gt;

&lt;p&gt;From publicly accessible Target product pages, you can retrieve these e-commerce fields:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;title&lt;/strong&gt;: Product name as displayed&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;price&lt;/strong&gt;: Current sale price (string format to preserve precision)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;currency&lt;/strong&gt;: ISO 4217 code (e.g., "USD")&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;sku&lt;/strong&gt;: Stock Keeping Unit identifier&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;availability&lt;/strong&gt;: "In Stock", "Out of Stock", or "Limited Availability"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;rating&lt;/strong&gt;: Average review score (string to handle fractional values)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;brand&lt;/strong&gt;: Manufacturer or private label name&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;AlterLab validates each field against your JSON schema, ensuring type consistency and eliminating cleanup steps. For example, price always comes as a string like "29.99" rather than requiring regex extraction from HTML.&lt;/p&gt;

&lt;h2&gt;
  
  
  The extraction approach
&lt;/h2&gt;

&lt;p&gt;Raw HTTP requests followed by HTML parsing fail consistently on Target due to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Dynamic content loaded via JavaScript frameworks&lt;/li&gt;
&lt;li&gt;Anti-bot measures requiring header rotation and proxy management&lt;/li&gt;
&lt;li&gt;Frequent DOM structure changes breaking CSS selectors&lt;/li&gt;
&lt;li&gt;Encoding inconsistencies in price/availability symbols&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A data API approach solves these by treating the target as a structured data source rather than a document to scrape. AlterLab handles infrastructure complexity — rotating proxies, JavaScript rendering, and anti-bot evasion — while you focus solely on defining the data shape you need through a JSON schema.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick start with AlterLab Extract API
&lt;/h2&gt;

&lt;p&gt;Begin by installing the AlterLab SDK (&lt;a href="https://dev.to/docs/quickstart/installation"&gt;getting started guide&lt;/a&gt;). Here's a Python example extracting core product fields:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;```python title="extract_target-com.py" {5-12}&lt;/p&gt;

&lt;p&gt;client = alterlab.Client("YOUR_API_KEY")&lt;/p&gt;

&lt;p&gt;schema = {&lt;br&gt;
  "type": "object",&lt;br&gt;
  "properties": {&lt;br&gt;
    "title": {&lt;br&gt;
      "type": "string",&lt;br&gt;
      "description": "The title field"&lt;br&gt;
    },&lt;br&gt;
    "price": {&lt;br&gt;
      "type": "string",&lt;br&gt;
      "description": "The price field"&lt;br&gt;
    },&lt;br&gt;
    "currency": {&lt;br&gt;
      "type": "string",&lt;br&gt;
      "description": "The currency field"&lt;br&gt;
    },&lt;br&gt;
    "sku": {&lt;br&gt;
      "type": "string",&lt;br&gt;
      "description": "The sku field"&lt;br&gt;
    },&lt;br&gt;
    "availability": {&lt;br&gt;
      "type": "string",&lt;br&gt;
      "description": "The availability field"&lt;br&gt;
    }&lt;br&gt;
  }&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;result = client.extract(&lt;br&gt;
    url="&lt;a href="https://www.target.com/p/apple-iphone-15-pro/-/A-88932345" rel="noopener noreferrer"&gt;https://www.target.com/p/apple-iphone-15-pro/-/A-88932345&lt;/a&gt;",&lt;br&gt;
    schema=schema,&lt;br&gt;
)&lt;br&gt;
print(result.data)&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


**Output:**


```json
{
  "title": "Apple iPhone 15 Pro - 256GB Black Titanium",
  "price": "999.99",
  "currency": "USD",
  "sku": "A-88932345",
  "availability": "In Stock"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The equivalent cURL request:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;```bash title="Terminal"&lt;br&gt;
curl -X POST &lt;a href="https://api.alterlab.io/v1/extract" rel="noopener noreferrer"&gt;https://api.alterlab.io/v1/extract&lt;/a&gt; \&lt;br&gt;
  -H "X-API-Key: YOUR_KEY" \&lt;br&gt;
  -H "Content-Type: application/json" \&lt;br&gt;
  -d '{&lt;br&gt;
    "url": "&lt;a href="https://www.target.com/p/apple-iphone-15-pro/-/A-88932345" rel="noopener noreferrer"&gt;https://www.target.com/p/apple-iphone-15-pro/-/A-88932345&lt;/a&gt;",&lt;br&gt;
    "schema": {&lt;br&gt;
      "properties": {&lt;br&gt;
        "title": {"type": "string"},&lt;br&gt;
        "price": {"type": "string"},&lt;br&gt;
        "currency": {"type": "string"},&lt;br&gt;
        "sku": {"type": "string"},&lt;br&gt;
        "availability": {"type": "string"}&lt;br&gt;
      }&lt;br&gt;
    }&lt;br&gt;
  }'&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


For batch processing, use asynchronous jobs to handle rate limits efficiently:



```python title="batch_target.py" {8-15}

client = alterlab.Client("YOUR_API_KEY")

async def extract_product(url):
    schema = {"properties": {"title": {"type": "string"}, "price": {"type": "string"}}}
    return await client.extract(url=url, schema=schema)

urls = [
    "https://www.target.com/p/apple-iphone-15-pro/-/A-88932345",
    "https://www.target.com/p/samsung-galaxy-s24/-/A-89012345",
    "https://www.target.com/p/google-pixel-8-pro/-/A-89123456"
]

async def main():
    tasks = [extract_product(url) for url in urls]
    results = await asyncio.gather(*tasks)
    for i, res in enumerate(results):
        print(f"Product {i+1}: {res.data}")

asyncio.run(main())
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Define your schema
&lt;/h2&gt;

&lt;p&gt;The Extract API uses JSON Schema Draft 07 for validation. Key principles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Type safety&lt;/strong&gt;: Specify &lt;code&gt;string&lt;/code&gt;, &lt;code&gt;number&lt;/code&gt;, &lt;code&gt;boolean&lt;/code&gt;, or &lt;code&gt;object&lt;/code&gt; types&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Field descriptions&lt;/strong&gt;: Improve AI extraction accuracy with clear semantics&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Required fields&lt;/strong&gt;: Mark critical data as &lt;code&gt;"required": ["title", "price"]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Default values&lt;/strong&gt;: Provide fallbacks for occasionally missing fields&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example schema for enriched product data:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"object"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"required"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"price"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"sku"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"properties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Full product title"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"price"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Current price"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"currency"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"enum"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"USD"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"CAD"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"default"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"USD"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"sku"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"pattern"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^A-&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;d{8}$"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"availability"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"enum"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"In Stock"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Out of Stock"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Pre-order"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Limited Availability"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"rating"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"pattern"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;d&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;.&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;d$"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"brand"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;AlterLab returns only validated data matching this schema. Invalid fields are omitted (not nulled), ensuring your pipeline receives clean, predictable output.&lt;/p&gt;

&lt;h2&gt;
  
  
  Handle pagination and scale
&lt;/h2&gt;

&lt;p&gt;For catalog-level extraction:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Discover URLs&lt;/strong&gt;: Use sitemaps or category pages to collect product links&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Batch requests&lt;/strong&gt;: Process 10-50 URLs per async job to stay within rate limits&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Error handling&lt;/strong&gt;: Implement retry logic for 429 responses (AlterLab includes &lt;code&gt;Retry-After&lt;/code&gt; header)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost optimization&lt;/strong&gt;: Monitor usage via the dashboard — AlterLab charges only for successful extractions&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;See &lt;a href="https://dev.to/pricing"&gt;pricing&lt;/a&gt; for volume tiers. At 10K extractions/month, the effective cost is ~$0.005 per request. No minimums mean you pay strictly for what you use, with credits rolling over indefinitely.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Schema-first design&lt;/strong&gt;: Define your data shape upfront to eliminate parsing fragility&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Public data focus&lt;/strong&gt;: Extract only what Target intentionally exposes to visitors&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Infrastructure offload&lt;/strong&gt;: AlterLab manages proxies, JavaScript, and anti-bot systems&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Typed output guarantee&lt;/strong&gt;: Receive JSON that strictly conforms to your schema&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scale confidently&lt;/strong&gt;: Async batching and transparent pricing support production pipelines&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Start with a single product page, validate your schema, then scale to full catalog extraction. Your data pipeline gains reliability by shifting from brittle HTML parsing to contract-based data extraction.&lt;/p&gt;

&lt;p&gt;AlterLab // Web Data, Simplified.&lt;/p&gt;

</description>
      <category>dataextraction</category>
      <category>api</category>
      <category>ecommerce</category>
      <category>ai</category>
    </item>
    <item>
      <title>Capterra Data API: Extract Structured JSON in 2026</title>
      <dc:creator>AlterLab</dc:creator>
      <pubDate>Thu, 23 Jul 2026 23:13:36 +0000</pubDate>
      <link>https://dev.to/alterlab/capterra-data-api-extract-structured-json-in-2026-242a</link>
      <guid>https://dev.to/alterlab/capterra-data-api-extract-structured-json-in-2026-242a</guid>
      <description>&lt;h1&gt;
  
  
  Capterra Data API: Extract Structured JSON in 2026
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; To get structured Capterra data via API, use the AlterLab Extract API to send a URL and a JSON schema. The engine handles the browser rendering and anti-bot challenges, returning validated, typed JSON objects containing product names, ratings, and review counts.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclaimer: This guide covers extracting publicly accessible data. Always review a site's robots.txt and Terms of Service before scraping.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why use Capterra data?
&lt;/h2&gt;

&lt;p&gt;For data engineers and AI researchers, Capterra represents a massive repository of qualitative and quantitative software intelligence. Relying on manual collection or fragile parsing scripts is not a viable strategy for production-grade pipelines.&lt;/p&gt;

&lt;p&gt;Engineers typically integrate Capterra data into three main workflows:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Competitive Intelligence Dashboards&lt;/strong&gt;: Automatically tracking how competitor products are rated over time to identify market shifts.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;AI Training &amp;amp; RAG&lt;/strong&gt;: Using real-world user reviews to fine-tune LLMs or as context for Retrieval-Augmented Generation (RAG) in enterprise software assistants.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Market Analytics&lt;/strong&gt;: Aggregating category-wide sentiment to build industry trend reports.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To build these, you need a reliable way to turn unstructured HTML into a predictable data stream. For a &lt;a href="https://dev.to/docs/quickstart/installation"&gt;getting started guide&lt;/a&gt;, see our documentation.&lt;/p&gt;

&lt;h2&gt;
  
  
  What data can you extract?
&lt;/h2&gt;

&lt;p&gt;When building a Capterra data API pipeline, you aren't just looking for "text." You are looking for specific attributes that can be mapped to a database schema. Since we are focusing on publicly available review data, the most common fields include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;product_name&lt;/code&gt;: The official name of the software being reviewed.&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;rating&lt;/code&gt;: The numerical or star-based score (e.g., "4.5/5").&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;review_count&lt;/code&gt;: The total number of user submissions for that product.&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;category&lt;/code&gt;: The software niche (e.g., "CRM" or "Project Management").&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;verified_purchase&lt;/code&gt;: A boolean flag indicating if the reviewer is a confirmed user.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The extraction approach
&lt;/h2&gt;

&lt;p&gt;The traditional method of extracting data involves fetching raw HTML via a library like &lt;code&gt;requests&lt;/code&gt; and then traversing the DOM with &lt;code&gt;BeautifulSoup&lt;/code&gt; or &lt;code&gt;lxml&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;In 2026, this approach is fundamentally broken for sites like Capterra for two reasons:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Dynamic Rendering&lt;/strong&gt;: Much of the content is injected via JavaScript after the initial page load. A standard HTTP request will return an empty shell.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Anti-Bot Complexity&lt;/strong&gt;: Modern web infrastructure uses sophisticated fingerprinting to block non-browser traffic.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A data API approach moves the complexity from your application logic to the infrastructure layer. Instead of writing selectors (which break whenever a &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; class changes), you describe the &lt;em&gt;shape&lt;/em&gt; of the data you want.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick start with AlterLab Extract API
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://dev.to/docs/extract"&gt;Extract API docs&lt;/a&gt; provide the full specification for making these calls. You can interact with the API via Python or direct cURL commands.&lt;/p&gt;

&lt;h3&gt;
  
  
  Python Implementation
&lt;/h3&gt;

&lt;p&gt;Using the Python client is the most efficient way to integrate extraction into existing data pipelines.&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;```python title="extract_capterra-com.py" {5-12}&lt;/p&gt;

&lt;p&gt;client = alterlab.Client("YOUR_API_KEY")&lt;/p&gt;

&lt;h1&gt;
  
  
  Define the exact shape of the data you need
&lt;/h1&gt;

&lt;p&gt;schema = {&lt;br&gt;
  "type": "object",&lt;br&gt;
  "properties": {&lt;br&gt;
    "product_name": {&lt;br&gt;
      "type": "string",&lt;br&gt;
      "description": "The name of the software product"&lt;br&gt;
    },&lt;br&gt;
    "rating": {&lt;br&gt;
      "type": "string",&lt;br&gt;
      "description": "The star rating value"&lt;br&gt;
    },&lt;br&gt;
    "review_count": {&lt;br&gt;
      "type": "string",&lt;br&gt;
      "description": "The total number of reviews"&lt;br&gt;
    },&lt;br&gt;
    "category": {&lt;br&gt;
      "type": "string",&lt;br&gt;
      "description": "The software category"&lt;br&gt;
    },&lt;br&gt;
    "verified_purchase": {&lt;br&gt;
      "type": "boolean",&lt;br&gt;
      "description": "Whether the review is a verified purchase"&lt;br&gt;
    }&lt;br&gt;
  }&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;result = client.extract(&lt;br&gt;
    url="&lt;a href="https://capterra.com/p/12345/product-name/" rel="noopener noreferrer"&gt;https://capterra.com/p/12345/product-name/&lt;/a&gt;",&lt;br&gt;
    schema=schema,&lt;br&gt;
)&lt;/p&gt;

&lt;p&gt;print(result.data)&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


**Expected Output:**


```json
{
  "product_name": "Example CRM",
  "rating": "4.8",
  "review_count": "1,240",
  "category": "Customer Relationship Management",
  "verified_purchase": true
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  cURL Implementation
&lt;/h3&gt;

&lt;p&gt;For shell scripts or lightweight services, use the POST endpoint directly.&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;```bash title="Terminal"&lt;br&gt;
curl -X POST &lt;a href="https://api.alterlab.io/v1/extract" rel="noopener noreferrer"&gt;https://api.alterlab.io/v1/extract&lt;/a&gt; \&lt;br&gt;
  -H "X-API-Key: YOUR_KEY" \&lt;br&gt;
  -H "Content-Type: application/json" \&lt;br&gt;
  -d '{&lt;br&gt;
    "url": "&lt;a href="https://capterra.com/p/12345/product-name/" rel="noopener noreferrer"&gt;https://capterra.com/p/12345/product-name/&lt;/a&gt;",&lt;br&gt;
    "schema": {&lt;br&gt;
      "type": "object",&lt;br&gt;
      "properties": {&lt;br&gt;
        "product_name": {"type": "string"},&lt;br&gt;
        "rating": {"type": "string"},&lt;br&gt;
        "review_count": {"type": "string"}&lt;br&gt;
      }&lt;br&gt;
    }&lt;br&gt;
  }'&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


## Define your schema

The core strength of a data API is the schema. Unlike a web scraper that returns a messy blob of HTML, the Extract API uses the schema to perform intelligent extraction. 

When you provide a JSON schema, the engine:
1.  Navigates the page to find relevant nodes.
2.  Uses LLM-based reasoning to map text to your specific keys.
3.  Validates the output against your types (e.g., ensuring a `boolean` is actually `true` or `false`).

This eliminates the "selector maintenance" cycle that plagues traditional scraping. If Capterra changes their UI from a `&amp;lt;span&amp;gt;` to a `&amp;lt;div&amp;gt;`, your pipeline remains unbroken because the underlying semantic data hasn't changed.

## Handle pagination and scale

If you are building a comprehensive dataset, you will need to handle multiple pages of reviews. For high-volume extraction, do not use synchronous loops. Instead, utilize asynchronous jobs to maximize throughput.



```python title="batch_extraction.py" {4-9}

client = alterlab.Client("YOUR_API_KEY")

urls = [
    "https://capterra.com/p/1/product-a/",
    "https://capterra.com/p/2/product-b/",
    "https://capterra.com/p/3/product-c/"
]

# Submit jobs in parallel
jobs = [
    client.extract_async(url=u, schema=my_schema) 
    for u in urls
]

# Poll for results or use webhooks
for job in jobs:
    print(job.get_result())
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When scaling, keep an eye on your &lt;a href="https://dev.to/pricing"&gt;AlterLab pricing&lt;/a&gt;. Costs are calculated per extraction. You can use the &lt;code&gt;POST /v1/extract/estimate&lt;/code&gt; endpoint to calculate costs before running large batches, which is critical for managing budget in production environments.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Schema over Selectors&lt;/strong&gt;: Use JSON schemas to define data shapes instead of fragile CSS/XPath selectors.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Data API vs Scraper&lt;/strong&gt;: Treat your extraction as a structured data request rather than a web scraping task.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Scale Asynchronously&lt;/strong&gt;: For large-scale Capterra data extraction, use async jobs and webhooks to prevent bottlenecking.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Predictable Costs&lt;/strong&gt;: Use the estimation endpoint to manage spend when running large-scale batch jobs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hit reply if you have questions.&lt;/p&gt;

&lt;p&gt;AlterLab // Web Data, Simplified.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>dataextraction</category>
      <category>api</category>
      <category>datapipelines</category>
    </item>
    <item>
      <title>ESPN Data API: Extract Structured JSON in 2026</title>
      <dc:creator>AlterLab</dc:creator>
      <pubDate>Thu, 23 Jul 2026 23:13:35 +0000</pubDate>
      <link>https://dev.to/alterlab/espn-data-api-extract-structured-json-in-2026-2o26</link>
      <guid>https://dev.to/alterlab/espn-data-api-extract-structured-json-in-2026-2o26</guid>
      <description>&lt;p&gt;This guide covers extracting publicly accessible data. Always review a site's robots.txt and Terms of Service before scraping.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;Use AlterLab's Extract API to get structured JSON from ESPN pages by defining a schema for fields like team, score, date, venue and competition. Send a POST request with the URL and schema to receive validated, typed JSON output—no HTML parsing required.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why use ESPN data?
&lt;/h2&gt;

&lt;p&gt;Sports data powers real-time analytics, AI model training for game outcome prediction, and competitive intelligence for sports betting platforms. Developers build dashboards tracking team performance trends or monitor injury reports across leagues. Researchers correlate historical match data with social media sentiment for fan engagement studies. All require reliable, structured access to publicly listed game statistics.&lt;/p&gt;

&lt;h2&gt;
  
  
  What data can you extract?
&lt;/h2&gt;

&lt;p&gt;From publicly accessible ESPN pages (e.g., scoreboards, team pages, event summaries), you can extract:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;team&lt;/strong&gt;: String (e.g., "Los Angeles Lakers")&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;score&lt;/strong&gt;: String (e.g., "112-107")&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;date&lt;/strong&gt;: String in ISO 8601 format (e.g., "2026-03-15T20:00:00Z")&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;venue&lt;/strong&gt;: String (e.g., "Crypto.com Arena")&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;competition&lt;/strong&gt;: String (e.g., "NBA Regular Season")
These fields represent core game metadata available without authentication on standard ESPN URLs. Define additional fields in your schema as needed—AlterLab validates output types against your specification.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The extraction approach
&lt;/h2&gt;

&lt;p&gt;Raw HTTP requests to ESPN return HTML filled with dynamic JavaScript-rendered content, embedded ads, and anti-bot measures. Parsing this with regex or brittle CSS selectors breaks when ESPN updates its frontend. AlterLab's Extract API handles headless browsing, JavaScript execution, and proxy rotation automatically. You receive clean JSON matching your schema—eliminating parsing logic and reducing maintenance overhead. This shifts focus from HTML gymnastics to data pipeline logic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick start with AlterLab Extract API
&lt;/h2&gt;

&lt;p&gt;First, install the AlterLab Python client via the &lt;a href="https://dev.to/docs/quickstart/installation"&gt;Getting started guide&lt;/a&gt;. Then define your schema and call the extract endpoint.&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;```python title="extract_espn-com.py" {5-12}&lt;/p&gt;

&lt;p&gt;client = alterlab.Client("YOUR_API_KEY")&lt;/p&gt;

&lt;p&gt;schema = {&lt;br&gt;
  "type": "object",&lt;br&gt;
  "properties": {&lt;br&gt;
    "team": {&lt;br&gt;
      "type": "string",&lt;br&gt;
      "description": "The team field"&lt;br&gt;
    },&lt;br&gt;
    "score": {&lt;br&gt;
      "type": "string",&lt;br&gt;
      "description": "The score field"&lt;br&gt;
    },&lt;br&gt;
    "date": {&lt;br&gt;
      "type": "string",&lt;br&gt;
      "description": "The date field"&lt;br&gt;
    },&lt;br&gt;
    "venue": {&lt;br&gt;
      "type": "string",&lt;br&gt;
      "description": "The venue field"&lt;br&gt;
    },&lt;br&gt;
    "competition": {&lt;br&gt;
      "type": "string",&lt;br&gt;
      "description": "The competition field"&lt;br&gt;
    }&lt;br&gt;
  }&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;result = client.extract(&lt;br&gt;
    url="&lt;a href="https://www.espn.com/nba/scoreboard/_/date/20260315" rel="noopener noreferrer"&gt;https://www.espn.com/nba/scoreboard/_/date/20260315&lt;/a&gt;",&lt;br&gt;
    schema=schema,&lt;br&gt;
)&lt;br&gt;
print(result.data)&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


The highlighted lines show schema definition and the extract call. For direct HTTP, use cURL:



```bash title="Terminal"
curl -X POST https://api.alterlab.io/v1/extract \
  -H "X-API-Key: YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://www.espn.com/nba/scoreboard/_/date/20260315",
    "schema": {
      "properties": {
        "team": {"type": "string"},
        "score": {"type": "string"},
        "date": {"type": "string"},
        "venue": {"type": "string"},
        "competition": {"type": "string"}
      }
    }
  }'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Both examples return JSON like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"team"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Los Angeles Lakers"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"score"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"112-107"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-03-15T20:00:00Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"venue"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Crypto.com Arena"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"competition"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"NBA Regular Season"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Define your schema
&lt;/h2&gt;

&lt;p&gt;The schema parameter uses JSON Schema Draft 07 to specify expected output types and structure. AlterLab validates the extracted data against this schema before returning results. If a field doesn't match (e.g., expecting a string but getting nested object), the API returns a validation error—preventing malformed data from entering your pipeline. Include descriptions for documentation; they don't affect validation but appear in AlterLab's interactive API explorer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Handle pagination and scale
&lt;/h2&gt;

&lt;p&gt;For high-volume extraction (e.g., scraping entire league schedules), use asynchronous jobs via AlterLab's batch endpoint. Group 100 URLs per request to stay within rate limits. Monitor costs using the &lt;a href="https://dev.to/pricing"&gt;pricing&lt;/a&gt; page—each extraction costs between $0.001 and $0.50 based on complexity. For recurring tasks, combine with AlterLab's scheduling feature to automate daily ESPN scoreboard pulls at 2 AM UTC.&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;```python title="batch_extract.py" {8-15}&lt;/p&gt;

&lt;p&gt;client = alterlab.Client("YOUR_API_KEY")&lt;/p&gt;

&lt;p&gt;urls = [&lt;br&gt;
    f"&lt;a href="https://www.espn.com/nba/scoreboard/_/date/202603%7Bstr(i).zfill(2)%7D" rel="noopener noreferrer"&gt;https://www.espn.com/nba/scoreboard/_/date/202603{str(i).zfill(2)}&lt;/a&gt;"&lt;br&gt;
    for i in range(1, 32)&lt;br&gt;
]&lt;/p&gt;

&lt;p&gt;async def extract_all():&lt;br&gt;
    tasks = []&lt;br&gt;
    for url in urls:&lt;br&gt;
        task = client.extract_async(&lt;br&gt;
            url=url,&lt;br&gt;
            schema={"properties": {"team": {"type": "string"}, "score": {"type": "string"}}}&lt;br&gt;
        )&lt;br&gt;
        tasks.append(task)&lt;br&gt;
    return await asyncio.gather(*tasks)&lt;/p&gt;

&lt;p&gt;results = asyncio.run(extract_all())&lt;br&gt;
for res in results:&lt;br&gt;
    print(res.data)&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


This async pattern processes multiple ESPN pages concurrently while respecting concurrency limits. Adjust batch size based on your API tier—check your dashboard for current limits.

## Key takeaways
- Define a strict JSON schema for ESPN fields to get typed, validation-guaranteed output
- Avoid HTML parsing fragility by using AlterLab's Extract API for JavaScript-rendered pages
- Start with single URL extraction, then scale using async batching for pipelines
- Always verify public data compliance with ESPN's robots.txt and Terms of Service
- Pay only per extraction—no minimums, no expiring credits

AlterLab transforms ESPN's public pages into reliable data APIs. Focus on building your sports analytics pipeline, not fighting anti-bot systems.
&amp;lt;div data-infographic="stats"&amp;gt;
  &amp;lt;div data-stat data-value="99.2%" data-label="Extraction Accuracy"&amp;gt;&amp;lt;/div&amp;gt;
  &amp;lt;div data-stat data-value="1.4s" data-label="Avg Response Time"&amp;gt;&amp;lt;/div&amp;gt;
  &amp;lt;div data-stat data-value="100%" data-label="Typed JSON Output"&amp;gt;&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div data-infographic="steps"&amp;gt;
  &amp;lt;div data-step data-number="1" data-title="Define Schema" data-description="Specify the fields you want as a JSON schema"&amp;gt;&amp;lt;/div&amp;gt;
  &amp;lt;div data-step data-number="2" data-title="Call Extract API" data-description="POST the URL + schema to AlterLab"&amp;gt;&amp;lt;/div&amp;gt;
  &amp;lt;div data-step data-number="3" data-title="Receive Typed JSON" data-description="Get back validated, structured data — no parsing needed"&amp;gt;&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>dataextraction</category>
      <category>api</category>
      <category>datapipelines</category>
      <category>python</category>
    </item>
  </channel>
</rss>
