Table of contents

How Do I Extract Data from HTML Using GPT?

Extracting data from HTML using GPT involves leveraging large language models to intelligently parse and structure web content without relying on fragile CSS selectors or XPath expressions. GPT can understand the semantic meaning of HTML elements and extract relevant information based on natural language instructions, making it ideal for handling complex, inconsistent, or frequently changing web pages.

Why Extract Data from HTML Using GPT?

Traditional HTML parsing requires writing specific selectors for each data point. When website layouts change, your extraction code breaks. GPT-based extraction offers several advantages:

  • Adaptability: Works across different HTML structures without code modifications
  • Semantic understanding: Extracts data based on meaning, not just DOM position
  • Natural language instructions: Specify what you need in plain English
  • Reduced maintenance: Less brittle than selector-based approaches
  • Complex pattern recognition: Handles variations in data presentation

This approach is particularly valuable when: - Scraping sites with inconsistent HTML structure - Extracting information embedded in natural language - Dealing with frequently updated layouts - Processing unstructured or semi-structured data

Prerequisites

Before extracting data from HTML with GPT, you'll need:

  • An OpenAI API key from platform.openai.com
  • A method to fetch HTML content (requests, axios, or browser automation)
  • Basic understanding of JSON and API calls

Method 1: Basic HTML Extraction with Python

Here's a complete Python example that fetches HTML and extracts structured data using GPT:

import openai
import requests
from bs4 import BeautifulSoup

# Initialize OpenAI client
client = openai.OpenAI(api_key="your-api-key-here")

def fetch_html(url):
    """Fetch HTML content from a URL"""
    response = requests.get(url, headers={
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
    })
    return response.text

def extract_data_from_html(html_content, extraction_instructions):
    """Extract structured data from HTML using GPT"""

    # Create the extraction prompt
    system_prompt = """You are an expert at extracting structured data from HTML.
    Analyze the HTML and extract only the requested information.
    Return the data as valid JSON with clear field names.
    If information is not available, use null instead of guessing."""

    user_prompt = f"""Extract data from this HTML according to the following instructions:

{extraction_instructions}

HTML Content:
{html_content}

Return ONLY valid JSON, no explanations or markdown formatting."""

    # Call GPT API
    response = client.chat.completions.create(
        model="gpt-4",
        messages=[
            {"role": "system", "content": system_prompt},
            {"role": "user", "content": user_prompt}
        ],
        temperature=0,  # Use 0 for consistent, deterministic output
        response_format={"type": "json_object"}
    )

    return response.choices[0].message.content

# Example usage
url = "https://example.com/product"
html = fetch_html(url)

# Define what to extract
instructions = """
Extract the following product information:
- name: Product name or title
- price: Numeric price value (without currency symbols)
- currency: Currency code (USD, EUR, etc.)
- description: Product description text
- rating: Average rating (0-5 scale)
- reviews_count: Number of customer reviews
- availability: Whether the product is in stock (true/false)
- images: Array of image URLs

If any field is not found, set it to null.
"""

result = extract_data_from_html(html, instructions)
print(result)

Output example:

{
  "name": "Wireless Bluetooth Headphones",
  "price": 79.99,
  "currency": "USD",
  "description": "Premium over-ear headphones with active noise cancellation",
  "rating": 4.5,
  "reviews_count": 1234,
  "availability": true,
  "images": [
    "https://example.com/images/headphones-front.jpg",
    "https://example.com/images/headphones-side.jpg"
  ]
}

Method 2: HTML Extraction with JavaScript/Node.js

Here's the equivalent implementation in JavaScript:

const OpenAI = require('openai');
const axios = require('axios');
const cheerio = require('cheerio');

const openai = new OpenAI({
  apiKey: process.env.OPENAI_API_KEY
});

async function fetchHTML(url) {
  const response = await axios.get(url, {
    headers: {
      'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
    }
  });
  return response.data;
}

async function extractDataFromHTML(htmlContent, extractionInstructions) {
  const systemPrompt = `You are an expert at extracting structured data from HTML.
Analyze the HTML and extract only the requested information.
Return the data as valid JSON with clear field names.
If information is not available, use null instead of guessing.`;

  const userPrompt = `Extract data from this HTML according to the following instructions:

${extractionInstructions}

HTML Content:
${htmlContent}

Return ONLY valid JSON, no explanations or markdown formatting.`;

  const response = await openai.chat.completions.create({
    model: 'gpt-4',
    messages: [
      { role: 'system', content: systemPrompt },
      { role: 'user', content: userPrompt }
    ],
    temperature: 0,
    response_format: { type: 'json_object' }
  });

  return JSON.parse(response.choices[0].message.content);
}

