back to top

Il Web Scraping in PHP

Il Web Scraping è una tecnica di acquisizione dati da sorgenti esterne e consiste nell’acquisire, in maniera trasparente all’utente, un file (documento HTML, XML, TXT, ecc.) al fine di elaborarne il codice sorgente per le più disparate esigenze.

Ad esempio, quando visualizziamo una qualsiasi pagina web, sia essa statica o dinamica (basata, cioè, su un linguaggio di scripting come php, jsp o asp), il server chiamato restituisce un codice HTML che viene poi visualizzato dal browser. Il Web Scraping consente di acqusire, totalmente o in parte, questo codice di output ed inserirlo/utilizzarlo a proprio piacimento senza che l’utente finale capisca (o immagini) quale sia la sorgente di queste informazioni.

In realtà il Web Scraping è molto di più di questo poichè non consente solo l’acquisizione di codice HTML ma, come abbiamo detto nelle prime righe, anche XML, CSS, Javascript, ecc.

il Web Scraping, in sostanza, è una tecnica per acquisire contenuti web da altre fonti, esterne al nostro sito e dislocate anche su server differenti. E’ possibile, inoltre, acquisire anche contenuti derivanti da richieste GET e POST (con la specifica dei parametri richiesti).

Prima di addententrarmi nella descrizione delle tecniche e dei relativi processi ci tengo a precisare che acquisire dei dati in questo modo non è corretto in quanto non rispecchia la giusta etica del web secondo cui ognuno offre qualcosa per ragioni commerciali oppure, più semplicemente, per contribuire ad accrescere la libera conoscenza. Ci sono dei casi, tuttavia, in cui questa tecnica può risultare utile e in cui l’utilizzo può essere giustificato. In ogni caso è bene indicare che il contenuto proposto ha una specifica fonte (a cui si può far riferimento).

L’acquisizione dei dati mediante tecnica del Web Scraping può essere, per comodità, suddivisa in quattro fasi distinte:

  • Individuare la Risorsa da Acquisire
  • Acquisire la Risorsa
  • Manipolarla
  • Produrre un Risultato

Individuare la risorse consiste nel sapere quale file (pagina web o altro) si vuole prelevare. Acquisire la risorsa, come la parola suggerisce, consiste nell’acquirire il contenuto di interesse preparando opportunamente una request ed interrogando il datasource dove sono presenti i dati. La manipolazione consiste, invece, nell’elaborare i dati acquisiti eventualmente estraendo solo una parte di questi. Infine, produrre un risultato, significa, utilizzare il contenuto acquisito e manipolato per le nostre esigenze, eventualmente costituendo una nuova pagina/file che contiene il lavorato. Di seguito una immagine che sintetizzata quanto detto:

Per cercare di semplificare porrò un piccolo esempio: supponiamo di voler acquisire dalla home-page di Google la porzione di codice HTML relativa al box di ricerca ed il relativo bottone di Search per poi riportarlo in una nostra pagina web. La prima fase consiste nell’individuare la pagina di riferimento, cioè http://www.google.it; l’acquisizione consiste nel prelevare il codice di nostro interesse dalla pagina web di google.it; la manipolazione, invece, consiste nell’estrarre la porzione di codice desiderata; produrre un risultato, invece può consistere, semplicemente, nel riproporre il contenuto lavorato (il box ed il bottone di ricerca) oppure inserire lo stesso all’interno della nostra pagina web. Di seguito vedremo nel dettaglio ciascuna fase.

Individuazione e Acquisizione di Resource

<?php
$uri = 'http://www.google.it';

$get = file_get_contents($uri);

echo $get;
?>

Il codice sovrastante non fa altro che visualizzare la pagina di google, interamente. Questo poichè viene acquisito l’interno codice sorgente della pagina. In sostanza grazie ad una sola istruzione, file_get_contents(), possiamo acquisire e memorizzare in una variabile l’intero sorgente di una pagina web. A questo punto, quello che occorre è soltanto filtrare il contenuto della pagina per acquisire le sole informazioni di interesse.

Manipolazione e Produzione di un Risultato

Assumiamo che non vogliamo replicare il contenuto della pagina ma solto la parte relativa al form di ricerca keywords.

<?php
$uri = 'http://www.google.it';

$get = file_get_contents($uri);

$pos1 = strpos($get, "<form");   
//identifico la prima occorrenza di apertura del tag form

