diumenge, 30 d’octubre del 2011

Un "Piulador" personal amb Twitter4J

En el post d'avui crearé un petit "Piulador": una petita aplicació que em permetrà piular al Twitter.

El primer pas es descarregar l'API per al llenguatge de desenvolupament triat del lloc dels desenvolupadors de Twitter: https://dev.twitter.com/docs/twitter-libraries

Tenim APIs per a diferents llenguatges i amb diferents orígens. En particular per a Java, PHP, Python i C++ a la mateixa web dels desenvolupadors en destaquen aquestes:

C++:  Twitcurl,  http://code.google.com/p/twitcurl/.
Java:  Twitter4J, http://twitter4j.org/.
PHP: TmhOAuth, http://github.com/themattharris/tmhOAuth.
Python: Tweepy, https://github.com/tweepy/tweepy

En el meu cas, desenvoluparé l'aplicació amb Java, així que el primer que faig és descarregar Twitter4j

A la web de Twitter4J en podem llegir algunes de les característiques d'aquesta API


"Twitter4J és una biblioteca java (jar) no oficial per a l'API de Twitter.
Amb Twitter4J, es pot integrar fàcilment una aplicació Java amb el servei de Twitter.


Twitter4J ofereix: 
✔ és Java pur 100%. Funciona a partir de la versió de plataforma Java 1.4.2
✔ Preparat per a la plataforma Android i per a Google App Engine.
✔ Sense dependències. No li cal cap jar addicional.
✔ suport OAuth inclòs
✔ suport de GZip inclòs


Requeriments de sistema
Windows o Unix amb suport de Java.
JVM: Java 1.4.2 o superior


Com utilitzar Twitter4J?
Només cal afegir twitter4j-core-2.2.5.jar al classpath de l'aplicació.
El millor lloc per on començar és llegir el JavaDoc
El millor lloc per on començar a llegir el JavaDoc és la interface twitter4j.Twitter."

Però potser el primer que cal per a poder treballar amb Twitter és conèixer el protocol per a autenticar-se amb el servei:  El protocol OAuth  (rfc5849). Podem consultar també a http://oauth.net/core/1.0/.

El document de la rfc5849  ocupa 39 pàgines. però en un primer moment no cal llegir-lo per a poder fer servir la Twitter4J, perquè els detalls del funcionament estan encapsulats a la llibreria.

El que sí que caldrà és registrar l'aplicació que estem construint al servei Twitter, per a que aquest la reconegui i sigui capaç d'identificar-ne l'origen dels tweets. Això es fa a l'adreça https://dev.twitter.com/apps/new


Al formulari de registre haurem de posar el nom de l'aplicació, la descripció, l'adreça de descàrrega de l'aplicació (si la té)...



També hi podrem posar una icona, el tipus d'accés...el registre no resulta complicat.

Un cop registrada l'aplicació obtindrem les claus per autoritzar l'aplicació al Twitter.

En el llenguatge de OAuth  un Consumer és una aplicació, o una web, que accedeix a un proveïdor de servei en representació d'un usuari. Al registrar l'aplicació obtindrem el parell de valors que ens caldran per a autenticar l'aplicació, o consumer:

Consumer Key: Un valor utilitzat per l'aplicació per a identificar-se ella mateixa enfront del servei Twitter (el "login" de l'aplicació).
Consumer Secret: Un valor secret utilitzat per l'aplicació per a certificar la propietat de la Consumer Key  (el password).

A més, se'ns proporcionarà un conjunt d'URLs a les que caldrà accedir per a que l'usuari que faci servir l'aplicació també pugui autenticar-se


Request token URL: https://api.twitter.com/oauth/request_token
Authorize URL: https://api.twitter.com/oauth/authorize
Access token URL: https://api.twitter.com/oauth/access_token


Aquestes adreces permetran el diàleg entre el consumer i el servei per a autenticar a l'usuari final.