// Example usage
async function main() {
  const url = 'https://example.com/article';
  const html = await fetchHTML(url);

  const instructions = `
Extract the following article information:
- headline: Main article headline
- author: Author name
- publish_date: Publication date in ISO format (YYYY-MM-DD)
- category: Article category or section
- tags: Array of article tags
- word_count: Approximate word count of the article
- summary: Brief 2-3 sentence summary

If any field is not found, set it to null.
  `;

  const data = await extractDataFromHTML(html, instructions);
  console.log(JSON.stringify(data, null, 2));
}

main().catch(console.error);

Method 3: Preprocessing HTML for Better Results

To improve extraction accuracy and reduce token usage, preprocess the HTML before sending it to GPT:

from bs4 import BeautifulSoup

def clean_html_for_extraction(html_content):
    """Clean and simplify HTML for GPT processing"""
    soup = BeautifulSoup(html_content, 'html.parser')

    # Remove elements that don't contain useful data
    for element in soup(['script', 'style', 'noscript', 'meta', 'link',
                         'iframe', 'nav', 'footer', 'header', 'aside']):
        element.decompose()

    # Remove HTML comments
    from bs4 import Comment
    for comment in soup.find_all(string=lambda text: isinstance(text, Comment)):
        comment.extract()

    # Remove empty tags
    for tag in soup.find_all():
        if len(tag.get_text(strip=True)) == 0 and not tag.find('img'):
            tag.decompose()

    # Simplify attributes (keep only class and id for context)
    for tag in soup.find_all(True):
        attrs_to_keep = {}
        if tag.has_attr('class'):
            attrs_to_keep['class'] = tag['class']
        if tag.has_attr('id'):
            attrs_to_keep['id'] = tag['id']
        tag.attrs = attrs_to_keep

    return str(soup)

# Use cleaned HTML
html = fetch_html(url)
cleaned_html = clean_html_for_extraction(html)
result = extract_data_from_html(cleaned_html, instructions)

Method 4: Extracting Specific Sections

For large pages, extract only relevant sections before processing with GPT:

def extract_section_and_process(html_content, css_selector, extraction_instructions):
    """Extract a specific HTML section and process with GPT"""
    soup = BeautifulSoup(html_content, 'html.parser')

    # Find the target section
    section = soup.select_one(css_selector)

    if not section:
        raise ValueError(f"Section not found: {css_selector}")

    # Convert section to string and clean
    section_html = clean_html_for_extraction(str(section))

    # Extract data from the section
    return extract_data_from_html(section_html, extraction_instructions)

# Example: Extract only the product details section
result = extract_section_and_process(
    html_content=html,
    css_selector='.product-details',
    extraction_instructions=product_extraction_instructions
)

Method 5: Batch Processing Multiple Items

When extracting data from pages with multiple items (product listings, search results, etc.):

def extract_multiple_items(html_content, extraction_instructions):
    """Extract multiple items from HTML in one API call"""

    system_prompt = """You are an expert at extracting structured data from HTML.
    Extract ALL items from the page and return them as a JSON array.
    Each item should follow the specified structure.
    Return {"items": [...]} with all extracted items."""

    response = client.chat.completions.create(
        model="gpt-4",
        messages=[
            {"role": "system", "content": system_prompt},
            {"role": "user", "content": f"{extraction_instructions}\n\nHTML:\n{html_content}"}
        ],
        temperature=0,
        response_format={"type": "json_object"}
    )

    return response.choices[0].message.content

# Example usage
instructions = """
Extract ALL products from this page.
For each product, extract:
- name: Product name
- price: Numeric price
- image_url: Main product image URL
- product_url: Link to product page

Return as: {"items": [{"name": "...", "price": 0.00, ...}, ...]}
"""

result = extract_multiple_items(html, instructions)

Combining GPT with Browser Automation

For JavaScript-heavy websites, combine browser automation with GPT extraction. This is especially useful when you need to handle AJAX requests using Puppeteer:

const puppeteer = require('puppeteer');
const OpenAI = require('openai');

const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });

