sysd.org
2mai/120

Google Refine + Perl

Google Refine é show. Para quem não conhece, acesse já o site oficial e assista pelo menos o primeiro vídeo. Serve para inúmeras tarefas envolvendo ETL.

Eu, no momento, uso muito para coisas simples, como carregar um CSV, eliminar outliers e salvar em JSON para carregar no MongoDB. Nada que um one-liner em Perl não pudesse fazer.

Infelizmente, a recíproca não é válida: one-liners em Perl são bem mais versáteis do que o Google Refine. Que tal integrar os dois?

  1. Google Refine pode ser facilmente integrado com um web-service qualquer.
  2. Perl transforma one-liners em webservices.
  3. PROFIT!!!

Como exemplo concreto, utilizarei dados georeferenciados. Digamos que preciso eliminar registros duplicatas, e uma das formas de detectar é pela proximidade física dos pontos no mapa. Google Refine não é um GIS, e não faz a menor ideia de como processar latitude/longitude. Entra o GeoDNA: um algoritmo que transforma coordenadas numéricas bidimensionais em uma string com propriedade interessante: quanto mais longo o prefixo compartilhado de dois GeoDNAs, mais perto estão as respectivas coordenadas no mapa (infelizmente, GeoDNAs com prefixos totalmente distintos também podem estar fisicamente próximos; localidades próximas ao meridiano de Greenwich são um exemplo clássico). Portanto, ordenando os registros por GeoDNA, as localidades próximas tenderão a ficar em linhas adjascentes. Para a integração, usaremos o recurso Add column by fetching URLs, clickando em header de qualquer coluna (a coluna não importa pois, de qualquer maneira, usaremos dados de duas):

No diálogo que aparecer, colamos o seguinte código (atenção para o nome das colunas com as respectivas coordenadas):

'http://127.0.0.1:3000/?lat='+
row.cells['latitude'].value
+'&lon='+
row.cells['longitude'].value

Não precisamos do throttle delay, pois o nosso webservice é local. O diálogo deve ficar assim (nada de clickar em OK, ainda):

Agora, certifique-se de que você tem os módulos Mojolicious e Geo::DNA instalados, e rode no terminal:

perl -MGeo::DNA -Mojo -E 'a("/"=>sub{my$s=shift;$s->render(json=>{geocode=>Geo::DNA::encode_geo_dna($s->param("lat"),$s->param("lon"))})})->start' daemon

Se preferir, aqui está a versão "por extenso":

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/usr/bin/env perl
use Geo::DNA qw(encode_geo_dna);
use Mojolicious::Lite;
 
any '/' => sub {
    my $self = shift;
    $self->render(json => {
        geocode => encode_geo_dna(
            $self->param('lat'),
            $self->param('lon'),
        ),
    });
};
 
app->start;

Uma vez iniciado o webservice, clique em OK lá no diálogo do Google Refine e aguarde. Mesmo sem o delay, é relativamente lento; porém o custo/benefício dessa gambiarrinha é, evidentemente, favorável ;)

20jul/112

TicketFeed – Alimentando o seu leitor de feeds!

Sei lá o que posso prosear a respeito disso :P

Mas vamos começar pelo começo. Um belo dia, estive eu no caixa de um restaurante, prestes a pagar pelo meu almoço, quando uma notícia nada agradável me surpreende: o meu saldo estava zerado!!!

Como isso seria possível, se o meu ticket até está na minha planilha de gastos (isso é, sempre que uso ele, anoto quando e aonde foi)?! Pois é, foi clonado.

Então de que adiantou todo o meu acompanhamento de crédito/débito? Pfffffft :P

