Caccia ai prezzi con shell e xmlstarlet

By abell on 2010-05-22-00:39:41 | In xmlstarlet shell e-commerce linux

Mettiamo che abbiate trovato un'offerta imperdibile in rete e che mentre state pagando vi venga mostrato un messaggio d'errore:
Il sistema non può elaborare il vostro ordine. Vi preghiamo di riprovare

Ripetete diligentemente i passi. Stesso risultato. Finché tornate all'elenco prodotti e scoprite che l'ultima frullocentrifuga 18 velocità con 4 braccia orbitali controrotanti ora è in vendita a 8000 euro. Evidentemente l'ultima in offerta è stata comprata da qualcuno prima che portaste a termine l'ordine.

Niente da dire: non sarebbe furbo da parte del sito di e-commerce riservarvi il prodotto solo perché l'avete nel carrello e vi viene assegnato solo quando portate a termine il pagamento. E' come per l'ultima bomba alla crema che avete adocchiato al bar: se un altro riesce a raggiungerla per prima è sua e rimanete a bocca asciutta. Al più potete ripiegare su un cornetto integrale (nota: episodio capitato di recente all'autore).

Ci sarà un'offerta del genere nel prossimo futuro? E se ci sarà, riusciremo a scoprirlo in tempo e non all'ultimo momento? Ah, se avessimo un assistente personale che controllasse i prezzi ogni 10 minuti e ci avvertisse se i prezzi si abbassano...

Un processo lanciato da cron con l'impostazione */10 (ogni 10 minuti) potrebbe fare al caso nostro.

Potremmo scrivere un programma in Java che instanzia un HttpClient impostato con un HttpResponseHandler che usa un HTMLParser che tramite un Connector...

NAAAAA....

Scomponiamo il problema in passi semplici per i quali possiamo usare componenti già pronti. Una proposta potrebbe essere:

La pagina con i prezzi si può visitare tranquillamente, quindi il primo passo è risolto in quattro e quattr'otto da un client http da riga di comando (wget o simili).

wget -O pricepage.html http://www.ammazzete.it/products/frullocentrifuga-18-velocita

Per l'estrazione dei prezzi, potremmo usare uno scriptino perl che usa un paio di espressioni regolari. Ancora troppo difficile. Basterebbe un filtro che estrae i div con classe price. xmlstarlet, che è una specie di grep/sed dopato per l'XML, farebbe al caso nostro.

Problema: la pagina con i prezzi non è XML valido. Dobbiamo introdurre un passo di normalizzazione del formato che lo trasformi in XHTML. Suona come qualcosa che qualcuno potrebbe avere già risolto, ed in effetti possiamo ad esempio usare tidy, con l'opzione -asxhtml.

Il passo che ci fa perdere più tempo è la ricerca dei parametri giusti per xmlstarlet. Badate che nel nome dei tag va specificato il namespace "http://www.w3.org/1999/xhtml". Dopo qualche esperimento, riusciamo a generare un file che contiene solo i prezzi.

wget -O pricepage.html http://www.ammazzete.it/products/frullocentrifuga-18-velocita
tidy -asxhtml -numeric pricepage.html > pricepage.xml
xmlstarlet sel -N x="http://www.w3.org/1999/xhtml" -t -m "//x:div[@class='price']" -v x:span pricepage.xml \
    > prices.new

E aggiungiamo un po' di logica per controllare se i prezzi sono cambiati e, nel caso, mandarci un'email:

if [ -f prices.old ] && ! diff -q prices.{old,new}; then
    ( echo "Nuovi:"; cat prices.new; echo; echo; echo "Vecchi:"; cat prices.old ) \
    | mail -s "Modifica prezzi" mioindirizzo@localhost
fi
mv prices.{new,old}

Uno script con un totale di 7 righe (le andate a capo con \ sono state inserite per chiarezza tipografica). E per vostra informazione, alla fine sono riuscito a comprare la frullocentrifuga al prezzo d'offerta.