ApiaryActive
Try: pause · settings · learn · wipe
← Community / Reading Room
ED
craft · 14 min read

Extracting Data from Websites

Websites are the modern libraries of human knowledge. From government portals that publish annual statistics to hobbyist blogs that share the latest sightings…

Websites are the modern libraries of human knowledge. From government portals that publish annual statistics to hobbyist blogs that share the latest sightings of rare bumblebees, the web holds a staggering amount of structured and unstructured information. For researchers, conservationists, and developers of self‑governing AI agents, the ability to pull that data into a usable form is no longer a luxury—it’s a necessity.

Imagine trying to map the decline of a native bee species across a continent without a single automated feed of observation records. You would spend months, if not years, manually copying tables, parsing PDFs, and reconciling inconsistent naming conventions. With a well‑designed extraction pipeline, the same task can be completed in hours, freeing up valuable time for analysis, policy‑making, and field work.

In this pillar article we’ll dive deep into the technical, ethical, and practical aspects of web scraping. We’ll explore the anatomy of a web page, walk through the most common extraction techniques, discuss how to keep your bots polite and legal, and look at concrete examples that tie directly into bee conservation and AI‑driven governance. By the end, you should have a full toolbox for turning the web’s raw pages into clean, structured datasets ready for analysis.


1. Foundations – What Is Web Scraping?

At its core, web scraping (also called web data extraction) is the automated process of retrieving information from web pages and converting it into a structured format—typically CSV, JSON, or a database table. While the term “scraping” can sound aggressive, most scraping activities are benign and serve legitimate purposes such as:

Use‑caseExample
Market researchAggregating product prices from e‑commerce sites to monitor price trends.
Academic studyHarvesting climate data from meteorological agency portals for longitudinal analysis.
ConservationPulling pollinator sighting records from citizen‑science platforms like iNaturalist.
AI trainingGathering large corpora of text to fine‑tune language models.

According to a Grand View Research report (2023), the global web scraping market is projected to reach USD 5.5 billion by 2030, growing at a CAGR of 14.7 %. The surge is driven by increasing demand for real‑time data pipelines in finance, e‑commerce, and environmental monitoring.

Legal Landscape

Scraping sits at the intersection of contract law, copyright law, and computer‑fraud statutes. In the United States, the Computer Fraud and Abuse Act (CFAA) has been invoked both to prosecute and to defend scraping activities. The landmark case hiQ Labs, Inc. v. LinkedIn Corp. (2022) affirmed that public web pages are generally not protected by the CFAA, provided the scraper respects technical barriers and does not bypass authentication. However, the legal situation varies by jurisdiction, and many websites explicitly forbid scraping in their Terms of Service (ToS).

Best practice: Always review a site’s ToS, check for a robots.txt file, and, when possible, seek explicit permission before launching a large‑scale extraction.


2. Anatomy of a Web Page – From HTML to APIs

Before you can extract data, you need to understand where that data lives. A typical web page is built from three layers:

  1. HTML (HyperText Markup Language) – The skeletal structure that defines elements like <table>, <div>, and <a>.
  2. CSS (Cascading Style Sheets) – The styling rules that affect layout and visual presentation but rarely contain data.
  3. JavaScript – The dynamic engine that can modify the DOM (Document Object Model) after the page loads, often fetching data from back‑end APIs.

HTML & the DOM

When a browser requests https://example.com/bee‑observations, the server returns an HTML document that might look like this:

<table id="observations">
  <tr><th>Date</th><th>Species</th><th>Location</th></tr>
  <tr><td>2024‑04‑12</td><td>Bombus terrestris</td><td>Meadow Park</td></tr>
  <tr><td>2024‑04‑13</td><td>Apis mellifera</td><td>Riverbank</td></tr>
</table>

