Table of contents

How do I scrape data from websites that require specific headers?

Many websites require specific HTTP headers to properly serve content or to identify legitimate requests from browsers versus automated scrapers. Understanding how to set and manage custom headers is essential for successful web scraping. This guide covers various approaches to handle header requirements across different Python libraries and tools.

Understanding HTTP Headers in Web Scraping

HTTP headers are key-value pairs sent with every HTTP request that provide metadata about the request. Common headers that websites check include:

  • User-Agent: Identifies the browser or client making the request
  • Accept: Specifies what content types the client can handle
  • Accept-Language: Indicates preferred languages
  • Referer: Shows the URL of the page that linked to the current request
  • Authorization: Contains authentication credentials
  • Content-Type: Specifies the format of request body data
  • Accept-Encoding: Lists supported compression methods

Setting Headers with Python Requests Library

The requests library is the most popular choice for HTTP requests in Python. Here's how to set custom headers:

Basic Header Configuration

import requests

# Define custom headers
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
    'Accept-Language': 'en-US,en;q=0.5',
    'Accept-Encoding': 'gzip, deflate',
    'Connection': 'keep-alive',
    'Upgrade-Insecure-Requests': '1'
}

# Make request with custom headers
response = requests.get('https://example.com', headers=headers)
print(response.status_code)
print(response.text)

Session-Based Header Management

For multiple requests, use a session to maintain headers across requests:

import requests

# Create session with persistent headers
session = requests.Session()
session.headers.update({
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36',
    'Accept': 'application/json, text/plain, */*',
    'Accept-Language': 'en-US,en;q=0.9',
    'Referer': 'https://example.com'
})

# All requests in this session will use these headers
response1 = session.get('https://api.example.com/data')
response2 = session.get('https://api.example.com/more-data')

# Add specific headers for individual requests
response3 = session.get('https://api.example.com/special', 
                       headers={'X-API-Key': 'your-api-key'})

Dynamic Header Generation

Some websites require headers that change based on the current time or page content:

import requests
import time
from datetime import datetime

def generate_dynamic_headers(page_url):
    """Generate headers with dynamic values"""
    timestamp = str(int(time.time()))

    return {
        'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36',
        'Referer': page_url,
        'X-Requested-With': 'XMLHttpRequest',
        'X-Timestamp': timestamp,
        'Cache-Control': 'no-cache',
        'Pragma': 'no-cache'
    }

# Use dynamic headers
url = 'https://example.com/api/data'
headers = generate_dynamic_headers(url)
response = requests.get(url, headers=headers)

Authentication Headers

Many APIs and protected websites require authentication headers:

Bearer Token Authentication

import requests

# API with Bearer token
token = "your-access-token"
headers = {
    'Authorization': f'Bearer {token}',
    'Content-Type': 'application/json',
    'Accept': 'application/json'
}

response = requests.get('https://api.example.com/protected', headers=headers)

Basic Authentication Header

import requests
import base64

# Manual basic auth header
username = 'your-username'
password = 'your-password'
credentials = base64.b64encode(f"{username}:{password}".encode()).decode()

headers = {
    'Authorization': f'Basic {credentials}',
    'User-Agent': 'Python-Scraper/1.0'
}

response = requests.get('https://example.com/protected', headers=headers)

# Or use requests built-in auth
response = requests.get('https://example.com/protected', 
                       auth=(username, password),
                       headers={'User-Agent': 'Python-Scraper/1.0'})

Headers with Selenium WebDriver

When using Selenium for JavaScript-heavy sites, you can set headers through browser options:

Chrome WebDriver Headers

from selenium import webdriver
from selenium.webdriver.chrome.options import Options

# Configure Chrome options
chrome_options = Options()
chrome_options.add_argument('--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36')
chrome_options.add_argument('--accept-language=en-US,en;q=0.9')

# Create driver with options
driver = webdriver.Chrome(options=chrome_options)

# For more complex header manipulation, use CDP
driver.execute_cdp_cmd('Network.setUserAgentOverride', {
    "userAgent": "Custom-Bot/1.0"
})

# Set additional headers via CDP
driver.execute_cdp_cmd('Network.enable', {})
driver.execute_cdp_cmd('Network.setRequestInterception', {'patterns': [{'urlPattern': '*'}]})

# Navigate to page
driver.get('https://example.com')

Adding Custom Headers with CDP

from selenium import webdriver
from selenium.webdriver.chrome.options import Options

def add_headers_to_requests(driver, headers):
    """Add custom headers to all requests using Chrome DevTools Protocol"""
    driver.execute_cdp_cmd('Network.enable', {})
    driver.execute_cdp_cmd('Network.setRequestInterception', {
        'patterns': [{'urlPattern': '*'}]
    })

    def interceptor(params):
        headers_to_add = []
        for name, value in headers.items():
            headers_to_add.append({'name': name, 'value': value})

        driver.execute_cdp_cmd('Network.continueInterceptedRequest', {
            'interceptionId': params['interceptionId'],
            'headers': headers_to_add
        })

    driver.add_cdp_listener('Network.requestIntercepted', interceptor)

# Usage
chrome_options = Options()
chrome_options.add_argument('--headless')
driver = webdriver.Chrome(options=chrome_options)

custom_headers = {
    'X-Custom-Header': 'CustomValue',
    'Authorization': 'Bearer token123',
    'Accept': 'application/json'
}

add_headers_to_requests(driver, custom_headers)
driver.get('https://api.example.com')

