Salta al contenuto

Come raschiare la ricerca in Algolia

Ecco un post sul blog di oltre 2000 parole su "Come raschiare la ricerca in Algolia":

Introduzione

Algolia è una popolare API di ricerca che alimenta la funzionalità di ricerca per molti siti Web su Internet. Consente ai siti Web di implementare una ricerca rapida e pertinente senza la necessità di eseguire autonomamente infrastrutture di ricerca complesse.

Alcuni esempi di siti Web popolari che utilizzano l'Algolia includono:

  • Reddit
  • Medio
  • GitHub
  • StackOverflow
  • HackerNews

Lo scopo di questo post è spiegare:

  1. Cos'è l'Algolia e come funziona
  2. Come ottenere i risultati della ricerca in Algolia utilizzando Python
  3. Tecniche per raschiare l'Algolia in modo efficiente su larga scala
  4. Come evitare di rimanere bloccati durante la raschiatura dell'Algolia

Alla fine, capirai come creare uno scraper web Algolia scalabile per qualsiasi sito Web che lo utilizza.

Cos'è l'Algolia?

Algolia è un'API di ricerca ospitata che fornisce servizi come indicizzazione, ricerca e consigli. Viene spesso definito provider SaaS (Search-as-a-Service).

Le proposte di valore chiave dell’Algolia includono:

  • Ricerca veloce – L’Algolia afferma di essere in grado di cercare oltre miliardi di record in meno di 100 ms. Questo è ordini di grandezza più veloce rispetto alla ricerca sulla propria infrastruttura.

  • Ricerca pertinente – Algolia gestisce aspetti come la tolleranza agli errori di battitura, i sinonimi e l'apprendimento in base al comportamento dell'utente per restituire i risultati più pertinenti.

  • Servizio ospitato – L’Algolia si occupa di cose come il ridimensionamento e la ridondanza. Non c'è alcuna infrastruttura da gestire.

  • Accesso API – È possibile accedere alla funzionalità di ricerca tramite API che consente una facile integrazione in siti Web, app mobili, ecc.

Algolia fornisce librerie client per la maggior parte dei principali linguaggi e framework che gestiscono la comunicazione API. Sul front-end, gli sviluppatori aggiungono il codice JavaScript per interfacciarsi con l'API dell'Algolia.

Quindi, in sintesi, Algolia fornisce una ricerca ospitata e scalabile tramite API. Ciò consente ai siti Web di creare rapidamente un'ottima ricerca senza dover costruire essi stessi sistemi complessi.

Raschiare la ricerca Algolia con Python

Ora che abbiamo capito cos'è l'Algolia, vediamo come possiamo ottenere i risultati della ricerca dell'Algolia usando Python.

Lo scraping dell'Algolia è semplice poiché l'API è pubblica e documentata. Dobbiamo semplicemente:

  1. Identificare l'endpoint e i parametri dell'API
  2. Estrarre eventuali chiavi di accesso
  3. Invia richieste di ricerca e analizza la risposta JSON

Esaminiamo un esempio completo di scraping di un sito Web basato sull'Algolia.

Trovare l'endpoint API

Innanzitutto, dobbiamo trovare l'endpoint API utilizzato dal sito Web per la ricerca. Il modo più semplice è aprire il sito nel browser, eseguire una query di ricerca e controllare le richieste di rete negli strumenti per sviluppatori.

Ad esempio, il HackerNews vediamo una richiesta fatta a:

https://hn.algolia.com/api/v1/search?query=python

I /api/v1/search path rivela che questa è l'API di ricerca dell'Algolia. Vediamo anche il termine di ricerca python passato come parametro di query.

Controllando la risposta, possiamo vedere che restituisce JSON con i risultati. Ora conosciamo l'endpoint API e il parametro di ricerca da utilizzare.

Ottenere le chiavi API

Successivamente, dobbiamo ottenere la chiave API necessaria per l'autenticazione. Controllando nuovamente la richiesta di rete, possiamo vederla passata tramite il file X-Algolia-API-Key intestazione.

