Come fare Web Scraping con Puppeteer e Chrome Headless?

Hai necessità di controllare il funzionamento del tuo sito ...  o di recuperare regolarmente dei dati da internet... ma non sai come farlo... Ecco il web-scraping e come puoi farlo!




Cos'è e a cosa serve il web-scraping?

Inanzi tutto : non è niente di illegale. Si tratta soltanto di recuperare i dati ai quali chiunque puo accedere con un normale browser, ma farlo in modo automatico.

Per fare web-scraping ci sono tanti strumenti che automatizzano i gesti (Autohokey, autoit...) oppure il browser ( iMacros...) ma se desideri continuare ad utilizzare il tuo pc, devi utilizzare un browser "headless" cioè "senza visualizzazione". Anche qui avrai sentito parlare di Phamtonjs, Casperjs... ma dal 2017 Chrome integra in tutti browser il Chromiun headless.

Per questo tutorial e se non hai mai utilizzato javascript: ti consiglio d utilizzare Visual Studio Code cosi da avere il prompt di comandi e l'editore script sotto la stessa interfaccia

Scarica ed installa Visual Studio Code

Utilizziamo Puppeteer per Chrome Headless.


- Crea una cartella dove potrai installare tutti i file di dipendenze di node.js, puppeteer, npm...

Per es. C:/puppeteer

- Posizionati in questa cartella con il Prompt: scrivendo "cd puppeteer" dopo il prompt ($):

$ cd puppeteer

Seguirò poi il tutorial di Google Getting Started Puppeteer


- Installa Puppeteer:
$ npm i --save puppeteer
$ npm i npm    (aggiorna npm)
$ npm init                 (crea package.json, premere INVIO fino alla fine del menu...)
- Prova alcuni script di esempio da cui


Per esempio: salva in "hover.js" il seguente codice nella stessa cartella :


/**
* @name hover
*
* @desc The hover function is a combination of scrolling and putting the mouse into a hover state over the requested element.
* This example hovers the first track we find on the soundcloud.com homepage, which should trigger the play and like
* buttons to be visible
*
* @see {@link https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#pagehoverselector}
*/
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch()
const page = await browser.newPage()
await page.goto('https://soundcloud.com/')
await page.hover('.playableTile__artwork')
await page.screenshot({ path: 'hover.png' })
await browser.close()
})()



- Avvia lo script in linea di comandi scrivendo: ("node nomescript.js")

node hover.js

Si verrà a creare un file hover.png nella stessa cartella, con lo screenshot simile a quello che si potrebbe vedere con il browser aperteo:




Lo script dovrebbe aprire in modo "nascosto" il browser Chrome (headless appunto) e salvare uno screenshot di una pagina internet visitata.

A questo punto sei pronto per creare il proprio codice per questo puoi utilizzare un registratore come Daydream, oppure puoi utilizzare lo strumento di ispezione di google per copiare gli selettori:


Incolla poi il selector nel codice di esempio: cui con la funziona "click"

Per lanciare il browser in visualizzazione, disabilità headless, inserando {headless: false} nella funzione launch:


Una volta fatti tutti i test potrai lanciare lo script in modalità "headless" quindi senza l'anteprima del browser lanciando la parentesi vuota:
const browser = await puppeteer.launch()

Principali comandi e applicazioni di Puppeteer:


//aggiungere testo 
await page.focus('trix-editor') await page.keyboard.type('Just adding a title')

oppure tramite selector:

await page.type('#password', 'xxxx')

per evitare di scrivere 2 volte lo stesso testo in loop, fare un eval:

await page.$eval('#email', el => el.value = 'test@example.com');
//navigare 
await page.goto('https://www.paypal.com/signin')

//cambiare dimensioni schermo
await page.setViewport({width: 1500, height: 500});

//premere tasti (send key: in Unicode)

await page.type('#reply-form > label:nth-child(6) > div', '\u0009 \u000D');

//attende la comparsa del selettor per proseguire
await page.waitForSelector('img')

//attendere x secondi
await page.waitFor(2*1000);

//click del mouse

await page.mouse.click(132, 103, { button: 'left' })

//oppure con il selector:
await page.click('#myModal > div > div > div.modal-body > center > a.btn.btn-lg.btn-primary')


