È buono avere una classe che memorizza solo i dati per l'astrazione?

1

Ho scritto un webscraper in Python che cattura i dati da ~ 10 diversi siti web (hanno confermato che questo è ok). La maggior parte dei siti web è un po 'diversa, ma l'idea generale di ottenere dati da ciascuno è la stessa:

  1. Carica l'URL del sito
  2. Premi ovunque i pulsanti da 0 a 3 (a seconda del sito).
  3. Inserisci una frase di ricerca specifica del sito.
  4. Acquisisci dati da qualsiasi risultato che contenga ancora un'altra frase specifica per il sito.
  5. Registra i dati in un file, specifico per il sito.

Ovviamente, la maggior parte di questo può essere sottratta, ma i passaggi 3 e 4 sono troppo diversi tra i siti per astrarre l'intero processo. Quindi c'è un raschietto astratto, esteso da un raschietto specifico per ogni sito che gestisce i passaggi 3 e 4.

Il mio problema è che ci sono molte informazioni specifiche del sito per tenerne traccia. Potrei inserire ogni configurazione specifica del sito nella sua classe, ma mi piacerebbe conservare tutto in un unico posto in modo da poter apportare modifiche di massa (scavando attraverso 10 classi per rendere lo stesso cambiamento terribile).

Quello che ho fatto è stato creare una classe che ho chiamato "ScraperData", che assomiglia a questo:

class ScraperData:

    scrapers = {
        "Website1": Website1Scraper(),
        "Website2": Website2Scraper(),
         ...
    }

    URLs = {
        "Website1": "www.website1.com",
        "Website2": "www.website2.com",
        ...
    }

    buttonsToPress = {
        "Website1": None,
        "Website2": ["Button1", "Button2"],
        ...
    }

    ....

So che potrei ottenere qualcosa di un po 'meno prolisso ristrutturando questo (potrei avere una classe di configurazione e inizializzarne una per ciascun sito qui), ma mi piace che questo approccio sia simile a tutti i dati.

Ho anche un file di configurazione che ha una riga:

Website1, Website2, Website5, ...

Dove scelgo i siti da cui ottenere i dati (non sempre vogliamo fare tutti e 10).

Infine, c'è una classe principale che carica i siti web dalla config in un array, sitesToScrape , e fa approssimativamente il seguente:

data = ScraperData()

for site in sitesToScrape:
    scraper = data.scrapers[site]

    scraper.load(data.URLs[site], data.buttonsToPress[site])
    scrapedData = scraper.scrape(data.searchStrings[site])

    self.write(site, data.files[site], scrapedData)

Ogni mattina scelgo solo i siti per prelevare i dati, avvia tutto, quindi lascialo in pace per alcune ore.

Per come la vedo io, questo rende molto facile collegare nuovi siti, eliminare quelli vecchi o modificare la configurazione di uno o più siti. Tuttavia, l'intero progetto sembra stranamente suddiviso in compartimenti, ma mi sembra che ogni compartimento abbia uno scopo specifico.

La mia domanda è: è un approccio facilmente manutenibile a questo problema? Le prestazioni non sono affatto un fattore.

    
posta Lord Farquaad 09.11.2017 - 16:07
fonte

1 risposta

2

Per quello che vale, ho fatto un sacco di lavoro esattamente come questo in un precedente lavoro. Dieci lezioni non mi piacciono molto.

Ci siamo occupati di centinaia di siti web. Originariamente, abbiamo archiviato i dati di configurazione per gli scrapers in un database, ma poiché lo sviluppatore originale non ha mai premuto il trigger su un'interfaccia utente di configurazione, la manutenzione è diventata un incubo. La classe base per i raschietti era di circa 1000 righe di codice e la compilazione delle informazioni di configurazione richiedeva centinaia di righe di script SQL per ciascun raschietto.

Alla fine, ho rifattorizzato spietatamente questo codice fino a quando ho potuto scrivere un raschietto in circa 30-100 linee di codice in un paio d'ore, e ho incorporato le informazioni di configurazione in ogni classe di raschietto, direttamente. In pratica, quello che stai per scoprire è che cambierai il codice e la configurazione per ogni raschietto allo stesso tempo, quindi è meglio da un punto di vista della manutenzione avere tutto nello stesso posto, poiché le informazioni di configurazione per qualsiasi raschietto dato non sarà mai usato altrove.

Abbiamo scoperto che i siti web sono abbastanza diversi l'uno dall'altro che il tentativo di trovare elementi comuni da inserire in una classe base o in un file di configurazione semplicemente non ne vale la pena. Invece, quello che vuoi nella tua classe base è un cookie robusto e la gestione dello stato di visualizzazione, e un semplice supporto per le operazioni HTTP GET e POST.

Detto questo, il nostro approccio generale a questo problema è stato piuttosto nuovo. Queste piccole classi di raschietto venivano eseguite in un ambiente Modello attore, in cui i flussi di lavoro potevano essere definiti e il codice del raschietto poteva essere sostituito a caldo.

Ma questo approccio è scalabile? È flessibile? È mantenibile? Bene, vediamo: sono stato in grado di scrivere 50 scrapers per 50 siti web diversi per un periodo di circa sei settimane (poco meno di due al giorno). Il modello di attore su cui sono stati pubblicati è in grado di essere scalato semplicemente aggiungendo server aggiuntivi e registrandoli con il server del database.

    
risposta data 09.11.2017 - 17:04
fonte

Leggi altre domande sui tag