Zum Inhalt

So verwandeln Sie Web Scraper in Daten-APIs

Web Scraping ist eine leistungsstarke Technik zum Extrahieren großer Datenmengen von Websites. Das Scrapen von Daten bei Bedarf kann jedoch eine Herausforderung sein. In dieser umfassenden Anleitung erfahren Sie, wie Sie mithilfe von FastAPI einen Python-Web-Scraper in eine Echtzeit-Daten-API verwandeln.

Warum eine Scraping-API erstellen?

Hier sind einige wichtige Vorteile der Bereitstellung von Scraped-Daten über eine API:

  • Echtzeitdaten – APIs können Daten bei Bedarf extrahieren, anstatt sich auf veraltete, zwischengespeicherte Batches zu verlassen.

  • Benutzerdefinierte Abfragen – APIs ermöglichen die benutzerdefinierte Abfrage von Daten, anstatt nur ganze Websites zu sichern.

  • Skalierbarkeit – APIs bewältigen Verkehrsspitzen und können auf Tausende von Benutzern skaliert werden.

  • Zuverlässigkeit – APIs wiederholen fehlgeschlagene Anfragen und implementieren eine robuste Scraping-Logik.

  • Flexibilität – APIs können verschiedene Datenbereitstellungsmethoden wie Webhooks implementieren.

  • Abstraktion – APIs verbergen komplexe Scraping-Logik und Infrastruktur vor API-Konsumenten.

Scraping-API-Architektur

Auf einer hohen Ebene folgt eine Web-Scraping-API dieser Architektur:

Scraping-API-Architektur

  1. API empfängt Anfrage
  2. Scraper ruft Daten ab
  3. Daten werden zwischengespeichert
  4. API gibt Scraped-Daten zurück

Die Schlüsselkomponenten sind:

  • API-Server – Behandelt Kundenanfragen und liefert Scraped-Daten.

  • Schaber – Ruft Daten bei Bedarf von Zielstandorten ab.

  • Cache-Speicher – Speichert Scraping-Daten, um redundantes Scraping zu vermeiden.

  • Datenbase – Speichert optional Scraped-Daten für die historische Analyse.

Warum FastAPI verwenden?

Es gibt viele hervorragende API-Frameworks. Für Schaber empfehle ich FastAPI da:

  • FastAPI ist sehr schnell – perfekt für Data-Scraping-APIs.

  • Es bietet automatische Dokumente, Validierung, Serialisierung usw.

  • Unterstützt Asyncio für asynchrones Scraping.

  • Einfach zu bedienen und zu erlernen. Flexibel für kleine bis große APIs.

  • Verfügt über ein großartiges Ökosystem an Scraping-Tools wie httpx, Parsel usw.

Scraping-API-Setup

Wir werden die folgenden Kernbibliotheken verwenden:

  • FastAPI – Unser API-Framework

  • httpx – Asynchroner HTTP-Client

  • Paket – HTML/XML-Parser

  • loguru – Protokollierungsdienstprogramm

Installieren Sie die Pakete:

pip install fastapi uvicorn httpx parsel loguru

Für diesen Leitfaden extrahieren wir einige grundlegende Aktiendaten von Yahoo Finance.

Erstellen Sie die API

Lassen Sie uns die erste FastAPI-App mit einem einzigen Endpunkt einrichten:

from fastapi import FastAPI

app = FastAPI() 

@app.get("/stock/{symbol}")  
async def get_stock(symbol: str):
    return { "stock": symbol } 

Diese Basis-API gibt lediglich das von uns bereitgestellte Aktiensymbol zurück.

Starten wir den Server und testen ihn:

uvicorn main:app --reload
import httpx

print(httpx.get("http://localhost:8000/stock/AAPL").json())

# {‘stock‘: ‘AAPL‘}

Unsere API ist bereit, Anfragen zu empfangen. Lassen Sie uns als Nächstes einige Daten kratzen.

Scraping von Bestandsdaten

Um die Daten einer Aktie zu erhalten, gehen wir wie folgt vor:

  1. Erstellen Sie die Yahoo Finance-URL aus dem Symbol
  2. Rufen Sie die HTML-Seite ab
  3. Analysieren Sie Werte mit XPath
from parsel import Selector # for xpath parsing