Possiamo estrarre questa chiave API e aggiungerla alle nostre richieste. Potrebbe essere necessario un ulteriore reverse engineering se la chiave è offuscata in JavaScript.

Effettuare richieste di ricerca

Con l'endpoint e la chiave API, ora possiamo effettuare richieste di ricerca in Python:

import requests 

api_key = "abc123" # Extracted key 

search_url = "https://hn.algolia.com/api/v1/search"

params = {
  ‘query‘: ‘python‘,
  ‘hitsPerPage‘: 100, 
  ‘attributesToSnippet‘: [‘title:10‘]
}

headers = {
  "X-Algolia-API-Key": api_key
}

response = requests.get(search_url, params=params, headers=headers)
data = response.json()

print(data[‘hits‘])

Effettuiamo una richiesta GET all'endpoint API passando il nostro termine di ricerca, i risultati per pagina e l'intestazione della chiave API. Il risultato contiene i risultati della ricerca come JSON che possiamo analizzare ed elaborare secondo necessità.

E ora abbiamo un raschietto Algolia di base!

Raschiare pagine aggiuntive

Una limitazione è che l'API restituisce solo la prima pagina dei risultati. Per ottenere pagine aggiuntive, dobbiamo passare il file page parametro incrementale da 0:

# First page
params[‘page‘] = 0 

# Second page
params[‘page‘] = 1 

# Third page
params[‘page‘] = 2

Per raschiare tutte le pagine, possiamo ripetere l'esecuzione delle richieste incrementando il numero di pagina finché non vengono restituiti più risultati.

Mettendo insieme questo:

from typing import Iterator

def scrape_search(search_term: str) -> Iterator[dict]:

  params = {
    ‘query‘: search_term,
    ‘hitsPerPage‘: 100,
  }

  page = 0
  while True:
    params[‘page‘] = page
    resp = requests.get(search_url, params=params, headers=headers)
    data = resp.json()

    if not data[‘hits‘]:
      break

    yield from data[‘hits‘]

    page += 1

Questo scorre sulle pagine e produce tutti i risultati.

Per raccogliere tutti i risultati:

results = []

for result in scrape_search("python"):
  results.append(result)

print(len(results))

E ora disponiamo di un impaginatore completo per raccogliere tutti i risultati di ricerca dell'Algolia!

Raschiare l'Algolia su larga scala

Il raschietto di base sopra funziona ma non è ottimizzato per il raschiamento su larga scala. Problemi che potresti riscontrare:

  • Rallentare – Le richieste sincrone rallentano il recupero di centinaia di pagine.
  • Fragile – Un guasto interrompe l’intero processo di scraping.
  • Banned – Lo scraping da un IP rischia di essere bloccato.

Diamo un'occhiata a come affrontare questi problemi per un efficace raschiamento su larga scala.

Richieste asincrone

Per velocizzare lo scraping possiamo sfruttare le richieste asincrone. Questo ci permette di avere molte richieste in volo contemporaneamente.

Ad esempio con il asyncio modulo:

import asyncio

async def fetch_page(page):
  params[‘page‘] = page
  resp = await asyncio.to_thread(requests.get, search_url, params=params) 
  return resp.json()

async def async_scrape():
  page = 0 
  while True:
    tasks = [asyncio.create_task(fetch_page(page + i)) for i in range(10)]
    results = await asyncio.gather(*tasks)

    for data in results:
      if not data[‘hits‘]:
        return

      for hit in data[‘hits‘]:
        yield hit

    page += 10

pages = async_scrape()  

Ciò recupera 10 pagine contemporaneamente su ogni iterazione. Con le richieste asincrone lo scraper è molto più veloce.

Nuovi tentativi e tolleranza agli errori

Le richieste di rete sono soggette a errori intermittenti. Possiamo aggiungere tentativi per gestire gli errori con garbo:

from time import sleep

async def fetch_page(page):

  for retry in range(3):

    try:
      return await asyncio.to_thread(requests.get, search_url, params=params) 
    except Exception as e:
      print(f"Error: {e}, retrying")
      sleep(1)

  print(f"Failed to fetch page {page} after {retries} retries")
  return {‘hits‘: []} # Return empty result