The DOM is a tree representation of this markup, which JavaScript can traverse and manipulate. Tools like Chrome DevTools let you inspect the DOM in real time, making it easy to locate the CSS selector (#observations tr td) that targets the data you need.

Modern APIs & JSON Endpoints

Many sites now serve data through RESTful APIs that return JSON, bypassing the need to parse HTML entirely. For example, the European Bee Monitoring Initiative (EBMI) publishes a public endpoint:

GET https://api.ebmi.org/v1/records?species=Bombus%20terrestris&year=2023

The response is a compact JSON payload:

{
  "records": [
    {"date":"2023-06-01","location":"Heathfield","count":12},
    {"date":"2023-06-08","location":"Heathfield","count":9}
  ]
}

When an API exists, it’s usually more reliable and less resource‑intensive to query it directly. However, not every site offers a public API, and some hide their endpoints behind authentication or rate limits, prompting the need for HTML scraping.


3. Core Techniques – From Requests to Parsers

3.1 Making HTTP Requests

The first step in any scraping workflow is to fetch the raw page. In Python, the requests library is the go‑to tool:

import requests

url = "https://example.com/bee-observations"
headers = {"User-Agent": "ApiaryBot/1.0 (+https://apiary.org/bot)"}
response = requests.get(url, headers=headers, timeout=10)

if response.status_code == 200:
    html = response.text
else:
    raise RuntimeError(f"Failed with status {response.status_code}")

A well‑crafted User-Agent string signals to the target server who you are and why you’re requesting the page. Some sites block generic agents like “Python‑urllib/3.9”.

3.2 Parsing HTML

Once you have the raw HTML, you need to parse it into a navigable structure. Two popular parsers are:

LibraryLanguageSpeedEase of Use
BeautifulSoupPythonModerateVery beginner‑friendly
CheerioJavaScript/Node.jsFast (uses htmlparser2)jQuery‑like syntax
lxmlPythonFast (C‑based)More complex, but powerful

BeautifulSoup example:

from bs4 import BeautifulSoup

soup = BeautifulSoup(html, "html.parser")
table = soup.find("table", id="observations")
rows = table.find_all("tr")[1:]  # skip header row

data = []
for row in rows:
    cols = row.find_all("td")
    record = {
        "date": cols[0].text.strip(),
        "species": cols[1].text.strip(),
        "location": cols[2].text.strip()
    }
    data.append(record)

The resulting data list can be exported to CSV or inserted into a database.

3.3 Dealing with Pagination

Many sites split large datasets across multiple pages. A typical pagination pattern looks like:

https://example.com/bee-observations?page=1
https://example.com/bee-observations?page=2
...

A loop that increments the page parameter until an empty result set is encountered is a common approach. Always respect the site’s rate limits (see Section 5).

3.4 Extracting from JSON Embedded in HTML

Sometimes a page embeds a JSON blob inside a <script> tag. For example:

<script id="initial-data" type="application/json">
  {"observations":[{"date":"2024-04-12","species":"Bombus terrestris","location":"Meadow Park"}]}
</script>

You can pull this out with a regular expression or a DOM query, then decode it with json.loads.


4. Handling Dynamic Content – When JavaScript Takes Over

Modern websites increasingly rely on client‑side rendering. A simple requests.get will return an HTML skeleton with placeholders like <div id="app"></div>. The real data appears only after JavaScript runs, often via XHR (XMLHttpRequest) or Fetch calls.

4.1 Headless Browsers

A headless browser runs a full Chromium or Firefox engine without a graphical UI, allowing you to capture the rendered DOM. Popular tools include:

ToolLanguageHeadlessNotable Features
SeleniumMultipleYesWide browser support, mature ecosystem
PuppeteerNode.jsYesTight integration with Chrome DevTools
PlaywrightMultipleYesMulti‑browser (Chromium, Firefox, WebKit) support, excellent auto‑wait

Playwright example (Python):

import asyncio
from playwright.async_api import async_playwright

async def scrape():
    async with async_playwright() as p:
        browser = await p.chromium.launch(headless=True)
        page = await browser.new_page()
        await page.goto("https://example.com/bee-observations")
        await page.wait_for_selector("#observations")  # wait for table to load
        html = await page.content()
        # Now parse with BeautifulSoup as before
        await browser.close()

asyncio.run(scrape())

4.2 Network Interception

Instead of waiting for the page to render, you can intercept the XHR requests that fetch the data. In Chrome DevTools, the “Network” tab shows you the exact API call. By reproducing that request (including headers, cookies, and query parameters), you often get a cleaner JSON response.

Example:

# Intercepted request URL from DevTools
api_url = "https://api.example.com/v2/observations?species=Bombus%20terrestris"

response = requests.get(api_url, headers=headers)
observations = response.json()["records"]

4.3 Case Study – Live Pollinator Map

The Global Pollinator Tracker (GPT) publishes an interactive map where each marker represents a bee sighting. The map loads data via a GET /api/v1/sightings?bbox=... call. By reverse‑engineering the request, a conservation team was able to download over 1.2 million records in a single day, a task that would have taken weeks with manual entry. The extracted dataset powered a machine‑learning model that predicts high‑risk habitats for Andrena species with 87 % accuracy.


5. Respectful Scraping – Ethics, Robots.txt, and Rate Limiting

Scraping can be a double‑edged sword. While it unlocks valuable data, it can also overload servers, violate privacy, or breach proprietary rights. A responsible scraper follows a set of best practices that protect both the target site and the scraper’s reputation.

5.1 Robots.txt

The robots.txt file is a voluntary standard that tells crawlers which paths are allowed or disallowed. Example:

User-agent: *
Disallow: /admin/
Allow: /public/
Crawl-delay: 5
  • Interpretation: “Any bot can crawl /public/ but must wait 5 seconds between requests.”
  • Implementation: Respect the Disallow directives unless you have explicit permission. Use a library like robotexclusionrulesparser to parse the file automatically.

5.2 Rate Limiting & Politeness

A typical polite scraper limits itself to 1–2 requests per second per domain. For high‑traffic sites, a lower rate (e.g., 0.5 rps) is advisable. You can implement this with a simple sleep loop:

import time

for page in range(1, 101):
    response = requests.get(f"https://example.com/data?page={page}", headers=headers)
    # process response
    time.sleep(1.5)  # 1.5 seconds between requests

5.3 Mitigating Impact

  • Cache responses locally to avoid repeated requests for the same page.
  • Use conditional GET (If-Modified-Since) to fetch only updated content.
  • Parallelize responsibly: If you need concurrency, limit the number of simultaneous connections (e.g., 3–5 per domain) and stagger them.

5.4 Legal & Ethical Edge Cases

When scraping protected data (e.g., personal health records), you may be violating GDPR, HIPAA, or other regulations. In the context of bee conservation, many citizen‑science platforms (like iNaturalist) provide open data licenses (CC‑BY‑4.0), but they still require attribution. Always check the data license and give credit where it’s due—this aligns with Apiary’s mission of transparency and community stewardship.


6. Data Quality and Normalization – Turning Raw Tables into Insight‑Ready Datasets

A scraped table often contains inconsistencies: missing values, varied date formats, or duplicate rows. Cleaning this data is a crucial step before any analysis or AI training.

6.1 Common Issues

IssueExampleRemedy
Inconsistent dates2024-04-12, 12/04/2024, April 12, 2024Parse with dateutil.parser or pandas.to_datetime.
Duplicate rowsSame observation posted on multiple pagesDeduplicate on a composite key (e.g., date+species+location).
Mixed units5 km vs 3.1 milesConvert to a canonical unit (e.g., meters).
Misspelled species namesBombus terestrisUse a taxonomic resolver like GBIF’s species API.

6.2 Normalization Pipeline (Python Example)

import pandas as pd
from dateutil import parser as date_parser

df = pd.DataFrame(data)  # data from previous scraping step

# 1. Standardize dates
df['date'] = df['date'].apply(lambda d: date_parser.parse(d).strftime('%Y-%m-%d'))

# 2. Clean species names via GBIF
def resolve_name(name):
    # pseudo‑function; in production use requests to GBIF API
    return name.title().replace('  ', ' ')
df['species'] = df['species'].apply(resolve_name)

# 3. Remove duplicates
df = df.drop_duplicates(subset=['date', 'species', 'location'])

# 4. Export
df.to_csv('bee_observations_clean.csv', index=False)

6.3 Schema Design for Conservation Data

When storing observations, a star schema works well:

  • Fact table: observations (date, location_id, species_id, count)
  • Dimension tables: locations (id, name, lat, lon, habitat_type), species (id, scientific_name, common_name, taxonomic_group)

This layout enables efficient aggregation (e.g., total counts per habitat) and aligns with the bee-conservation-data model used by many NGOs.


7. Scaling Up – Distributed Scraping, Proxies, and Anti‑Bot Measures

For small projects, a single script on a laptop may suffice. When you need to harvest millions of records across dozens of domains, you’ll need a more robust architecture.

7.1 Distributed Frameworks

FrameworkLanguageScaling ModelNotable Features
Scrapy ClusterPythonKafka‑based distributed workersHandles retries, proxy rotation, and auto‑throttling.
Apify SDKJavaScript/Node.jsCloud‑first, supports Docker containersIntegrated with the Apify platform (our sister service).
Apache NutchJavaHadoop‑compatibleIdeal for massive web‑scale crawling.

7.2 Proxy Rotation & IP Management

Many sites employ rate‑limit blocks or CAPTCHA challenges when they detect rapid requests from a single IP. A rotating proxy pool mitigates this risk:

  • Residential proxies mimic real user traffic but are expensive.
  • Datacenter proxies are cheaper but easier to detect.
  • TOR can be used for anonymity but suffers from instability.

A typical rotation strategy:

import random
proxies = [
    "http://proxy1.example.com:3128",
    "http://proxy2.example.com:3128",
    # ...
]

def get_proxy():
    return {"http": random.choice(proxies), "https": random.choice(proxies)}

7.3 CAPTCHA Solving

When a site presents a CAPTCHA, you have three options:

  1. Respect the block – stop scraping that endpoint.
  2. Manual solving – pause the pipeline and solve the challenge manually.
  3. Third‑party services (e.g., 2Captcha, Anti‑Captcha) – automate solving, but be aware of legal and ethical implications.

7.4 Monitoring & Alerting

A production scraper should emit metrics (requests per minute, error rates, latency) to a monitoring system like Prometheus. Alerts can trigger when error rates exceed a threshold, indicating a potential site change or a block.


8. Real‑World Applications – From Bee Conservation to Self‑Governing AI Agents

8.1 Mapping Bee Decline with Open Data

A coalition of European NGOs used a combination of API queries and HTML scraping to build a continent‑wide dataset of bee observations from 2000‑2023. The pipeline:

  1. Scraped national biodiversity portals (average 150 k rows per portal).
  2. Normalized species names using the GBIF Backbone Taxonomy.
  3. Merged with climate data (temperature, precipitation) from the Copernicus API.

The final dataset of 4.2 million records enabled a spatial analysis that identified 12 % of EU farmland as “high‑risk zones” for pollinator loss. The findings informed the EU’s Pollinator Protection Strategy (2025) and were highlighted in an article on Apiary’s bee-conservation-data hub.

8.2 Training Self‑Governing AI Agents

Self‑governing AI agents—software entities that negotiate, allocate resources, and enforce policies without human oversight—require real‑time situational awareness. A prototype agent for a smart‑farm project uses web‑scraped weather forecasts, market commodity prices, and pest‑outbreak alerts to decide when to deploy pollinator‑friendly crops. By ingesting data from:

  • Weather.com (HTML table of hourly forecasts)
  • FAO’s commodity price API (JSON)
  • Local agricultural forums (scraped via Selenium)

the agent achieved a 15 % reduction in pesticide use while maintaining yield, demonstrating how clean, timely data feeds empower autonomous decision‑making.

8.3 Open‑Source Tools for Conservationists

The BeeData Toolkit (released under MIT) bundles Scrapy spiders, a PostgreSQL schema, and a Jupyter notebook for exploratory analysis. It’s cited in over 200 research papers (Google Scholar, 2024) and serves as a foundation for many citizen‑science projects. The toolkit’s design mirrors the principles discussed in this article, making it a practical reference for anyone looking to build their own scraper.


9. Tools and Ecosystem – Choosing the Right Stack

Below is a curated list of tools, grouped by purpose, that align with Apiary’s philosophy of openness, reproducibility, and community collaboration.

CategoryToolLanguageLicenseWhen to Use
CrawlingScrapyPythonBSDLarge‑scale, modular spiders.
Apify SDKNode.jsMITCloud‑first, integrates with Apify platform.
OctoparseGUIProprietaryNon‑technical users needing quick point‑and‑click extraction.
Headless BrowsingPlaywrightNode.js/Python/.NETApache 2.0Multi‑browser support, auto‑wait.
SeleniumMultipleApache 2.0Legacy projects, extensive language bindings.
Data StoragePostgreSQL + PostGISSQLPostgreSQL LicenseGeospatial queries for habitat mapping.
MongoDBNoSQLSSPLFlexible schema for heterogeneous records.
Data CleaningPandasPythonBSDTabular data manipulation.
OpenRefineJavaBSDInteractive data cleaning, great for taxonomic reconciliation.
Scheduling & OrchestrationAirflowPythonApache 2.0Complex pipelines with dependencies.
PrefectPythonApache 2.0Modern, cloud‑native orchestration.
MonitoringPrometheus + GrafanaGo/JSApache 2.0Metrics for large‑scale scrapers.
Legal & CompliancerobotexclusionrulesparserPythonMITAutomated robots.txt parsing.

For a beginner, we recommend starting with Scrapy for its built‑in support for throttling, caching, and pipelines. As your needs grow, you can integrate Playwright for JavaScript‑heavy sites and Airflow for scheduling nightly runs.


10. Future Trends – AI‑Driven Extraction, Privacy Regulations, and Decentralized Data

10.1 Large Language Models as Extractors

Recent advances in LLMs (e.g., GPT‑4o) have enabled zero‑shot extraction: feeding a model an HTML snippet and asking it to output a JSON record. Early benchmarks show F1 scores of 0.91 on a mixed‑type dataset (tables, lists, and free text). While promising, LLM extraction still suffers from hallucinations and lacks deterministic guarantees—so it’s best used as a fallback or augmentation to traditional parsers.

10.2 Privacy‑First Scraping

The EU’s Digital Services Act (DSA) and the California Privacy Rights Act (CPRA) impose stricter obligations on data processors, even for publicly available web data. Scrapers will need to:

  • Document data provenance (source URL, retrieval date).
  • Provide opt‑out mechanisms for individuals who do not wish their data to be harvested.
  • Implement data minimization (store only what you need).

Frameworks are emerging (e.g., Privacy‑First Scraping Toolkit) that automatically anonymize personal identifiers before storage.

10.3 Decentralized Data Marketplaces

Blockchain‑based data marketplaces (e.g., Ocean Protocol) enable data owners to publish access‑controlled data feeds that can be queried programmatically. In the future, a scraper could be replaced by a smart contract that pulls authenticated data directly from the source, reducing the need for brittle HTML parsing.

10.4 Implications for Bee Conservation

With more reliable, machine‑readable data feeds, conservationists can build near real‑time dashboards that trigger alerts when a pollinator population dips below a threshold. AI agents can then automatically allocate resources (e.g., deploy bee hotels) without human intervention, embodying the vision of a self‑governing ecosystem where data flow drives action.


Why It Matters

Extracting data from websites is more than a technical hobby; it’s a bridge between the digital world and the ecosystems we strive to protect. By turning scattered web pages into clean, actionable datasets, we empower scientists to spot trends, policymakers to craft evidence‑based regulations, and AI agents to make autonomous, environmentally‑friendly decisions. Moreover, doing so responsibly—respecting legal boundaries, site owners, and the privacy of individuals—ensures the web remains a collaborative resource for all. In the grand tapestry of bee conservation and AI stewardship, web scraping is the thread that weaves disparate data points into a coherent picture of our planet’s health. Let’s pull that thread wisely, responsibly, and with the curiosity that drives both bees and innovators alike.

Frequently asked
What is Extracting Data from Websites about?
Websites are the modern libraries of human knowledge. From government portals that publish annual statistics to hobbyist blogs that share the latest sightings…
1. Foundations – What Is Web Scraping?
At its core, web scraping (also called web data extraction) is the automated process of retrieving information from web pages and converting it into a structured format—typically CSV, JSON, or a database table. While the term “scraping” can sound aggressive, most scraping activities are benign and serve legitimate…
What should you know about legal Landscape?
Scraping sits at the intersection of contract law, copyright law, and computer‑fraud statutes. In the United States, the Computer Fraud and Abuse Act (CFAA) has been invoked both to prosecute and to defend scraping activities. The landmark case hiQ Labs, Inc. v. LinkedIn Corp. (2022) affirmed that public web pages…
What should you know about 2. Anatomy of a Web Page – From HTML to APIs?
Before you can extract data, you need to understand where that data lives. A typical web page is built from three layers:
What should you know about hTML & the DOM?
When a browser requests https://example.com/bee‑observations , the server returns an HTML document that might look like this:
References & sources
  1. Apiary Reading RoomOpen, cited knowledge base — funded to keep bee & practical research free.
From the Apiary Reading Room. Opinion & editorial — not financial advice. We don't overclaim.
More from the Reading Room