перейти к содержанию

Как превратить веб-скребки в API данных

Веб-скрапинг — это мощный метод извлечения больших объемов данных с веб-сайтов. Однако сбор данных по требованию может оказаться сложной задачей. В этом подробном руководстве мы узнаем, как превратить веб-скребок Python в API данных в реальном времени с помощью FastAPI.

Зачем создавать API для парсинга?

Вот некоторые ключевые преимущества доставки очищенных данных через API:

  • Данные в режиме реального времени – API-интерфейсы могут собирать данные по требованию, а не полагаться на устаревшие кэшированные пакеты.

  • Пользовательские запросы – API позволяют настраивать запросы к данным, а не просто выгружать целые веб-сайты.

  • Масштабируемость – API справляются с всплесками трафика и масштабируются до тысяч пользователей.

  • Надежность – API повторяют неудачные запросы и реализуют надежную логику очистки.

  • Трансформируемость – API-интерфейсы могут реализовывать различные методы доставки данных, такие как веб-перехватчики.

  • абстракция – API скрывают сложную логику и инфраструктуру парсинга от потребителей API.

Парсинг архитектуры API

На высоком уровне API веб-скрапинга следует следующей архитектуре:

Парсинг архитектуры API

  1. API получает запрос
  2. Скребок извлекает данные
  3. Данные кэшируются
  4. API возвращает очищенные данные

Ключевые компоненты:

  • API-сервер – Обрабатывает запросы клиентов и доставляет очищенные данные.

  • Скребок – Извлекает данные по запросу с целевых сайтов.

  • Кэш – Сохраняет очищенные данные, чтобы избежать избыточного очистки.

  • База данных – Опционально сохраняет очищенные данные для исторического анализа.

Зачем использовать FastAPI?

Существует множество отличных API-фреймворков. Для скребков рекомендую FastAPI потому что:

  • FastAPI очень быстрый — идеально подходит для API очистки данных.

  • Он обеспечивает автоматическое документирование, проверку, сериализацию и т. д.

  • Поддерживает asyncio для асинхронного парсинга.

  • Простой в использовании и обучении. Гибкий для малых и больших API.

  • Имеет отличную экосистему инструментов парсинга, таких как httpx, parsel и т. д.

Настройка API парсинга

Мы будем использовать следующие основные библиотеки:

  • FastAPI – Наша платформа API

  • httpx – Асинхронный HTTP-клиент

  • посылка — Парсер HTML/XML

  • логуру — Утилита журналирования

Установите пакеты:

pip install fastapi uvicorn httpx parsel loguru

Для этого руководства мы возьмем некоторые основные данные об акциях из Yahoo Finance.

Создайте API

Давайте настроим исходное приложение FastAPI с одной конечной точкой:

from fastapi import FastAPI

app = FastAPI() 

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

Этот базовый API просто возвращает предоставленный нами символ акции.

Запустим сервер и протестируем его:

uvicorn main:app --reload
import httpx

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

# {‘stock‘: ‘AAPL‘}

Наш API готов принимать запросы. Далее давайте заставим его очистить некоторые данные.

Парсинг данных о запасах

Чтобы получить данные об акции, мы:

  1. Создайте URL-адрес Yahoo Finance из символа
  2. Получить HTML-страницу
  3. Анализ значений с использованием 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

Этот парсер возвращает словарь, содержащий проанализированные данные. Давайте подключим его к нашему 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

Теперь, когда мы вызываем наш API, он получает последние данные:

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"
}

Добавление кэширования

Скрапинг по каждому запросу — расточительство. Давайте добавим кеширование, чтобы очищать стоковые данные только раз в 5 минут.

Мы будем использовать простой dict для хранения очищенных данных, связанных с биржевым символом:

STOCK_CACHE = {} 

async def scrape_stock(symbol):

   if symbol in STOCK_CACHE:
       return STOCK_CACHE[symbol] 

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

   return data

Теперь повторные запросы будут возвращать кэшированные данные, а не каждый раз очищать их.

Мы также можем периодически очищать старый кеш:

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()) 

Это гарантирует, что наш кеш не будет неограниченно расти.

Добавление вебхуков

Для длительных заданий парсинга мы можем использовать вебхуки для асинхронного возврата результатов:

@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)

Теперь вместо ожидания завершения очистки наш API немедленно вернет статус и асинхронно доставит данные в вебхук обратного вызова.

Мы можем проверить это с помощью такого инструмента, как Вебхук.сайт.

Масштабирование API парсинга

По мере увеличения трафика вот несколько методов масштабирования:

  • Добавить кэширование API – Используйте кеш, такой как Redis, чтобы уменьшить нагрузку на очистку.

  • Запуск нескольких процессов – Масштабирование по ядрам/серверам с помощью Gunicorn.

  • Разгрузка очистки – Переместите скребки в рабочие процессы, такие как Celery или RabbitMQ.

  • Воспользуйтесь услугами парсинга – Используйте API-интерфейсы очистки, такие как Scrapfly или ScraperAPI.

  • Оптимизация парсеров – Обеспечьте эффективность парсеров и избегайте запретов.

  • Добавить базы данных – Храните собранные данные в базах данных для дальнейшего анализа.

Заключение

В этом руководстве мы создали API веб-скрапинга на Python с использованием FastAPI. Ключевые выводы:

  • FastAPI предоставляет отличную платформу для очистки API.

  • Мы можем создавать парсеры для получения данных по требованию.

  • Кэширование и веб-перехватчики помогают преодолеть ограничения очистки.

  • Существует множество стратегий оптимизации и масштабирования по мере роста трафика.

API-интерфейсы парсинга открывают множество данных на веб-сайтах. Создавая API вместо статического парсинга, мы можем предоставлять персонализированные данные с малой задержкой в ​​любом масштабе.

Теги:

Присоединяйтесь к беседе

Ваш электронный адрес не будет опубликован. Обязательные поля помечены * *