Aí no processo de resgatar o rico dinheirinho do meu rango, me deparei com o site oficial, http://www.ticket.com.br/, que é uma tosqueira inigualável. Para começar, o "sistema de segurança" é tão pífio que requer apenas o número do cartão, sem senha alguma, para consultas de extrato/saldo! Tudo bem que não é uma informação pra lá de sigilosa, ainda assim... Qual a utilidade podemos extrair disso?

  1. Funcionários de uma mesma empresa recebem seus cartões do mesmo lote. A numeração dos cartões é sequencial, só muda o dígito verificador (que segue o padrão do cartão de crédito). No extrato sai o nome do local aonde o dinheiro foi debitado. Assim, é perfeitamente possível rastrear os meus coleguinhas;
  2. Posso fazer coleta automática do extrato, assim saberei de antemão se fui debitado indevidamente. Poderia receber avisos de débito/crédito por email, mas o email está morrendo, e o hype do momento são os leitores de feed (sarcasmo mode off).

Acabei optando pela segunda opção. Aliás, aproveitei para fazer um test drive do DotCloud, e gostei!

Então, o negócio é o seguinte. Pegue o seu Ticket. Entre em http://ticket.iwatcher.net/. Preencha o respectivo campo, e gere URL do tracker. Eu gosto do Google Reader, mas funciona em qualquer outro agregador de feeds. A ideia central é: para cada "ping" no tracker, o webservice rodará um scrapper no site oficial, e gerará um feed a partir dos dados coletados. Assim, você terá um feed de notícias gerado pelos seus hábitos gastronômicos ;)

Uma observação importantíssima a respeito da privacidade dos dados: o número do seu Ticket é transferido em plaintext, assim como no site oficial. Obviamente, dessa forma ele acaba parando no access.log do servidor. Não tem como evitar isso. Já os dados das transações não estão sendo replicadas em nenhum banco de dados. Traduzindo: eu não sei o que se passa na sua conta, caso você venha a utilizar o meu webservice. Nem pretendo saber. Mas, de posse dos logs dos servidores, é perfeitamente possível acessar o extrato referente a cada Ticket consultado, visto que o site oficial não utiliza nenhum tipo de PIN/senha.

Ah, e o layout da página do gerador de feeds fica uma nhaca no Firefox. Eu não sei corrigir :(

Alguém com um bom domínio de CSS se habilita?

6jun/112

Perl e módulos na $HOME

Mas, por quê?!

Qual o sentido de alguém instalar os módulos dentro do seu $HOME? Normalmente, uma das duas:

  1. Você não tem permissão suficiente para instalar no próprio sistema (você está mexendo num servidor ou coisa do tipo);
  2. Você está desenvolvendo a bagaça, e quer manter a versão bleeding edge só para você.

Bom, se for o 2-o caso, existe o tal do perlbrew.

Mas eu gosto das instalações locais e as uso desde '97. E o local::lib foi uma mão na roda e tanto! Então, vamos lá:

Passo-a-passo:

Download do local::lib:

curl -LO http://search.cpan.org/CPAN/authors/id/A/AP/APEIRON/local-lib-1.008004.tar.gz
tar xzf local-lib-1.008004.tar.gz
cd local-lib-1.008004/

Instalação do local::lib:

perl Makefile.PL --bootstrap=$HOME/perl5
make
make test
make install

Ativando local::lib na inicialização da shell (Bash):

cat << PROFILE >> $HOME/.profile

export PERL_MM_USE_DEFAULT=1
eval \$(perl -I\$HOME/perl5/lib/perl5/ -Mlocal::lib)
PROFILE

Agora, é hora de logoff/logon para quem está acostumado com o Windows, ou então:

. $HOME/.profile

Prosseguindo com a configuração/teste do CPAN (essa configuração faz as dependências serem instaladas automaticamente):

cpan

cpan[1]> o conf prerequisites_policy follow
cpan[2]> o conf commit
cpan[3]> install App::cpanminus
cpan[4]> quit

Enumerando os módulos instalados:

perl -MExtUtils::Installed -E 'chdir $ENV{PERL_LOCAL_LIB_ROOT}; my $i = new ExtUtils::Installed; say for $i->modules'

cpanminus permite atualizar todos de uma vez, de uma maneira eficiente:

perl -MExtUtils::Installed -E 'chdir $ENV{PERL_LOCAL_LIB_ROOT}; my $i = new ExtUtils::Installed; say for $i->modules' | cpanm

Referências:

Easy AdSense by Unreal