Primi esperimenti 2D con Python

Sto approfittando di queste giornate di riposo e vacanza (più legata agli acciacchi che al periodo di fine anno) per mettere mano a Python.

Al di là della sua indubbia utilità come linguaggio di scripting per piccoli e veloci attività da automatizzare, la vera ragione che mi ha spinto a smanettarci in modo più serio è il desiderio di riprogrammare alcuni piccoli giocattoli grafici che avevo creato tanto tempo fa su altri sistemi operativi e con altri linguaggi.

L’articolo continua, leggi il resto… »

Whatsup 0.3: le query degli utenti in mappa mentale

La versione 0.3 di Whatsup permette di esportare automaticamente i dati in formato Freemind. Se non sapete che cosa è Whatsup, allora vi invito a dare un’occhiata agli articoli dedicati a Whatsup.

Forse il risultato visuale non sarà figo come quello ottenibile esportando i dati in formato XMind, tuttavia ho scelto il formato Freemind per le seguenti buone ragioni:

  • E’ più facile da creare, perché si tratta di un semplice ed essenziale file XML. Il formato XMind è invece più complesso, in quanto un file è in realtà un archivio zip contenente directory, thumbnail e più di un file XML.
  • Per Freemind esiste un applet Java che consente di mostrare via browser una mappa in tale formato. In questo modo sarà possibile mostrare la mappa delle query degli utenti direttamente sul pannello di controllo di Whatsup.
  • E’ un formato importabile in XMind, se proprio si desidera conferire figosità estetica alla mappa creata.

Per mostrarvi il risultato finale, segue una mappa delle query estratte ieri, sia in formato Freemind che in formato XMind. Le keyphrase in neretto sono quelle considerate più “hot” nel momento dell’estrazione.

E a proposito di questo stramaledetto neretto, sappiate che è ciò che ha fatto slittare di molto la presentazione di Whatsup 0.3, pronto da tempo ma fino a ieri privo di un sistema di assegnazione di attributi alle keyphrase, che adesso invece c’è.

Formato Freemind

Mappa mentale in formato Freemind

Importazione in XMind

Il file Freemind importato in XMind

Brute-force verso Google e codice PHP per le disposizioni

Nel precedente articolo sui servizi nascosti o segreti di Google, Fabio Schenone aveva chiesto nei commenti quando avrei svolto un attacco brute-force.

Ho accolto il suggerimento di Fabio ed ho cercato URL di Google nella seguente forma, assegnando al parametro “tbm” tutte le possibili stringhe di tre o di quattro caratteri basate sull’alfabeto inglese:

http://www.google.com/search?q=test&hl=en&prmd=ivnsfd&source=lnms&tbm=XXXX&sa=X&oi=mode_link&ct=mode&cd=4

(per maggiori informazioni sull’URL sopra indicato vi invito a leggere le spiegazioni nel post precedente)

Quantità delle interrogazioni

Disposizioni con ripetizione (permutations)
Le possibili stringhe di testo lunghe tre caratteri, ciascuno dei quali può essere uno qualunque dei simboli dell’alfabeto inglese sono esattamente 17576 (26^3).

Le possibili stringhe di testo lunghe quattro caratteri, ciascuno dei quali può essere uno qualunque dei simboli dell’alfabeto inglese sono esattamente 456976 (26^4).

In totale ho dunque fatto 474552 interrogazioni, che non sono servite ad un fico secco perché non ho scoperto ulteriori servizi nascosti. Gli unici individuati rimangono dunque quelli osservati e pubblicati nel post precedente.

Codice PHP per le disposizioni

Oltre a disporre di una batteria di Xenu, per produrre tutte le stringhe/URL da interrogare ho sviluppato una semplice funzione PHP che produce l’elenco di disposizioni (con ripetizione) ottenibili. Non ho idea se mai mi servirà ancora in futuro, quindi ve la fornisco nella speranza che possa un giorno essere utile a qualcuno di voi.