Request Token: és un valor utilitzat pel Consumer per a obtenir autorització de l'usuari i que es tradueix en un Access Token.
Access Token: és un valor utilitzat pel Consumer per a obtenir accés als Protected Resources (en el cas del Twitter, als tweets emesos o adreçats a l'usuari) en representació de l'usuari, en comptes de fer servir les pròpies credencials de l'usuari al Servei. És dir, l'aplicació no fa servir directament el login i el password de twitter de l'usuari. Podriem dir que l'Access Token és un login temporal.
Access Token Secret: un valor secret utilitzat pel Consumer per a certificar la propietat de l'Access Token (seria el password temporal corresponent al login temporal).

En la pàgina que es registra l'aplicació també podem obtenir un Acces Token i un Access Token Secret que es poden fer servir directament a l'aplicació per a piular des del propi compte de Twitter.

Guardem molt bé els diferents tokens rebuts. I mantinguem en secret els "passwords"
 Finalment, un cop registrada l'aplicació, podrem veure la nova aplicació registrada (i totes aquelles altres que puguem tenir) a https://dev.twitter.com/apps






A la pàgina de Twitter4J ens diuen com fer servir aquests parells.

Amb un  fitxer de propietats estàndard:  twitter4j.properties. Cal que el fitxer "twitter4j.properties" es trobi a les rutes del classpath.

debug=true
oauth.consumerKey=*********************
oauth.consumerSecret=******************************************
oauth.accessToken=**************************************************
oauth.accessTokenSecret=******************************************

Amb un objecte ConfigurationBuilder

ConfigurationBuilder cb = new ConfigurationBuilder();
cb.setDebugEnabled(true)
    .setOAuthConsumerKey("*********************")
    .setOAuthConsumerSecret("******************************************")
    .setOAuthAccessToken("**************************************************")
    .setOAuthAccessTokenSecret("******************************************");
TwitterFactory tf = new TwitterFactory(cb.build());
Twitter twitter = tf.getInstance();

O amb variables de sistema passades a la JVM.

$ java -Dtwitter4j.debug=true
    -Dtwitter4j.oauth.consumerKey=*********************
    -Dtwitter4j.oauth.consumerSecret=******************************************
    -Dtwitter4j.oauth.accessToken=**************************************************
    -Dtwitter4j.oauth.accessTokenSecret=******************************************
    -cp twitter4j-core-2.2.5.jar:yourApp.jar yourpackage.Main

Arribats a aquest punt, un cop obtinguts els parells Consumer Key, Consumer Secret i Access Token i Access Token Secret ja estic en condicions de fer una petita aplicació amb java que "Piuli" al twitter en nom del meu compte.

Una cosa tan senzilla com això:

package com.sticipl.proves;


import twitter4j.Status;
import twitter4j.Twitter;
import twitter4j.TwitterException;
import twitter4j.TwitterFactory;
import twitter4j.conf.ConfigurationBuilder;




public final class ProvaTwitter {
    /**
     * Usage: java twitter4j.examples.tweets.UpdateStatus [text]
     *
     * @param args message
     */
    public static void main(String[] args) {
        try {
        ConfigurationBuilder cb = new ConfigurationBuilder();
        cb.setDebugEnabled(true)
           .setOAuthConsumerKey("[El consumer Key obtingut]")
           .setOAuthConsumerSecret("[el consumer secret obtingut]")
           .setOAuthAccessToken("[l'access token obtingut]")
           .setOAuthAccessTokenSecret("[l'access token secret obtingut]");
        TwitterFactory tf = new TwitterFactory(cb.build());
        Twitter twitter = tf.getInstance();
            
            Status status = twitter.updateStatus("Aquest és el missatge enviat des de l'aplicació #Java de prova fent us de #Twitter4J");
            System.out.println("Actualitzat status a [" + status.getText() + "].");
            System.exit(0);
        } catch (TwitterException te) {
            te.printStackTrace();
            System.out.println("Excepció de Twitter: " + te.getMessage());
            System.exit(-1);
        }
    }
}

En executar aquesta mini-aplicació, obtinc:

Actualitzat status a [Aquest és el missatge enviat des de l'aplicació #Java de prova fent us de #Twitter4J].
I en anar a Twitter puc comprovar que, efectivament, així és:



En aquesta primera aproximació a Twitter4J he fet un petit "piulador" personal. En un proper post presentaré un "Piulador" general.

divendres, 28 d’octubre del 2011

Com instal·lar XAMPP a Ubuntu.

A l'hora de fer presentacions i demos d'aplicacions web, pot ser molt útil disposar d'una versió de la demo en un servidor web en localhost, potser en una clau usb.

També pot ser molt útil un servidor web d'aquest tipus a l'hora de preparar sessions de formació.

És possible trobar per Internet diverses distribucions que d'aquest tipus que combinen Apache amb  MySQL i PHP, tant sobre Linux (LAMP), com sobre Windows (WAMP), per exemple XAMPP o MoWeS Portable.

MoWeS Portable empaqueta, a més de la plataforma AMP, altres aplicacions que utilitzen aquesta infraestructura, com Joomla! o Drupal. Ara bé, MoWeS Portable només està disponible per a Windows.

XAMPP, en canvi, s'ofereix per a Linux i Windows.

En el post d'avuí el que faig és instal·lar el XAMPP a un netbook Linux.

No cal dir que la plataforma AMP es pot instal·lar des del Centre de Programari de l'Ubuntu. Però la instal·lació de XAMPP és encara més senzilla.

Dit i fet. El primer pas és descarregar-se el paquet d'instal·lació. El  puc trobar en aquesta adreça:  http://sourceforge.net/projects/xampp/files/BETAS/xampp-linux-1.7.7.tar.gz/download. Són uns 77MB.

Aquesta versió incorpora:   Apache, MySQL, PHP amb PEAR, Perl, ProFTPD, phpMyAdmin, OpenSSL, GD, Freetype2, libjpeg, libpng, gdbm, zlib, expat, Sablotron, libxml, Ming, Webalizer, pdf class, ncurses, mod_perl, FreeTDS, gettext, mcrypt, mhash, eAccelerator, SQLite i IMAP C-Client.

En particular Apache 2.2.21, MySQL 5.5.16, PHP 5.3.8, i phpMyAdmin 3.4.5.

Per instal·lar  n'hi ha prou amb desempaquetar el tar.gz. Cal tenir en compte que als fitxers d'instal·lació s'assumeix que la home del XAMPP serà /opt/lampp. Això NO vol dir que només es pugui instal·lar en aquesta carpeta. Això l'únic que vol dir és que caldrà que /opt/lampp sigui la "home" del XAMPP i això es podrà aconseguir amb un enllaç simbòlic des de /opt/lampp al directori d'instal·lació que triï.

Si la carpeta de destinació del XAMPP es troba en una clau usb caldrà que aquesta clau estigui formatada amb un sistema de fitxers que permeti els enllaços simbòlics, per exemple  ext2,ext3 o ext4.

A l'hora de fer l'enllaç simbòlic caldrà tenir en compte el punt de muntatge del dispositiu. Per exemple, al meu netbook amb Ubuntu 11.04, el punt de muntatge és /media.

Per a poder instal·lar correctament el XAMPP caldran, a més, permisos de root. I també per a posar en marxa i aturar els diversos components de la distribució.

Tenint en compte tot l'anterior, instal·lo el XAMPP a la meva carpeta home, on he deixat el tar.gz:

sudo tar xvfz xampp-linux-1.7.7.tar.gz -C .

Amb la ordre anterior es crea una carpeta lampp amb els dversos components del XAMPP.

Ara creo l'enllaç simbòlic:

sudo ln -s /home/albert/lampp /opt/lampp

I engego per primer cop el servidor. Aquesta primera arrencada acaba d'instal·lar i configurar els components.

albert@athena:~$ sudo /opt/lampp/lampp start
Starting XAMPP for Linux 1.7.7...
XAMPP: Starting Apache with SSL (and PHP5)...
XAMPP: Starting MySQL...
XAMPP: Starting ProFTPD...
XAMPP for Linux started.
albert@athena:~$ 

I per revisar la nova instal·lació en tinc prou amb obrir un navegador i apuntar-lo al localhost:




El directori arrel del servidor web es troba a /opt/lampp/htdocs (en el meu cas, mercès a l'enllaç simbòlic, és /home/albert/lampp/htdocs).

Per aturar el XAMPP puc fer:


albert@athena:~$ sudo /opt/lampp/lampp stop
Stopping XAMPP for Linux 1.7.7...
XAMPP: Stopping Apache with SSL...
XAMPP: Stopping MySQL...
XAMPP: Stopping ProFTPD...
XAMPP stopped.
albert@athena:~$ 

I per a eliminar la instal·lació sense deixar rastres, amb el XAMPP aturat, n'hi ha prou amb fer:

sudo rm -r lampp

És possible engegar i aturar individualment els diversos components del XAMPP. Examinant el fitxer $HOME/lampp/lampp es poden  trobar les diverses opcions disponibles. La forma d'invocar-les, en general, és: 

sudo /opt/lampp/lampp opció

diumenge, 9 d’octubre del 2011

Com accedir a bases de dades SQLite amb Python

En l'exercici d'avui, presento el mòdul pysqlite2 que proporciona una senzilla interfície per a utilitzar SQLite amb Python.

A l'Ubuntu, per a afegir aquest mòdul  n'hi ha prou amb anar al Centre de Programari de l'Ubuntu i instal·lar els paquets python-pysqlite2 i python-pysqlite2-doc.



Cal anar amb compte perquè els números de versió poden crear confusió: trobarem també els mòduls python-pysqlite, però aquests són per a taules de l'anterior SQLite2. Els python-pysqlite2, corresponen a SQLite3, que és la versió actual.

Primer de tot crearé una base de dades SQLite3 de proves amb una taula diccionari. amb tres columnes: id, PK, numèric amb autoincrement; nom, text; valor, text. 

La taula es pot crear de forma senzilla amb l'aplicació gràfica SQLiteman, que permet operar amb taules d'SQLite3. En tot cas, també es pot crear la taula de proves amb la interfície en mode text que proporciona el mateix SQLite3. En cas de no disposar de SQLiteman, aquest es pot instal·lar, com tota la resta, des del Centre de Programari de l'Ubuntu.




L'esquema  

CREATE TABLE "diccionari" (
    "id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
    "nom" TEXT NOT NULL,
    "valor" TEXT NOT NULL
);
CREATE TABLE sqlite_sequence(name,seq);

Un cop creada la taula, la informo amb dades de prova. 

I, a continuació, el codi per a afegir, cercar, esborrar...amb Python i pysqlite2.


#!/usr/bin/python
# coding: latin-1
# python i sqlite

from pysqlite2 import dbapi2 as sqlite

# es connecta a una base de dades
con = sqlite.connect("./prova-sqlite.db")

# itera a través de la taula diccionari amb un cursor
cursor = con.cursor()

# executa el cursor
cursor.execute("select id, nom, valor from diccionari")

# itera a través de les files
# obtenir-ne només resultat un: 
print "\n-------------------------------"
print "estat inicial"
for fila in cursor:
# recupera els valors
iddic, nom, valor = fila[0], fila[1], fila[2]
# els mostra
print "id: " + str(iddic) + "; nom: " + nom + "; valor: " + valor

# inserta noves files, amb una seqüència
print "\n-------------------------------"
print "insereix 3 files"
cursor.execute("insert into diccionari(nom, valor) values (?, ?)", ("nom6","valor6") )
cursor.execute("insert into diccionari(nom, valor) values (?, ?)", ("nom7","valor7") )
cursor.execute("insert into diccionari(nom, valor) values (?, ?)", ("nom8","valor8") )

# commit
con.commit();

# a veure què ha fet...
cursor.execute("select id, nom, valor from diccionari")

# itera a través de les files
for fila in cursor:
# recupera els valors
iddic, nom, valor = fila[0], fila[1], fila[2]
# els mostra (un mètode alternatiu)
print "id: %d; nom: %s; valor: %s" % (iddic, nom, valor)

# amb un mapeig
print "\n-------------------------------"
print "insereix 3 files més"
item = {"nom": "nom9", "valor": "valor9"}
cursor.execute("insert into diccionari(nom, valor) values (:nom, :valor)", item)
item = {"nom": "nom10", "valor": "valor10"}
cursor.execute("insert into diccionari(nom, valor) values (:nom, :valor)", item)
item = {"nom": "nom11", "valor": "valor11"}
cursor.execute("insert into diccionari(nom, valor) values (:nom, :valor)", item)

# commit
con.commit();

# tornem a veure què ha fet...
cursor.execute("select id, nom, valor from diccionari")

# itera a través de les files
for fila in cursor:
# recupera els valors
iddic, nom, valor = fila[0], fila[1], fila[2]
# els mostra 
print "id: %d; nom: %s; valor: %s" % (iddic, nom, valor)


#finalment, ho deixo tot com estava al començament
cursor.execute("delete from diccionari where id > 5") 
con.commit()

# ho verifica...
cursor.execute("select id, nom, valor from diccionari")

# itera a través de les files, un mètode alternatiu amb fetchone
print "\n-------------------------------"
print "ho deixa com estava a l'inici"
fila = cursor.fetchone()
while (not (fila is None)):
# recupera els valors
iddic, nom, valor = fila[0], fila[1], fila[2]
# els mostra
print "id: %d; nom: %s; valor: %s" % (iddic, nom, valor)
fila = cursor.fetchone()

# tanca el cursor
cursor.close()

# tanca la connexió
con.close()

Els comentaris del codi en proporcionen les explicacions. Només en destacaria les alternatives idiomàtiques que ofereix Python per a realitzar diverses accions:

Per exemple: un print de diferents variables, i l'alternativa a l'estil del printf de C:

print "id: " + str(iddic) + "; nom: " + nom + "; valor: " + valor

print "id: %d; nom: %s; valor: %s" % (iddic, nom, valor)

O aquesta altre: la iteració a través d'un cursor amb for, i uns alternativa amb while 
 
amb for

for fila in cursor:
# recupera els valors
iddic, nom, valor = fila[0], fila[1], fila[2]
# els mostra 
print "id: %d; nom: %s; valor: %s" % (iddic, nom, valor)

amb while:

fila = cursor.fetchone()
while (not (fila is None)):
# recupera els valors
iddic, nom, valor = fila[0], fila[1], fila[2]
# els mostra
print "id: %d; nom: %s; valor: %s" % (iddic, nom, valor)
fila = cursor.fetchone()


Instruccions "preparades" i l'ús de '?', o de variables vinculades a l'insert

amb '?'
cursor.execute("insert into diccionari(nom, valor) values (?, ?)", ("nom6","valor6") )

amb variables vinculades
item = {"nom": "nom11", "valor": "valor11"}
cursor.execute("insert into diccionari(nom, valor) values (:nom, :valor)", item)

I, a continuació, una execució del programa   

albert@atenea:~/wk-python/prova-sqlite$ python prova-sqlite.py 

-------------------------------
estat inicial
id: 1; nom: nom1; valor: valor1
id: 2; nom: nom2; valor: valor2
id: 3; nom: nom3; valor: valor3
id: 4; nom: nom4; valor: valor4
id: 5; nom: nom5; valor: valor5

-------------------------------
insereix 3 files
id: 1; nom: nom1; valor: valor1
id: 2; nom: nom2; valor: valor2
id: 3; nom: nom3; valor: valor3
id: 4; nom: nom4; valor: valor4
id: 5; nom: nom5; valor: valor5
id: 45; nom: nom6; valor: valor6
id: 46; nom: nom7; valor: valor7
id: 47; nom: nom8; valor: valor8

-------------------------------
insereix 3 files més
id: 1; nom: nom1; valor: valor1
id: 2; nom: nom2; valor: valor2
id: 3; nom: nom3; valor: valor3
id: 4; nom: nom4; valor: valor4
id: 5; nom: nom5; valor: valor5
id: 45; nom: nom6; valor: valor6
id: 46; nom: nom7; valor: valor7
id: 47; nom: nom8; valor: valor8
id: 48; nom: nom9; valor: valor9
id: 49; nom: nom10; valor: valor10
id: 50; nom: nom11; valor: valor11

-------------------------------
ho deixa com estava a l'inici
id: 1; nom: nom1; valor: valor1
id: 2; nom: nom2; valor: valor2
id: 3; nom: nom3; valor: valor3
id: 4; nom: nom4; valor: valor4
id: 5; nom: nom5; valor: valor5
albert@atenea:~/wk-python/prova-sqlite$ 

Per saber-ne més, una cerca a Google ens proporcionarà un munt d'enllaços. Tanmateix, cal explicitar la referència fonamental: el lloc de la documentació de Python (http://docs.python.org).

En particular, l'apartat de SQLite 3: http://docs.python.org/library/sqlite3.html