Headers with Other Python Libraries

Using urllib3

import urllib3
from urllib3.util.retry import Retry

# Create pool manager with custom headers
http = urllib3.PoolManager()

# Define default headers
default_headers = {
    'User-Agent': 'Python-urllib3/1.26',
    'Accept': 'text/html,application/xhtml+xml',
    'Accept-Encoding': 'gzip, deflate'
}

# Make request with headers
response = http.request('GET', 'https://example.com', headers=default_headers)
print(response.status)
print(response.data.decode('utf-8'))

Using httpx (Async Alternative)

import httpx
import asyncio

async def scrape_with_headers():
    headers = {
        'User-Agent': 'Mozilla/5.0 (compatible; Python-httpx/0.24.0)',
        'Accept': 'application/json',
        'X-Custom-Header': 'custom-value'
    }

    async with httpx.AsyncClient(headers=headers) as client:
        response = await client.get('https://example.com/api')
        return response.json()

# Run async function
data = asyncio.run(scrape_with_headers())

Common Header Patterns for Different Scenarios

API Scraping Headers

api_headers = {
    'User-Agent': 'YourApp/1.0 (contact@yourcompany.com)',
    'Accept': 'application/json',
    'Content-Type': 'application/json',
    'X-Requested-With': 'XMLHttpRequest',
    'Cache-Control': 'no-cache'
}

Browser Mimicking Headers

browser_headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8',
    'Accept-Language': 'en-US,en;q=0.9',
    'Accept-Encoding': 'gzip, deflate, br',
    'Connection': 'keep-alive',
    'Sec-Fetch-Dest': 'document',
    'Sec-Fetch-Mode': 'navigate',
    'Sec-Fetch-Site': 'none',
    'Upgrade-Insecure-Requests': '1'
}

Mobile Device Headers

mobile_headers = {
    'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 15_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.0 Mobile/15E148 Safari/604.1',
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
    'Accept-Language': 'en-US,en;q=0.5',
    'Accept-Encoding': 'gzip, deflate',
    'Connection': 'keep-alive'
}

Error Handling and Debugging

Checking Response Headers

import requests

headers = {'User-Agent': 'Custom-Agent/1.0'}
response = requests.get('https://httpbin.org/headers', headers=headers)

# Check what headers were sent
print("Request headers:")
print(response.request.headers)

# Check response headers
print("\nResponse headers:")
print(response.headers)

# Check if custom header was received
response_data = response.json()
print("\nHeaders received by server:")
print(response_data['headers'])

Handling Header-Related Errors

import requests
from requests.exceptions import RequestException

def scrape_with_fallback_headers(url, header_sets):
    """Try multiple header configurations if requests fail"""

    for i, headers in enumerate(header_sets):
        try:
            response = requests.get(url, headers=headers, timeout=10)
            response.raise_for_status()

            print(f"Success with header set {i + 1}")
            return response

        except RequestException as e:
            print(f"Header set {i + 1} failed: {e}")
            continue

    raise Exception("All header configurations failed")

# Define multiple header strategies
header_strategies = [
    {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/120.0.0.0'},
    {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) Safari/537.36'},
    {'User-Agent': 'curl/7.68.0', 'Accept': '*/*'}
]

try:
    response = scrape_with_fallback_headers('https://example.com', header_strategies)
    print(response.text[:100])
except Exception as e:
    print(f"All attempts failed: {e}")

Best Practices and Considerations

Header Rotation

import random
import requests

class HeaderRotator:
    def __init__(self):
        self.user_agents = [
            'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
            'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36',
            'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36'
        ]

        self.accept_languages = [
            'en-US,en;q=0.9',
            'en-GB,en;q=0.8',
            'fr-FR,fr;q=0.9,en;q=0.8'
        ]

    def get_random_headers(self):
        return {
            'User-Agent': random.choice(self.user_agents),
            'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
            'Accept-Language': random.choice(self.accept_languages),
            'Accept-Encoding': 'gzip, deflate',
            'Connection': 'keep-alive'
        }

# Usage
rotator = HeaderRotator()

for url in urls_to_scrape:
    headers = rotator.get_random_headers()
    response = requests.get(url, headers=headers)
    # Process response...

Integration with WebScraping.AI

When working with complex header requirements, consider using specialized web scraping APIs. For instance, when dealing with websites that have sophisticated anti-bot measures, you might need to handle authentication flows or monitor network requests to understand the exact header patterns required.

Command Line Testing

Test your headers using curl before implementing in Python:

# Test with custom headers
curl -H "User-Agent: Custom-Agent/1.0" \
     -H "Accept: application/json" \
     -H "Authorization: Bearer token123" \
     https://api.example.com/data

# Verbose output to see all headers
curl -v -H "User-Agent: Custom-Agent/1.0" https://example.com

# Save response headers to file
curl -D headers.txt -H "User-Agent: Custom-Agent/1.0" https://example.com

Conclusion

Setting appropriate HTTP headers is crucial for successful web scraping. Whether you're dealing with API authentication, browser detection, or content negotiation, understanding how to configure headers correctly will help you access the data you need while respecting website requirements. Always ensure your scraping practices comply with the website's terms of service and robots.txt file.

Remember to rotate headers when making multiple requests, handle errors gracefully, and test your header configurations thoroughly before deploying production scrapers. For complex scenarios involving JavaScript-heavy sites, consider combining header management with tools like Selenium or specialized web scraping services.

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