Questo semplicemente riprova fino a 3 volte in caso di errore. Potrebbero essere aggiunti anche altri miglioramenti come il backoff esponenziale.

Per una maggiore resilienza, possiamo racchiudere il ciclo complessivo di scraping in un tentativo/eccetto e riprovare in caso di arresti anomali imprevisti.

Con tentativi a più livelli, il raschiatore può riprendersi da vari guasti e continuare a funzionare.

Proxy rotanti

Lo scraping eccessivo di un singolo IP rischia di essere bloccato. Per evitare ciò, possiamo instradare le richieste attraverso diversi proxy utilizzando moduli come requests-proxy-killer:

from proxy_killer import KillerScraper

scraper = KillerScraper(use_cache=False, max_retries=3)

async def fetch_page(page):

  for retry in range(3): 
    try:
      proxy = scraper.get_proxy() # Rotate proxy
      resp = scraper.get(search_url, proxies=proxy, params=params)
      return resp.json()
    except Exception as e:
      print(f"Error: {e}, retrying")
      sleep(1)

# Remainder same as above

Instradando ciascuna richiesta attraverso un IP proxy diverso, possiamo eseguire operazioni su vasta scala senza preoccuparci dei blocchi.

I passaggi precedenti ci consentono di creare uno scraper Algolia robusto, ad alte prestazioni e su larga scala in Python. Gli stessi principi si applicano a qualsiasi lingua.

Evitare i blocchi durante la raschiatura dell'Algolia

L’ultima questione da affrontare è evitare blocchi dal servizio stesso dell’Algolia. Se effettui troppe richieste aggressive, Algolia potrebbe bloccare il tuo IP o limitare le richieste.

Ecco alcuni suggerimenti per raschiare educatamente e ridurre al minimo i blocchi:

  • Tasso limite: non sovraccaricare l'API con centinaia di richieste simultanee. Inizia in piccolo e aumenta gradualmente.

  • Usa i proxy: Ruota diversi IP per distribuire il carico ed evitare richieste concentrate.

  • Randomizza gli user-agent: varia l'intestazione dell'agente utente tra le richieste.

  • Segui robots.txt: assicurati che il tuo scraper rispetti le regole del file robots.txt.

  • Utilizza la logica dei tentativi: Backoff esponenziale se la tua tariffa viene limitata o bloccata.

  • Raschiare durante i periodi di basso traffico: scegli come target le notti dei giorni feriali quando il carico è inferiore.

  • Monitorare attentamente: controlla l'aumento degli errori o delle limitazioni.

Con la dovuta cura, è possibile costruire raschiatori Algolia sostenibili e di lunga durata. Ma assicurati di monitorare attentamente e adattare il tuo approccio nel tempo.

Scraping delle librerie di supporto

Gestire manualmente tutta la complessità della scalabilità e della resilienza può essere complicato. Esistono vari strumenti commerciali per semplificare il web scraping.

Per esempio:

Questi strumenti semplificano la creazione di scraper robusti senza dover codificare da soli una logica complessa. Vedi la mia guida su come e quando utilizzare un'API di scraping.

Avvolgere Up

Ecco i punti chiave da asporto:

  • Algolia fornisce la ricerca ospitata tramite API per una facile integrazione nei siti.
  • L'API di ricerca è pubblica e può essere recuperata estraendo l'endpoint e le chiavi.
  • Lo scraping su larga scala richiede richieste asincrone e rotazione dei proxy.
  • Monitorare attentamente e raschiare educatamente per evitare blocchi.
  • I servizi di raschiatura commerciale possono semplificare i lavori di raschiatura di grandi dimensioni.

Spero che questo post fornisca una buona panoramica su come raschiare in modo efficace l'API di ricerca Algolia su larga scala con Python. Gli stessi principi valgono anche per le altre lingue.

Fatemi sapere se avete altre domande!

Tag:

Partecipa alla conversazione

L'indirizzo email non verrà pubblicato. I campi obbligatori sono contrassegnati con *