$pos2 = strpos($get, "</form>", $pos1); 
//identifico la prima occorrenza di chiusura del tag form a partire da pos1

$text = substr($get,$pos1,$pos2-$pos1+7); 
//estraggo il codice html ivi contenuto
//+7 per acquisire anche il tag </form>

echo $text; // visualizzo il codice html
?>

L’output del codice sovrastante non sarà altro che una porzione della pagina di google ovvero la form di ricerca.

E’ bene, però, fare attenzione. L’acquisizione di questi contenuti spesso non implica che questi siano immediatamente disponibili. Una porzione di codice HTML, ad esempio, può far riferimento ad uno script javascript, ad un’altra risorsa PHP o ad altro ancora. Affinchè sia possibile "clonare" le funzionalità sulla propria pagina web è necessario duplicare anche i contenuti a cui la pagina principale fa riferimento o, alternativamente, rimuovere il riferimento a quest’ultimi.

Esempio: supponiamo di aver duplicato parzialmente il contenuto della pagina http:\www.miodominio.itpagina1.htm. Poniamo, ancora, che questa pagina faccia riferimento, per lo svolgimento delle proprie funzioni, allo script "valida.js" posizionato nella root dello stesso dominio. In questa circostanza possiamo fare diverse cose:

  1. Eliminare il riferimento allo script (qualora questo sia superfluo o non dispensabile)
  2. Modificare il riferimento allo script in modo che venga linkato quello esterno (cioè quello "originale")
  3. Clonare, se possibile, sul proprio host anche lo script (nel caso di javascript è sufficiente fare il download dello script e poi l’upload sul proprio sito)

Quando detto, per siti di medio-bassa complessità è estremamente facile e banale. Il discorso cambia per siti complessi e/o articolati, in cui si fa riferimento ad una moltitudine di file, script ed immagini. In questo caso, pertanto, adattattare il contenuto acquisito alle proprie esigenze può risultare un pò più lento e tedioso.

Web Scraping: un esempio più complesso

Fino ad ora abbiamo visto come acquisire il codice di una web resource senza però poter comporre una specifica request. In realtà è possibile anche interrogare ed acquisire il contenuto derivato da elaborazioni (a seguito di una richiesta get o post) a script che operano lato server. Per semplicità consideriamo una semplice pagina di iscrizione ad una mailing-list:

<?php
//pagina di iscrizione ad una mailing-list

$myFile = "email.dat";
//file con gli indirizzi email

$fh = fopen($myFile, 'a') or die("Impossibile Accedere al File");
//apertura file in appending

$stringData = $_POST["mail"]."n";
//valore del parametro mail presente al'interno di un comune form 

if (fwrite($fh, $stringData) === FALSE)
  echo "Operazione Fallita";
else
  echo "Iscrizione di ".$_POST["mail"]." completata correttamente";

fclose($fh);
//chiudo il file

?>

Questo script viene lanciato, sul sito originario, mediante un semplice modulo:

<form method="pos" action="mailing-list.php">
Email: <input type="text" name="email" />
<input type="submit" value="Iscriviti"/>
</form>

Iniziamo dalle prime considerazioni: come avete notato questo script è stato realizzato per scopi puramente didattici ed infatti non prevede alcun tipo di controllo sul valore dell’input ricevuto, sul suo formato e sulla sua validità.

In aggiunta, ad aggravare la pericolosità dello script realizzato, è evidente che non esiste alcuna procedura di verifica quali captcha, ACL (Access Control List) o altro che impedisca l’esecuzione dello script stesso in circostanze "anomale".

Vediamo ora come sia possibile effettuare, in maniera invisible, queste richieste da remoto. Di seguito un codice PHP che effettua la richiesta mediante metodo post simulando, in sostanza, il submit del form:

<?php

$uri = 'http://sito.com/mailing-list.php';
// url di riferimento

$context = stream_context_create(array('http' => array(
  'method' => 'POST',
  'header' => 'Content-Type: application/x-www-form-urlencoded',
  'content' => http_build_query(array('mail' => 'test@test.com')))));
// imposto il method a post
// preparo content secondo lo standard: nomeparametro, valore
// è possibile inserire più parametri

$post = file_get_contents($uri, false, $context);
// effettuo la richiesta

echo $post;
?>

La nostra pagina PHP restituirà in output la risposta "catturata" dal server remoto:

Iscrizione di test@test.com completata correttamente

