Metodi hook
Questi metodi funzionano secondo il principio degli hook. L'implementazione di questi metodi consente di controllare il funzionamento dello scraper in diverse fasi, dall'inizializzazione alla distruzione dell'oggetto
L'implementazione di tutti i metodi eccetto parse è opzionale
async parse(set, results)
Il metodo parse implementa la logica principale di elaborazione della query e di ottenimento del risultato dello scraping; come argomenti vengono passati:
set- oggetto con informazioni sulla query:set.query- stringa di testo della queryset.lvl- livello della query, predefinito a0
results- oggetto con i risultati, che deve essere compilato e restituito dal metodoparse()- lo scraper deve verificare la presenza di ogni chiave nell'oggetto results e compilarla solo se presente, ottimizzando così la velocità e scrapando solo i dati utilizzati nella formazione del risultato
resultscontiene le chiavi delle variabili flat necessarie con valorenone, che per impostazione predefinita significa che il risultato non è stato ottenuto, così come le chiavi delle variabili-array (arrays) con valore sotto forma di array vuoto, pronto per essere compilatoresults.successdeve essere impostato su1in caso di elaborazione riuscita della query, il valore predefinito è0, il che significa che la query è stata elaborata con un errore
Vediamo un esempio:
class JS_HTML_Tags extends BaseParser {
static defaultConf = {
results: {
flat: [
['title', 'Title'],
],
arrays: {
h2: ['H2 Headers List', [
['header', 'Header'],
]],
}
},
...
};
async parse(set, results) {
// Otteniamo il contenuto della pagina HTML, il cui indirizzo è stato passato nella query
const {success, data, headers} = await this.request('GET', set.query);
// Verifichiamo il successo e il tipo di data; con una corretta elaborazione delle pagine HTML dovremmo ricevere il tipo 'string', altrimenti A-Parser restituisce un oggetto di tipo Buffer
if (success && typeof data == 'string') {
let matches;
// Verifichiamo la necessità di raccogliere il title e salviamo il valore
if (results.title && matches = data.match(/<title[^>]*>(.*?)<\/title>/))
results.title = matches[1];
// Verifichiamo la necessità di raccogliere h2
if (results.h2) {
let count = 0;
const re = /<h2[^>]*>(.*?)<\/h2>/g;
while(matches = re.exec(data)) {
// Salviamo in un ciclo tutti i tag h2 trovati
results.h2.push(matches[1]);
}
}
// Notifichiamo il successo dello scraping
results.success = 1;
}
// Restituiamo i risultati elaborati
return results;
}
};
Si noti che è possibile creare le proprie funzioni e metodi per una migliore organizzazione del codice:
function Answer() {
return 42;
}
class JS_HTML_Tags extends BaseParser {
...
async parse(set, results) {
results = await this.doWork(set, results);
return results;
}
async doWork(set, results) {
results.answer = Answer();
return results;
}
};
async processConf?(conf)
Questo metodo viene utilizzato per trasformare la configurazione secondo determinate regole, ad esempio quando si utilizza un captcha è sempre necessario utilizzare le sessioni:
async processConf(conf) {
if (conf.useCaptcha)
conf.useSessions = 1
}
async parse(set, results) {
if (conf.useSessions)
await this.login();
}
L'esistenza di questo metodo è dovuta al fatto che A-Parser supporta campi di configurazione dinamici e, nell'ambito di un singolo task, la configurazione può avere valori diversi; tale scenario è possibile in due casi:
- Utilizzo di modelli nei campi di configurazione, ad esempio
[% tools.ua.random() %]per il campo User-Agent - Utilizzo di
overridesquando si chiama uno scraper da un altro perthis.parser.request
Il metodo processConf viene chiamato una sola volta prima di init(). Per i casi sopra descritti, processConf viene chiamato ulteriormente prima dell'elaborazione di ogni query
Regole principali per l'applicazione di processConf:
- Utilizzarlo solo se le trasformazioni della configurazione hanno un effetto sulle prestazioni
- Tenere presente che
initviene eseguito una volta, mentreprocessConfpuò essere eseguito per ogni query; in questo caso la logica potrebbe essere compromessa seinitdipende da campi di configurazione variabili (vedi sotto)
async init?()
Il metodo init viene chiamato una volta all'inizializzazione dell'oggetto base dello scraper, serve per eseguire azioni una tantum:
- Avvio del browser
- Inizializzazione del gestore delle sessioni tramite il metodo
this.sessionManager.init() - Connessione al database e creazione di tabelle nel DB
- Lettura di dati statici
- Ecc.
Poiché il metodo viene chiamato una sola volta, tutti i campi di configurazione da cui dipende init() non possono essere utilizzati insieme ai modelli dei campi di configurazione o con overrides durante la chiamata a this.parsers.request
async destroy?()
Il metodo destroy viene chiamato una volta al termine del task, è necessario per la corretta distruzione delle risorse aperte:
- Chiusura del browser
- Chiusura della connessione al DB
- Ecc.
async threadInit?()
Questo metodo viene avviato all'inizializzazione di ogni thread; ogni thread è una copia dell'oggetto base dello scraper con il proprio this.threadId unico, che inizia da 0 e finisce a threads_count - 1
Principali varianti di applicazione:
- creazione di una pagina (scheda) del browser per ogni thread
async threadDestroy?()
Viene eseguito al termine del thread durante il processo di completamento del task, serve per liberare le risorse allocate per quel thread
async afterResultsProcessor?(results)
Questo metodo viene eseguito dopo l'elaborazione dei risultati: costruttore dei risultati, filtraggio e deduplicazione. Il caso d'uso principale è l'aggiunta di query alla coda utilizzando il metodo this.query.add dopo l'applicazione dei filtri personalizzati; in questo modo è implementato il filtraggio dei link da seguire (followlinks) per lo scraper
HTML::LinkExtractor