Per esempio, chiamando la funzione con i seguenti parametri: permutations(“ab”, 3); si ottiene in output un array contenente le stringhe: aaa, aab, aba, abb, baa, bab, bba, bbb.

  /**
   * Permutations
   *
   * Returns an array of strings containing all the
   * ($alphabet ^ $output_length) permutations
   *
   * @alphabet (string|array) set of at least two elements to choose from
   * @output_length (int) the number of elements in each output string
   */
  function permutations ($alphabet, $output_length=1) {

    $output = array();

    if ($alphabet AND ($output_length > 0)) {

      // Handles both string alphabets and array alphabets
      if (is_string ($alphabet)) {
        $alphabet_length = strlen ($alphabet);
        $symbol = str_split ($alphabet);
      } elseif (is_array ($alphabet)) {
        $alphabet_length = count ($alphabet);
        $symbol = $alphabet;
      } else {
        return $output;
      }

      if ($alphabet_length < 2) return $output;


      // Creates a -1 index in order to avoid the out-of-bounds
      // warning during the last loop of the do-while structure
      $pointer = array_fill (-1, $output_length+1, 0);
      
      // How much iterations to perform
      $iterations = pow ($alphabet_length, $output_length);
  
      // To avoid all the "- 1"...
      $alphabet_length--;
      $output_length--;
  
      // Do the job
      for ($i=0; $i < $iterations; $i++) {
        $permutation = "";
        for ($c = 0; $c <= $output_length; $c++) {
          $permutation .= $symbol[$pointer[$c]];
        }
        $output[] = $permutation;
  
  
        // Updates the pointers
        $c = $output_length;
  
        do {
          $pointer[$c]++;
          if ($pointer[$c] <= $alphabet_length) {
            break;
          } else {
            $pointer[$c] = 0;
            $c--;
          }
        } while (TRUE);
      }
    }
    
    return $output;
  }

Whatsup 0.3: gestione dei datacenter e fermento sul web

Nel precedente post dedicato a Whatsup avevo accennato alla versione 0.3, che tra le altre cose introduce la produzione automatica delle mappe mentali.

Prima di affrontare l’esportazione dei cluster in formato FreeMind, però, penso che sia opportuno dare piorità ad un aspetto più critico e che durante la sua gestione mi ha permesso di sviluppare una nuova idea sul genere di informazioni che Whatsup potrebbe fornire.

La gestione dei datacenter

Datacenter di GoogleOgni software di ranking, nell’interrogare Google o qualsiasi altro motore di ricerca, si pone come obiettivo quello di acquisire informazioni sulla posizione dei siti, che vengono solitamente comparate con quelle acquisite precedentemente per comprendere se la visibilità dei siti migliora o peggiora nel tempo.

In linea teorica, converebbe interrogare sempre uno stesso datacenter, per essere certi che le informazioni acquisite sulle posizioni non siano sporcate dal tipico fenomeno di disallineamento dei dati che i datacenter solitamente mostrano. Nella pratica esistono ragioni per evitare l’interrogazione di un solo datacenter, ma in teoria la maggiore consistenza dei dati si otterrebbe evitando di interrogare datacenter diversi.

L’acquisizione di dati fatta da Whatsup si pone però obiettivi diversi da quelli che si pongono i software di ranking. L’interrogazione di un solo datacenter, infatti, non consentirebbe di acquisire tutte le ricerche “hot” del momento ma solo le ricerche hot conosciute dal datacenter interrogato. A causa del disallineamento dei dati, datacenter diversi possono ospitare ricerche leggermente diverse.

Che cosa conviene fare a Whatsup? Conviene porsi come obiettivo la completezza delle informazioni e acquisire tutte le ricerche facendo richieste multiple a datacenter diversi.

