Web Scraping & REST API Data Extraction in Python

Not all data arrives packaged in neat CSV or database tables. Often, the most valuable competitive signals — e-commerce competitor pricing, economic indices, social sentiment, and government data — must be harvested via REST APIs or extracted from public web pages using Web Scraping.

1. Professional REST API Extraction Pipeline

A resilient API client handles connection retries, authentication headers, and automatic pagination:

import os
import requests
import pandas as pd
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry

def fetch_api_records(base_url: str, total_pages: int = 5) -> pd.DataFrame:
    """Fetches paginated JSON records with exponential backoff retries."""
    session = requests.Session()
    retries = Retry(total=3, backoff_factor=1.5, status_forcelist=[429, 500, 502, 503, 504])
    session.mount("https://", HTTPAdapter(max_retries=retries))
    
    headers = {
        "User-Agent": "VeewomDataScienceBot/2.0 (research@veewom.com)",
        "Accept": "application/json"
    }
    
    all_records = []
    for page in range(1, total_pages + 1):
        response = session.get(f"{base_url}?page={page}&limit=100", headers=headers, timeout=10)
        if response.status_code == 200:
            payload = response.json()
            all_records.extend(payload.get('data', []))
        else:
            print(f"Warning: Page {page} returned status {response.status_code}")
            break
            
    # Flatten nested structures into tabular DataFrame
    return pd.json_normalize(all_records)

2. Web Scraping with BeautifulSoup

When parsing HTML tables or product catalogs from static web pages:

from bs4 import BeautifulSoup
import requests
import pandas as pd

html_sample = """
<div class="catalog">
  <div class="item">
    <h3 class="title">Data Science Workstation Pro</h3>
    <span class="price">$2,499.00</span>
    <span class="rating">4.8</span>
  </div>
  <div class="item">
    <h3 class="title">GPU Compute Node A100</h3>
    <span class="price">$8,999.00</span>
    <span class="rating">4.9</span>
  </div>
</div>
"""

soup = BeautifulSoup(html_sample, 'html.parser')
products = []

for item in soup.find_all('div', class_='item'):
    title = item.find('h3', class_='title').text.strip()
    price_raw = item.find('span', class_='price').text.strip()
    price = float(price_raw.replace('$', '').replace(',', ''))
    rating = float(item.find('span', class_='rating').text.strip())
    products.append({'title': title, 'price': price, 'rating': rating})

df_products = pd.DataFrame(products)
print(df_products)

Legal & Ethical Guardrails

Never scrape copyrighted proprietary databases behind login paywalls without explicit written permission (hiQ Labs v. LinkedIn legal precedent). Implement defensive rate-limiting (e.g., minimum 1-second delay between requests) to prevent Denial of Service (DoS) impacts on target hosts.

Frequently Asked Questions (FAQ) - Student & Interview Review

Q1. What is the difference between API data extraction and web scraping?

API extraction accesses structured, authorized data endpoints provided by a service (typically returning clean JSON or XML with token authentication). Web scraping parses unstructured HTML documents directly from public web pages when no official API exists.

Q2. How do I respect website scraping guidelines (robots.txt)?

Always inspect the target domain's /robots.txt file to identify disallowed paths. Set a descriptive User-Agent header, adhere to crawl delay guidelines, implement exponential backoff on HTTP 429 errors, and avoid aggressive parallel scraping that strains servers.

Q3. What is pandas.json_normalize() and why is it essential?

REST APIs frequently return deeply nested JSON objects containing nested dictionaries and arrays. pandas.json_normalize() flattens nested JSON hierarchies into clean tabular columns with dot-separated names (e.g., user.address.geo.lat).

Q4. How do I handle authentication (OAuth2 and Bearer Tokens) in Python?

Pass credentials via HTTP request headers (e.g., {'Authorization': 'Bearer YOUR_TOKEN'}). Never hardcode secret keys in source files; always load credentials from environment variables using python-dotenv.

Q5. When should I use Playwright or Selenium instead of BeautifulSoup?

BeautifulSoup and Requests can only parse static HTML served by the web server. If a modern Single Page App (React, Vue, Angular) dynamically renders content via client-side JavaScript, you must use a headless browser like Playwright to render the DOM.

Explore Related Data Science Tutorials & Next Steps

Broaden your statistical analysis, Python data wrangling, and production engineering expertise:

Data Ingestion Formats: CSV, JSON & Parquet

Parse and normalize nested JSON responses into columnar storage.

Pandas DataFrames Manipulation & Indexing

Convert scraped tables into clean Pandas DataFrames for analysis.

NoSQL & MongoDB for Unstructured Data

Store raw web scraped documents directly into MongoDB collections.

FastAPI REST API Microservices

Build your own data endpoints with rate limits and API authentication.

Share Share on Facebook Share on Twitter Share on LinkedIn Pin on Pinterest Share on Reddit

You may also like this!