async function scrapeWithBrowserAndGPT(url, extractionInstructions) {
  // Launch browser
  const browser = await puppeteer.launch({ headless: true });
  const page = await browser.newPage();

  // Navigate to page
  await page.goto(url, { waitUntil: 'networkidle2' });

  // Wait for dynamic content
  await page.waitForSelector('.main-content', { timeout: 5000 });

  // Get rendered HTML
  const htmlContent = await page.content();
  await browser.close();

  // Extract data using GPT
  const response = await openai.chat.completions.create({
    model: 'gpt-4',
    messages: [
      {
        role: 'system',
        content: 'Extract structured data from HTML as JSON.'
      },
      {
        role: 'user',
        content: `${extractionInstructions}\n\nHTML:\n${htmlContent.substring(0, 8000)}`
      }
    ],
    temperature: 0,
    response_format: { type: 'json_object' }
  });

  return JSON.parse(response.choices[0].message.content);
}

// Example usage
const instructions = `
Extract pricing information:
- plan_name: Subscription plan name
- monthly_price: Monthly price
- annual_price: Annual price
- features: Array of included features
`;

scrapeWithBrowserAndGPT('https://example.com/pricing', instructions)
  .then(data => console.log(data))
  .catch(error => console.error(error));

Using Function Calling for Type Safety

OpenAI's function calling ensures GPT returns data in your exact schema:

import json

def extract_with_function_calling(html_content):
    """Extract data with guaranteed schema using function calling"""

    tools = [
        {
            "type": "function",
            "function": {
                "name": "save_extracted_data",
                "description": "Save extracted product data",
                "parameters": {
                    "type": "object",
                    "properties": {
                        "product_name": {
                            "type": "string",
                            "description": "The product name"
                        },
                        "price": {
                            "type": "number",
                            "description": "Product price as a number"
                        },
                        "currency": {
                            "type": "string",
                            "enum": ["USD", "EUR", "GBP", "CAD"],
                            "description": "Currency code"
                        },
                        "in_stock": {
                            "type": "boolean",
                            "description": "Whether product is available"
                        },
                        "features": {
                            "type": "array",
                            "items": {"type": "string"},
                            "description": "List of product features"
                        },
                        "specifications": {
                            "type": "object",
                            "description": "Product specifications as key-value pairs"
                        }
                    },
                    "required": ["product_name", "price", "currency"]
                }
            }
        }
    ]

    response = client.chat.completions.create(
        model="gpt-4",
        messages=[
            {
                "role": "user",
                "content": f"Extract product data from this HTML:\n{html_content}"
            }
        ],
        tools=tools,
        tool_choice={"type": "function", "function": {"name": "save_extracted_data"}}
    )

    # Parse the function call arguments
    tool_call = response.choices[0].message.tool_calls[0]
    extracted_data = json.loads(tool_call.function.arguments)

    return extracted_data

# Usage
result = extract_with_function_calling(html)
print(json.dumps(result, indent=2))

Advanced Prompting Techniques

1. Few-Shot Learning

Provide examples to improve extraction accuracy:

extraction_prompt = """
Extract event information from HTML.

Example output format:
{
  "event_name": "Tech Conference 2024",
  "date": "2024-03-15",
  "location": "San Francisco, CA",
  "price": 299.00,
  "organizer": "Tech Events Inc"
}

Now extract the event information from this HTML:
{html_content}

Return only JSON, no additional text.
"""

2. Handling Date Formats

Instruct GPT to normalize dates:

instructions = """
Extract and normalize the following:
- event_date: Convert any date format to ISO 8601 (YYYY-MM-DD)
- time: Convert to 24-hour format (HH:MM)
- timezone: Extract timezone if mentioned

Examples:
- "March 15th, 2024" → "2024-03-15"
- "15/03/2024" → "2024-03-15"
- "2 days from now" → Calculate and return as ISO date
"""

3. Extracting Nested Data

For complex hierarchical structures:

instructions = """
Extract company data with nested structure:

{
  "company_name": "string",
  "headquarters": {
    "city": "string",
    "country": "string",
    "address": "string"
  },
  "departments": [
    {
      "name": "string",
      "employees": [
        {
          "name": "string",
          "title": "string",
          "email": "string"
        }
      ]
    }
  ]
}

Extract all available information from the HTML.
"""

Handling Token Limits

GPT models have token limits. For large HTML files:

Strategy 1: Chunking