Interrogare più datacenter implica che si acquisiranno sia ricerche appena introdotte da Google nella categoria delle ricerche del momento, sia ricerche ormai meno attuali ma che rimangono ancora per un po’ di tempo nei datacenter aggiornati per ultimi. Questa non è una reale criticità, tuttavia, perché la frequenza di aggiornamento dei datacenter è così alta che anche le ricerche “vecchie” hanno vita breve e scompaiono da tutti i datacenter abbastanza velocemente, dietro la spinta delle query più nuove.

Datacenter non vuol dire IP

Molti SEO credono che un datacenter di Google venga identificato da uno specifico indirizzo IP o, per essere più precisi, che vi sia una corrispondenza biunivoca tra un datacenter e un indirizzo IP. Almeno relativamente ai servizi di Google che interrogo per estrarre le ricerche hot, questa convinzione pare essere errata.

Anche interrogando Google allo stesso indirizzo IP, l’insieme di query restituito può variare da utente a utente, che in termini di protocollo si traduce in “da connessione a connessione”. Quindi magari ad un IP corrisponderà pure una specifica struttura tecnologica, però sicuramente non corrisponde un unico centro di dati o archivio.

Per questa ragione, piuttosto che fare interrogazioni a IP diversi, Whatsup mantiene inalterato l’IP interrogato e fa di tutto per presentarsi sotto spoglie diverse cambiando user-agent, cookie e ovviamente aprendo ogni volta una nuova connessione HTTP. La quantità di richieste è modesta e non c’è rischio di incorrere in contromisure anti-flood di Google.

Diversi test testimoniano che questo approccio permette di ottenere ad ogni interrogazione un insieme di query leggermente diverso da quello dell’interrogazione precedente. Whatsup fa un po’ di tali richieste e poi mette assieme tutte le query raccolte. Ho anche svolto inoltre delle prove che dimostrano che, sfruttando la tecnica indicata, cambiere l’IP interrogato non porta ulteriori benefici in termini di nuove query acquisite.

Sfruttare il disallineamento

Nel fare query ai servizi di Google che erogano le informazioni sulle query più cercate del momento, ho notato un fenomeno interessante che riguarda l’allineamento dei datacenter.

Durante le ore diurne il disallineamento è maggiore, probabilmente perché l’aggiornamento dei dati avviene dietro la spinta delle ricerche effettuate dagli utenti e un volume maggiore di ricerche o la nascita di picchi su temi nuovi comporta un maggiore e più frenetico avvicendamento delle query vecchie/nuove. Al contrario, le ore notturne non mostrano quasi mai datacenter dai contenuti disallineati.

Ho allora pensato che il grado di disallineamento dei datacenter potrebbe essere usato come un indice indiretto del volume di query in un dato istante o, più precisamente, del “fermento” delle ricerche degli utenti.

Si tratterebbe di un indice molto approssimativo e difficile da estrarre (anche durante il giorno i datacenter non appaiono disallineati costantemente) ma se l’intuizione sulla relazione “attività umana – disallineamenti” si dovesse dimostrare azzeccata, si potrebbe ottenere per la prima volta uno strumento in grado di dare visibilità del fermento esistente in rete durante l’arco di una giornata. :)

Un proxy PHP per il querybot

Dopo aver pubblicato l’articolo sul querybot per la simulazione di ricerche degli utenti, alcune persone mi hanno chiesto se l’emulazione umana avrebbe previsto anche il cambio di IP durante le richieste.

PHP proxyLa risposta è sì. Se non ne ho parlato nell’articolo è perché, senza pensarci, ho dato per scontata tale caratteristica, visto che da tempo uso un proxy PHP che mi permette di cambiare facilmente IP. Ma ugualmente scontato per i lettori non lo è e quindi vi spiego un po’ come funziona il proxy.

Il proxy è una versione riveduta e corrotta di un software che ho programmato qualche anno fa, per la creazione di alcuni tool SEO e di un proxy web in grado di bypassare certe restrizioni imposte da Google.