Come potete notare siamo riusciti ad interagire con uno script remoto senza invocarlo direttamente! Il tutto è avvenuto "dietro le quinte"!

I rischi del Web Scraping

Abbiamo visto nelle pagine precedenti in cosa consiste il Web Scraping e come metterlo in atto utilizzando PHP. Quello che non abbiamo detto che questa tecnica non è esente da rischi: includendo un file remoto, infatti, si corre anche il rischio di importare codici maligni e/o vulnerabilità in grado di compromettere la sicurezza e stabilità delle nostre web-application. Non è questa la sede dove approfondire l’argomento, ma è bene sapere fin da subito che molto spesso il Web Scraping è stato fonte di guai in quanto l’inclusione di file remoti comporta il rischio che questi siano stati appositamente alterati per creare danno. Per questo motivo molti hosting providers prefersicono impedire le chiamate a risorse remote, appunto al fine di evitare spiacevoli conseguenze.

Al fine di impedire il Web Scraping è sufficiente configurare opportunamente il file "php.ini" del php o il file ".htaccess" di Apache. Di seguito sono descritti entrambi gli approcci.

Se abilitato, allow_url_fopen consente alle funzioni PHP (come file_get_contents()) e agli statements come include e require di acquisire dati da endpoint remoti come altri siti web e/o indirizzi IP. Spesso questa direttiva, presente nel file php.ini, viene sottovalutata. La mancata disabilitazione della stessa e l’utilizzo delle funzioni citate nell’articolo nonchè una progettazione errata delle web application (dal punto di vista dell’input filtering) fa si che spesso si dia luogo a injection vulnerabilities. In tal senso, la maggior parte delle vulnerabilità riscontrate in PHP è proprio data dall’abilitazione della direttiva allow_url_fopen e da una cattiva progettazione delle input filtering rules. Per ovviare, parzialmente, al problema del WebScrapling è possibile agire direttamente sul file di configurazione php.ini disabilitando opportunamente la direttiva come segue:

; Disable allow_url_fopen for security reasons
allow_url_fopen = Off

Il metodo indicato sopra non è l’unico per impedire il WebScrapling. Nello specifico, oltre a disattivare la direttiva allow_url_fopen a livello globale, è possibile disattivarla a livello locale grazie ai file .htaccess di Apache:

php_value allow_url_fopen 0

Per ulteriori dettagli vi consiglio vivamente di consultare i seguenti link:

Si noti che impedire l’utilizzo di file_get_contents() può non essere sufficiente qualora sul server siano apresenti altre librerie, come ad esempio cURL, che svolgono funzioni analoghe.

Impedire che le nostre pagine siano vittime di Web Scraping

Impedire che i nostri contenuti vengano cannibalizzati da altri mediante la tecnica descritta è cosa piuttosto difficile. A tal fine è possibile intervenire sulla configurazione del nostro web server (oppure a livello di script) per impostare dei filtri che impediscano l’accesso a specifici IP o user-agent; in alternativa possiamo proteggere i nostri contenuti (soprattutto quelli di tipo "applicativo") facendo ricorso a rimedi, come il CAPTCHA, in grado di distinguere la visita compiuta da un essere umano piuttosto che da uno spider in cerca di rubare il frutto delle nostre fatiche.

Conclusioni

Dalle applicazioni e dagli esempi citati nell’articolo appare chiaro di come la tecnica del Web Scraping sia effettivamente molto potente ed utile ma altrettanto pericolosa. Un sitoportale mal progettato potrebbe subire gravissimi danni se non, addirittura, divenire inservibile se questa tecnica fosse usata in modo non adeguato. Vi invito, pertanto, ad utilizzare le informazioni contenute in quest’articolo con le dovute precauzioni e solo per finalità lecite.

Altri contenuti interessanti

Pubblicità

Leggi anche...

Cannot modify header information – headers already sent: come risolvere l’errore PHP

L'errore di PHP cannot modify header information - headers...

Ricavare l’estensione di un file con PHP

Quando si lavora con i file in un'applicazione web,...

GD Library: creazione, manipolazione e ridimensionamento immagini con PHP

Le librerie GD (o GD Library), sono componenti fondamentali...

PHP: impostare il fuso orario italiano

Le tue pagine PHP non mostrano l’orario corretto? Probabilmente...

5 script PHP per gestire BBCode

A volte può aversi l'esigenza di dover offrire agli...
Pubblicità