[SP-pm] use WWW::Mechanize

André Garcia Carneiro andre.garcia.carneir at terra.com.br
Thu Sep 18 11:10:44 PDT 2008


---------- Cabeçalho original -----------

De: saopaulo-pm-bounces+andre.garcia.carneir=terra.com.br em pm.org
Para: saopaulo-pm em mail.pm.org
Cópia: 
Data: Wed, 17 Sep 2008 16:41:25 -0300
Assunto: [SP-pm] use WWW::Mechanize

> Boa tarde!
> Estou com dúvida de como usar o $1.
> #!/usr/bin/perl


EXPLICANDO $1

Grosseiramente, $1 trás o resultado de uma expressão regular do primeiro parênteses, por exemplo, se vc tiver
uma expressão assim: /(\d+)x de r\$([\d\,\.]+)/

Essa expressão é uma expressão que serve para recuperar informações de parcelamento. Se eu quiser por exemplo a
informação de quantidade de parcelas, eu consigo isso através de $1. Se eu quiser o valor do parcelamento, eu
devo usar $2, e assim por diante.

Ah, mas e se tiver um parênteses dentro do outro? Por exemplo: /(\d+(\w##\w))(\w+)/. Mesma coisa. Mas você deve
considerar os parênteses de fora para dentro. Por que? Bom isso não é uma expressão matemática, portanto as
regras são diferentes. Em expressão regular, o parênteses serve para você agrupar expressões/subexpressões. E
por definição, a ordem dos parênteses para recuperação de dados, é de fora para dentro, ou seja: na expressão 
(\d+(\w_\w)), $1 irá conter uma sequencia numérica, seguido de uma letra ou '_', depois '##', depois letra ou
'_'. Já $2 irá conter uma letra ou _, seguido de um '##', seguido de outra letra ou '_'. E finalmente $3 teria
uma letra, ou '_'.




Lembrando que:

\w -> letras de a..z, A..Z ou _
\d -> números de 0 a 9
+  -> operador de expressão regular que significa 1 ou mais(grosseiramente falando).

RTFM bacana de fazer... perldoc perlre

Continue lendo os comentários abaixo...


> 
> use strict;
> use warnings;
> use WWW::Mechanize;
> 
> my $google = WWW::Mechanize->new();
> my $url = '
> http://www.google.com.br/search?hl=pt-BR&q=nasa&btnG=Pesquisa+Google&meta';
> $google->get($url);
> my $busca = $google->content();
> *print $1 for $busca=~ /<a href="(.*)">/;*


Nesse caso, $1 vai capturar tudo que estiver entre aspas duplas. Lembre-se que existe um parênteses, e é o
primeiro parênteses da expressão.


> Gostaria de saber como faço para imprimir só o que ta entre parênteses de
> uma forma correta, tentei usar o find_all_links() mas vem tudo até o que não
> é link.

 Ora, 

 print $1 for $busca=~ /<a href="(.*)">/

Isso já deveria imprimir o que você quer, certo? O problema é que você deve iterar isso para pegar no HTML
todo. Para fazer isso, veja o código abaixo(embora mais tarde, eu vá dizer pra não fazer isso, só sendo didático).

<code>

while($string =~ m/< a href="http://(.+?)"/sig){
     print "\n".$1; #Agora vou pegar todos!
}
</code>


Aí vc me pergunta.. .o que é 'sig'??? 

s transforma tudo numa única linha
i ignora 'case sensitive'
g procura na string toda
 

O que é .+?

Esse é um operador 'não guloso' de expressão regular, como costumam chamar. É preferível usar isso do que .*,
por que isso faz com que o motor de expressão regular restrinja ao máximo a região do 'match', com um menor
custo. Se eu estiver falando besteira, sintam-se a vontade para me baterem(mas na cara não).


POR QUE VOCÊ FALOU PRA NÃO USAR ISSO?

Simples, se vc realmente precisa de um parser, use um. Não precisa fabricar um, tem vários disponíveis no CPAN.
Eu gosto do HTML::TreeBuilder. Usando ele + WWW::Mechanize, você pode fazer assim:


<code>

use strict;
use HTML::TreeBuider;
use WWW::Mechanize;
my $mech = WWW::Mechanize->new();
my $url = 'http://suaurl.com.br/seila/mais/oq?var1=&var2=&var3=';
mech->get($url);
my $string = $mech->content;
#Instanciando o objeto, já fazendo parsing 
my $tree = HTML::TreeBuilder->new_from_content($string); #Transforma o HTML em um objeto HTML::TreeBuilder.

#Você pode trabalhar tanto em contexto de array, quanto escalar, pra mais detalhes, RTFM em
(http://search.cpan.org/~petek/HTML-Tree-3.23/lib/HTML/TreeBuilder.pm).

#Isso trás um array de objetos contendo TODAS as informações sobre TODAS as tags 'a', que o parser encontrar
my @all_links = $tree->look_down(_tag => 'a'); #Você pode restringir isso, incluindo o atributo que você
quiser, desde que esteja no HTML.

#Iterando o array de objetos
foreach my $link(@all_links){
      print "\n".$link->attr('href') if $link; #Isso imprime o que você quer.
}
$tree = $tree->delete; #destruindo o objeto.Isso é importante, principalmente se vc estiver iterando objetos
HTML::TreeBuilder. Se não fizer isso, dependendo da implementação, pode-se ter problemas com memória.

__END__

</code>


O Lorn falou no Template::Extract comigo. Não é um parser HTML, mas serve bem para extrair informações de um
HTML. Você só precisa de um template do que você quer extrair. Parece ser bem prático, mas esse eu não cheguei
a usar ainda, então dá uma olhada no cpan e entra em contato com o Lorn, porque ele já usou.




> #!/usr/bin/perl
> 
> use strict;
> use warnings;
> use WWW::Mechanize;
> my $url = "
> http://www.google.com.br/search?hl=pt-BR&q=nasa&btnG=Pesquisa+Google&meta=";
> my $busca = WWW::Mechanize->new();
> $busca->get($url);
> *$busca->find_all_links();*
> print $busca->content;
> 
> Obrigado.
> 
> 
> -- 
> Daniel de Oliveira Mantovani
> "A sede pelo aprendizado é insaciável"
> http://mantovanihouse.blogspot.com/
> ------------------------------------------------------------
> 

--
André Garcia Carneiro
Developer(Perl/PHP)
Member of "São Paulo Perl Mongers" - http://sao-paulo.pm.org



More information about the SaoPaulo-pm mailing list