Si tratta di uno script PHP che fa da wrapper delle funzioni cURL e che necessita dunque di questa libreria per funzionare, così come di una versione o configurazione di PHP che contempli la presenza di tali funzioni.

Dal punto di vista dello sviluppatore l’uso è molto semplice: esiste una copia esatta delle funzioni previste dalla cURL, con l’aggiunta di alcune opzioni di tipo CURLOPT_ per la gestione dei parametri del proxy.

Per esempio, usando la copia della funzione curl_setopt() è possibile specificare l’URL del proxy che dovrà essere usato per le successive richieste.

All’URL specificato è presente uno script PHP che rappresenta il proxy vero e proprio, ecco come funziona il meccanismo:

  • il client effettua una richiesta come si farebbe normalmente con la cURL
  • il wrapper entra in gioco per codificare la richiesta in un particolare formato
  • il wrapper usa la cURL per inviare la richiesta codificata allo script proxy, nel far questo usa il metodo POST
  • lo script proxy riceve la richiesta codificata e la decodifica
  • lo script proxy usa la cURL per effettuare la richiesta originale esattamente nello stesso modo in cui l’avrebbe fatta il client;
  • ovviamente la richiesta viene effettuata con l’IP dell’host sul quale lo script proxy risiede
  • lo script proxy riceve il risultato della richiesta, lo codifica nuovamente e lo spedisce al client
  • il client riceve e decodifica il risultato della richiesta e lo restituisce al codice chiamante

Tutto il processo sopra indicato viene effettuato in modo assolutamente trasparente per il programmatore. In altre parole, qualsiasi script PHP che usa già la cURL può facilmente essere modificato per aggiungere la capacità di sfruttare uno o più proxy esterni.

Il sistema è comodo perché il sottoscritto, come la maggior parte dei webmaster e dei SEO, possiede più di un host provider per i propri siti web. Uploadare su ciascuno di essi lo script proxy permette dunque di ottenere tanti IP diversi quanti sono gli host su cui si pubblica lo script.

Conflitto tra le opzioni

Un dettaglio di progettazione che trovo interessante e che voglio condividere con voi è il modo in cui ho evitato le collisioni tra le nuove opzioni CURLOPT_ introdotte dal wrapper e le opzioni CURLOPT_ già esistenti.

La cURL prevede già di default un lungo elenco di opzioni attraverso le quali è possibile stabilire il comportamento della libreria. Ciascuna di queste opzioni ha un nome (una costante che inizia con “CURLOPT_”) e un corrispondente valore numerico.

Il wrapper è stato progettato in modo da replicare le opzioni CURLOPT_ e aggiungerne di proprie. Ho dovuto quindi fare attenzione a non definire costanti che avessero gli stessi valori già usati per quelle “ufficiali”. Il problema però sta nel fatto che ad ogni aggiornamento della cURL è possibile che la quantità di opzioni (e quindi delle costanti) aumenti.

Il mio wrapper non poteva quindi definire le nuove costanti in modo statico, perché avrebbe rischiato di usare valori potenzialmente allocabili dalle future versioni della cURL. Ogni aggiornamento della libreria avrebbe potuto scatenare dei conflitti e mettere il wrapper nelle condizioni di produrre malfunzionamenti.

La soluzione che ho trovato è stata quella di definire dinamicamente le costanti che mi serviva aggiungere. Il wrapper fa così ad ogni sua inizializzazione (si legga: lancio dello script):

  • usa la funzione di PHP get_defined_constants() per ottenere la lista delle costanti definite dalla cURL
  • estrae il valore più alto usato dalle costanti “ufficiali”
  • inizia a definire dinamicamente con la funzione define() le nuove costanti, partendo da valori superiori a quello massimo usato dalla cURL

Facendo in questo modo non c’è rischio che le costanti vengano create con valori già in uso o potenzialmente usabili in futuro dalla libreria cURL. :)