//definire variabili : per esempio per salvare i selettori
const USERNAME_SELECTOR = '#login_field';
const PASSWORD_SELECTOR = '#password';
const BUTTON_SELECTOR = '#login > form > div.auth-form-body.mt-3 > input.btn.btn-primary.btn-block';
//dopo di che' : inserire le credenziali nei selettori:
await page.click(USERNAME_SELECTOR);
await page.keyboard.type(CREDS.username);
await page.click(PASSWORD_SELECTOR);
await page.keyboard.type(CREDS.password);
await page.click(BUTTON_SELECTOR);
await page.waitForNavigation();

Effettuare web-scrapping

Ecco alcuni funzioni per colletare i dati, vedi esempio qui)

//fare uno screenshot (stampa schermo)

await page.screenshot({ path: 'hover.png' })

//definire i selettori e sostituire i lnumero di tag per INDEX per creare un LOOP

// const LIST_USERNAME_SELECTOR = '#user_search_results > div.user-list > div:nth-child(1) > div.d-flex > div > a';
const LIST_USERNAME_SELECTOR = '#user_search_results > div.user-list > div:nth-child(INDEX) > div.d-flex > div > a';
// const LIST_EMAIL_SELECTOR = '#user_search_results > div.user-list > div:nth-child(2) > div.d-flex > div > ul > li:nth-child(2) > a';
const LIST_EMAIL_SELECTOR = '#user_search_results > div.user-list > div:nth-child(INDEX) > div.d-flex > div > ul > li:nth-child(2) > a';

//creare il LOOP di estrazione

for (let i = 1; i <= listLength; i++) {
    // change the index to the next child
    let usernameSelector = LIST_USERNAME_SELECTOR.replace("INDEX", i);
    let emailSelector = LIST_EMAIL_SELECTOR.replace("INDEX", i);

    let username = await page.evaluate((sel) => {
        return document.querySelector(sel).getAttribute('href').replace('/', '');
      }, usernameSelector);

    let email = await page.evaluate((sel) => {
        let element = document.querySelector(sel);
        return element? element.innerHTML: null;
      }, emailSelector);

    // not all users have emails visible
    if (!email)
      continue;

    console.log(username, ' -> ', email);

    // TODO save this user
  }

//emulare un device (es. iphone):

const puppeteer = require('puppeteer');
const devices = require('puppeteer/DeviceDescriptors');
const iPhone = devices['iPhone 6'];

puppeteer.launch().then(async browser => {
  const page = await browser.newPage();
  await page.emulate(iPhone);
  await page.goto('https://www.google.com');
  await page.screenshot({ path: 'ggiphone.png' })

  await browser.close();
});
Risultato: può controllare l'aspetto su tanti device (ecco la lista):


Ritornare valori, messaggi ... alla console: esempi di funzione "Console.log":

browser.close();
return arrayJobResults;

//ritorna una serie di dati salvati in arrays:

console.log(username, ' -> ', email);

//salvare dati in un file (con File System)
var fs = require('fs');
fs.writeFile("/tmp/test", "Hey there!", function(err) {
    if(err) {
        return console.log(err);
    }

    console.log("The file was saved!");
}); 

//ritorna un messaggio al caricamento completo della pagina:


page.once('load', () => console.log('Page loaded!'));

// valutare la preseza o meno di un selector e , se non presente, saltare l'iterazione:


let finishtest = await page.evaluate((sel) => {
const urlend = document.querySelector(sel);
if (!urlend ) return null;
//await page.waitForSelector('#main > div.content.right-rail.srp > div.msg.success > h2');
await page.screenshot({ path: 'screen'+i+'.png' }) console.log('Inviato con successo!');
}, '#main > div.content.right-rail.srp > div.msg.success > h2');
if (!finishtest) continue;

//utilizzo di proxy:


(async() => {
const proxyUrl = 'http://proxy.example.com:8000';
const username = 'bob';
const password = 'password123';
const browser = await puppeteer.launch({
args: [`--proxy-server=${proxyUrl}`],
headless: false,
});
const page = await browser.newPage();
await page.authenticate({ username, password });
await page.goto('https://www.example.com');
await browser.close();
})();


Vedi anche Documentazione completa Puppeteer


Nessun commento:

Posta un commento

Comment atteindre la liberté financière

Cela ne signifie pas nécessairement être un "sale riche" La principale raison des problèmes financiers dans la vie est le...