def chunk_html(html, max_tokens=6000):
    """Split HTML into chunks based on token estimate"""
    # Rough estimate: 1 token ≈ 4 characters
    max_chars = max_tokens * 4

    soup = BeautifulSoup(html, 'html.parser')
    sections = soup.find_all(['section', 'article', 'div'], class_=True)

    chunks = []
    current_chunk = []
    current_size = 0

    for section in sections:
        section_html = str(section)
        section_size = len(section_html)

        if current_size + section_size > max_chars and current_chunk:
            chunks.append(''.join(current_chunk))
            current_chunk = [section_html]
            current_size = section_size
        else:
            current_chunk.append(section_html)
            current_size += section_size

    if current_chunk:
        chunks.append(''.join(current_chunk))

    return chunks

def process_large_html(html, instructions):
    """Process large HTML by chunking"""
    chunks = chunk_html(html)
    all_results = []

    for i, chunk in enumerate(chunks):
        print(f"Processing chunk {i+1}/{len(chunks)}...")
        result = extract_data_from_html(chunk, instructions)
        all_results.append(json.loads(result))

    return all_results

Strategy 2: Convert to Text

def html_to_clean_text(html):
    """Convert HTML to clean text for token efficiency"""
    soup = BeautifulSoup(html, 'html.parser')

    # Remove unwanted elements
    for element in soup(['script', 'style', 'nav', 'footer', 'header']):
        element.decompose()

    # Get text with preserved structure
    text = soup.get_text(separator='\n', strip=True)

    # Remove excessive whitespace
    lines = [line.strip() for line in text.splitlines() if line.strip()]
    return '\n'.join(lines)

# Use text instead of HTML for lower token usage
text_content = html_to_clean_text(html)
result = extract_data_from_html(text_content, instructions)

Error Handling and Validation

Always validate GPT output:

import json
from jsonschema import validate, ValidationError

def extract_and_validate(html, instructions, schema=None):
    """Extract data and validate against schema"""
    try:
        # Extract data
        result_json = extract_data_from_html(html, instructions)
        result = json.loads(result_json)

        # Validate against schema if provided
        if schema:
            validate(instance=result, schema=schema)

        return result

    except json.JSONDecodeError as e:
        print(f"Invalid JSON returned: {e}")
        return None

    except ValidationError as e:
        print(f"Schema validation failed: {e.message}")
        return None

    except Exception as e:
        print(f"Extraction error: {e}")
        return None

# Define validation schema
product_schema = {
    "type": "object",
    "properties": {
        "name": {"type": "string", "minLength": 1},
        "price": {"type": "number", "minimum": 0},
        "in_stock": {"type": "boolean"}
    },
    "required": ["name", "price"]
}

# Extract and validate
result = extract_and_validate(html, instructions, product_schema)

Implementing Retry Logic

Handle API failures gracefully:

import time
from openai import RateLimitError, APIError

def extract_with_retry(html, instructions, max_retries=3):
    """Extract data with exponential backoff retry"""

    for attempt in range(max_retries):
        try:
            return extract_data_from_html(html, instructions)

        except RateLimitError:
            if attempt < max_retries - 1:
                wait_time = (2 ** attempt) * 2
                print(f"Rate limit hit. Waiting {wait_time}s...")
                time.sleep(wait_time)
            else:
                raise

        except APIError as e:
            print(f"API error: {e}")
            if attempt < max_retries - 1:
                time.sleep(2)
            else:
                raise

    return None

Cost Optimization Strategies

Minimize API costs when extracting structured data using GPT:

  1. Use GPT-4o-mini for simple extractions: 15x cheaper than GPT-4
  2. Preprocess HTML: Remove unnecessary elements before sending
  3. Extract sections: Send only relevant parts of the page
  4. Cache results: Store extracted data to avoid re-processing
  5. Batch process: Extract multiple items in a single API call
import hashlib
import pickle
import os

def extract_with_cache(html, instructions, cache_dir='cache'):
    """Extract data with file-based caching"""
    os.makedirs(cache_dir, exist_ok=True)

    # Create cache key from HTML content
    cache_key = hashlib.md5(html.encode()).hexdigest()
    cache_file = os.path.join(cache_dir, f"{cache_key}.pkl")

    # Check cache
    if os.path.exists(cache_file):
        with open(cache_file, 'rb') as f:
            print("Returning cached result")
            return pickle.load(f)

    # Extract data
    result = extract_data_from_html(html, instructions)

    # Save to cache
    with open(cache_file, 'wb') as f:
        pickle.dump(result, f)

    return result

Real-World Use Cases

E-commerce Product Extraction