async def scrape_stock(symbol: str):

    url = f"https://finance.yahoo.com/quote/{symbol}"

    async with httpx.AsyncClient() as client:
       response = await client.get(url)

    sel = Selector(response.text)

    # parse summary values 
    values = sel.xpath(‘//div[contains(@data-test,"summary-table")]//tr‘)
    data = {}
    for value in values:
        label = value.xpath("./td[1]/text()").get()
        val = value.xpath("./td[2]/text()").get()
        data[label] = val

    # parse price 
    data["price"] = sel.xpath(‘//fin-streamer[@data-symbol=$symbol]/@value‘, symbol=symbol).get()

    return data

Dieser Scraper gibt ein Wörterbuch zurück, das die analysierten Daten enthält. Verbinden wir es mit unserer API:

from fastapi import FastAPI
from yahoo_finance import scrape_stock

app = FastAPI()

@app.get("/stock/{symbol}")
async def get_stock(symbol: str):
    data = await scrape_stock(symbol) 
    return data

Wenn wir nun unsere API aufrufen, ruft sie die neuesten Daten ab:

http http://localhost:8000/stock/AAPL

HTTP/1.1 200 OK
Content-Length: 340

{
  "52 Week Range": "142.00 - 182.94",
  "Beta (5Y Monthly)": "1.25", 
  "Diluted EPS (ttm)": "6.05",
  "Earnings Date": "Oct 27, 2022",
  "Ex-Dividend Date": "Aug 05, 2022",
  "Forward Dividend & Yield": "0.92 (0.59%)",
  "Market Cap": "2.44T",
  "Open": "156.76",
  "PE Ratio (ttm)": "25.60",
  "Previous Close": "153.72",
  "Price": "155.33",  
  "Volume": "53,978,024"
}

Caching hinzufügen

Es ist verschwenderisch, bei jeder Anfrage zu scheitern. Fügen wir Caching hinzu, sodass wir nur alle 5 Minuten eine Brühe abkratzen.

Wir verwenden ein einfaches dict So speichern Sie die geschabten Daten verschlüsselt nach dem Aktiensymbol:

STOCK_CACHE = {} 

async def scrape_stock(symbol):

   if symbol in STOCK_CACHE:
       return STOCK_CACHE[symbol] 

   data = ... # scrape 
   STOCK_CACHE[symbol] = data

   return data

Jetzt werden bei wiederholten Anfragen zwischengespeicherte Daten zurückgegeben, anstatt sie jedes Mal zu extrahieren.

Wir können den alten Cache auch regelmäßig löschen:

import time

CACHE_MAX_AGE = 300 # seconds

async def clear_expired_cache():
   curr_time = time.time()
   for symbol, data in STOCK_CACHE.items():
       if curr_time - data["ts"] > CACHE_MAX_AGE:
           del STOCK_CACHE[symbol]

# run every 5 minutes   
clear_cache_task = asyncio.create_task(clear_expired_cache()) 

Dadurch wird sichergestellt, dass unser Cache nicht unbegrenzt wächst.

Webhooks hinzufügen

Für lange Scraping-Jobs können wir Webhooks verwenden, um Ergebnisse asynchron zurückzugeben:

@app.get("/stock/{symbol}")
async def get_stock(symbol: str, webhook: str):

   if webhook:
      task = asyncio.create_task(fetch_stock(symbol, webhook))
      return {"msg": "Fetching data"}

   data = await scrape_stock(symbol)  
   return data

async def fetch_stock(symbol, url):
   data = await scrape_stock(symbol)

   async with httpx.AsyncClient() as client:
      await client.post(url, json=data)

Anstatt nun auf den Abschluss des Scrapings zu warten, gibt unsere API sofort einen Status zurück und liefert die Daten asynchron an den Callback-Webhook.

Wir können dies mit einem Tool wie testen Webhook.site.

Skalierung der Scraping-API

Wenn der Datenverkehr zunimmt, gibt es hier einige Skalierungstechniken:

  • API-Caching hinzufügen – Verwenden Sie einen Cache wie Redis, um die Scraping-Last zu reduzieren.

  • Führen Sie mehrere Prozesse aus – Skalieren Sie mit Gunicorn über Kerne/Server hinweg.

  • Entladen Sie das Schaben – Verschieben Sie Scraper zu Arbeitern wie Celery oder RabbitMQ.

  • Nutzen Sie Scraping-Dienste – Nutzen Sie Scraping-APIs wie Scrapfly oder ScraperAPI.

  • Schaber optimieren – Stellen Sie sicher, dass Scraper effizient sind und vermeiden Sie Verbote.

  • Datenbanken hinzufügen – Speichern Sie Scraped-Daten zur weiteren Analyse in Datenbanken.

Zusammenfassung

In diesem Leitfaden haben wir mithilfe von FastAPI eine Web-Scraping-API in Python erstellt. Die wichtigsten Erkenntnisse sind:

  • FastAPI bietet ein hervorragendes Framework für das Scraping von APIs.

  • Wir können Scraper generieren, um Daten bei Bedarf abzurufen.

  • Caching und Webhooks helfen dabei, Scraping-Einschränkungen zu überwinden.

  • Es gibt viele Optimierungs- und Skalierungsstrategien, wenn der Datenverkehr wächst.

Scraping-APIs erschließen die Fülle an Daten auf Websites. Durch die Generierung von APIs anstelle von statischem Scraping können wir maßgeschneiderte Daten mit geringer Latenz in großem Maßstab bereitstellen.

Stichworte:

Mitreden

E-Mail-Adresse wird nicht veröffentlicht. Pflichtfelder sind MIT * gekennzeichnet. *