ecommerce_instructions = """
Extract comprehensive product information:
- name: Full product name
- brand: Brand name
- sku: Product SKU or identifier
- price: Current price (numeric)
- original_price: Original price before discount (if applicable)
- discount_percentage: Discount percentage (if applicable)
- currency: Currency code
- availability: "in_stock", "out_of_stock", or "pre_order"
- rating: Average rating (0-5)
- review_count: Number of reviews
- images: Array of all product image URLs
- description: Full product description
- specifications: Object with technical specs
- shipping_info: Shipping details
- return_policy: Return policy information

Return as JSON with all available fields.
"""

result = extract_data_from_html(product_html, ecommerce_instructions)

News Article Extraction

article_instructions = """
Extract article metadata and content:
- headline: Main article headline
- subheadline: Subheadline or deck
- author: Author name or "Staff" if not specified
- author_bio: Brief author bio if available
- publish_date: Publication date in ISO format (YYYY-MM-DD)
- update_date: Last update date if different from publish date
- category: Primary category
- tags: Array of article tags/keywords
- content: Full article text (main body only)
- summary: 2-3 sentence summary
- word_count: Approximate word count
- read_time: Estimated reading time in minutes
- related_articles: Array of related article titles/links if shown

Return as JSON.
"""

result = extract_data_from_html(article_html, article_instructions)

Job Listing Extraction

job_instructions = """
Extract job posting information:
- title: Job title
- company: Company name
- location: Job location (city, state, country)
- remote_option: "remote", "hybrid", "on-site", or null
- employment_type: "full-time", "part-time", "contract", etc.
- salary_range: {min: number, max: number, currency: string} or null
- experience_level: "entry", "mid", "senior", etc.
- posted_date: Date posted in ISO format
- application_deadline: Deadline date or null
- description: Full job description
- requirements: Array of job requirements
- benefits: Array of benefits/perks
- skills: Array of required/preferred skills
- apply_url: Application URL

Return as JSON with all available information.
"""

result = extract_data_from_html(job_html, job_instructions)

Best Practices Summary

  1. Always set temperature to 0 for consistent extraction results
  2. Use response_format: json_object to ensure valid JSON output
  3. Provide clear, specific instructions about data types and formats
  4. Validate all output before using in your application
  5. Implement retry logic to handle rate limits and API errors
  6. Cache results to reduce costs and improve performance
  7. Preprocess HTML to remove noise and reduce token usage
  8. Use function calling when you need guaranteed schema compliance
  9. Monitor token usage and optimize prompts accordingly
  10. Combine with traditional methods for hybrid approaches

When working with dynamic websites, you can use browser automation to navigate to different pages before extracting data with GPT.

Conclusion

Extracting data from HTML using GPT offers a powerful alternative to traditional web scraping methods. By leveraging natural language understanding, GPT can adapt to varying HTML structures, extract semantic meaning, and return consistently structured data. While it comes with API costs and requires careful prompt engineering, the flexibility and reduced maintenance make it invaluable for scraping complex or frequently changing websites.

For production systems, consider a hybrid approach: use traditional CSS selectors for stable, simple elements, and leverage GPT for complex, unstructured, or frequently changing content. Start with small-scale tests to optimize your prompts and understand costs before scaling to production workloads.

Remember to always respect website terms of service, implement rate limiting, and handle errors gracefully to build robust and ethical web scraping solutions.

Try WebScraping.AI for Your Web Scraping Needs

Looking for a powerful web scraping solution? WebScraping.AI provides an LLM-powered API that combines Chromium JavaScript rendering with rotating proxies for reliable data extraction.

Key Features:

  • AI-powered extraction: Ask questions about web pages or extract structured data fields
  • JavaScript rendering: Full Chromium browser support for dynamic content
  • Rotating proxies: Datacenter and residential proxies from multiple countries
  • Easy integration: Simple REST API with SDKs for Python, Ruby, PHP, and more
  • Reliable & scalable: Built for developers who need consistent results

Getting Started:

Get page content with AI analysis:

curl "https://api.webscraping.ai/ai/question?url=https://example.com&question=What is the main topic?&api_key=YOUR_API_KEY"

Extract structured data:

curl "https://api.webscraping.ai/ai/fields?url=https://example.com&fields[title]=Page title&fields[price]=Product price&api_key=YOUR_API_KEY"

Try in request builder

Related Questions

Get Started Now

WebScraping.AI provides rotating proxies, Chromium rendering and built-in HTML parser for web scraping
Icon