Mineração de dados com Ruby e Twitter

O lado interessante de uma API do Twitter

Twitter não é somente uma fantástica ferramenta de rede social em tempo real, ele também é uma fonte de informações valiosas prontas para mineração de dados. Em média, os usuários do Twitter geram 140 milhões de tweets por dia em uma variedade de tópicos. Esse artigo apresenta a mineração de dados e demonstra o conceito com a linguagem orientada a objeto Ruby.

M. Tim Jones, Independent author

M. Tim JonesM. Tim Jones é arquiteto de firmware integrado e autor de Artificial Intelligence: A Systems Approach, GNU/Linux Application Programming (atualmente em sua segunda edição), AI Application Programming (em sua segunda edição) e BSD Sockets Programming from a Multilanguage Perspective. Seu conhecimento em engenharia varia do desenvolvimento de kernels para naves espaciais geossincrônicas até a arquitetura de sistemas embarcados e o desenvolvimento de protocolos de rede. Tim é Consultor de Engenharia da Emulex Corp. em Longmont, Colorado.



19/Out/2011

Em outubro de 2008, como muitos outros, criei uma conta no Twitter por curiosidade. Como a maioria das pessoas, conectei-me com amigos e fiz algumas pesquisas aleatórias para entender melhor o serviço. A comunicação com 140 caracteres não parecia uma ideia que se tornaria popular. Um acontecimento que não tinha a ver com o Twitter me ajudou a entender seu valor real.

No início de julho de 2009, meu provedor de hospedagem da web saiu do ar. Depois de pesquisas aleatórias na Web, encontrei informações que apontavam o incêndio no Fisher Plaza de Seattle como sendo o culpado. Informações vindas de fontes tradicionais baseadas na Web eram lentas e não davam indicação de quando o serviço poderia retornar. No entanto, depois de pesquisar o Twitter, encontrei relatos pessoais do incidente, incluindo informações em tempo real sobre o que estava acontecendo no local. Por exemplo, logo antes que meu serviço de hospedagem retornasse, houve um tweet indicando que geradores a diesel estavam do lado de fora do prédio.

Foi quando me dei conta de que o verdadeiro poder do Twitter é a comunicação aberta e em tempo real de informações entre indivíduos e grupos. Mas, sob a superfície, ele tem um tesouro de informações sobre comportamentos dos usuários e de tendências em níveis local e global. Exploro isso no contexto de scripts simples usando a linguagem Ruby e o gem do Twitter, um wrapper da API para o Twitter. Também demonstro como criar mashups simples para visualização de dados usando outros serviços e aplicativos da Web.

Conhecimento sobre Ruby

Se você não tem conhecimento básico sobre a maravilhosa linguagem Ruby, encontre referências em Recursos .Esses exemplos demonstram o valor do Ruby e sua capacidade de codificar um poder significativo em um número limitado de linhas de origem de código.

Twitter e APIs

Embora, inicialmente, a Web se destinasse à interação entre homens e máquinas, a Web de hoje trata a interação entre máquinas, ativando o uso de serviços da Web. Esses serviços existem para os Web sites mais populares —de vários serviços do Google ao LinkedIn, Facebook e Twitter. Serviços da Web criam APIs por meio das quais aplicativos externos podem consultar ou manipular conteúdo nos sites da Web.

Serviços da Web são implementados usando uma série de estilos. Hoje, um dos mais populares é o Representational State Transfer, ou REST. Uma implementação do REST é sobre o bem conhecido protocolo HTTP, permitindo que o HTTP exista como um meio para uma arquitetura RESTful (usando operações HTTP padrão como GET, PUT das atualizações, POSTe DELETE). A API para o Twitter foi desenvolvida como uma abstração sobre esse meio. Dessa forma, não há conhecimento de REST, HTTP ou formatos de dados, como XML ou JSON, mas, em vez disso, uma interface com base em objeto que se integra de forma eficiente na linguagem Ruby.


Um tour rápido do Ruby e do Twitter

Vamos explorar como é possível usar a API do Twitter com Ruby. Primeiro, precisamos obter os recursos necessários. Se, como eu, você está usando o Ubuntu Linux®, use a estrutura apt .

Para obter a distribuição completa mais recente do Ruby (um download de aproximadamente 13MB), use essa linha de comando:

$ sudo apt-get install ruby1.9.1-full

A seguir, obtenha o gem do Twitter usando o utilitário gem :

$ sudo gem install twitter

Agora você tem tudo o que é necessário para essa etapa, então, vamos continuar com um teste do wrapper do Twitter. Para essa demonstração, use um shell chamado Interactive Ruby Shell (IRB). Esse shell permite executar comandos do Ruby e experimentar a linguagem em tempo real. O IRB tem um grande número de capacidades, mas nós o usaremos para experimentação simples.

A Listagem 1 mostra uma sessão com o IRB que foi dividida em três seções para auxiliar da capacidade de leitura. A primeira seção (linhas 001 e 002) simplesmente prepara o ambiente ao importar os elementos necessários de tempo de execução (o método exige carrega e executa a biblioteca nomeada). A próxima linha (003) demonstra o uso do gem do Twitter para exibir o tweet mais recente do IBM® developerWorks®. Como mostrado, você usa o método user_timeline do módulo Client::Timeline para exibir um tweet. Esse primeiro exemplo demonstra a capacidade de "métodos encadeados" do Ruby. Um método user_timeline retorna um array de 20 tweets que podem ser encadeados no método first . Isso extrai o primeiro tweet do array (first é um método da classe Array ). Para esse único tweet, você extrai o campo de texto emitido para a saída via puts.

A seção seguinte (linha 004) usa o campo de localização definido pelo usuário, um campo de formato livre no qual o usuário pode fornecer informações de localização úteis e não úteis. Neste exemplo, o módulo User obtém informações do usuário restringidas dentro do campo de localização.

A seção final (a partir da linha 005) explora o módulo Twitter::Search . O módulo de pesquisa fornece uma interface extremamente rica com a qual pesquisar no Twitter. Nesse exemplo, primeiro você cria uma instância de pesquisa (linha 005) e, a seguir, especifica uma pesquisa na linha 006. Você está pesquisando os tweets mais recentes contendo a palavra porquê que sejam direcionados ao usuário LulzSec. A lista resultante foi reduzida e editada. Pesquisas são persistentes com relação ao fato de que a instância da pesquisa mantém os filtros definidos. É possível limpar esses filtros executando search.clear.

Listagem 1. Experimentação com a API do Twitter por meio do IRB
$ irb
irb(main):001:0> require "rubygems"
=> true
irb(main):002:0> require "twitter"
=> true

irb(main):003:0> puts Twitter.user_timeline("developerworks").first.text
dW Twitter is saving #IBM over $600K per month: will #Google+ add to that? > 
http://t.co/HiRwir7 #Tech #webdesign #Socialmedia #webapp #app
=> nil

irb(main):004:0> puts Twitter.user("MTimJones").location
Colorado, USA
=> nil

irb(main):005:0> search = Twitter::Search.new
=> #<Twitter::Search:0xb7437e04 @oauth_token_secret=nil, 
    @endpoint="https://api.twitter.com/1/", 
    @user_agent="Twitter Ruby Gem 1.6.0", 
    @oauth_token=nil, @consumer_secret=nil, 
    @search_endpoint="https://search.twitter.com/", 
    @query={:tude=>[], :q=>[]}, @cache=nil, @gateway=nil, @consumer_key=nil, 
    @proxy=nil, @format=:json, @adapter=:net_http<
irb(main):006:0> search.containing("why").to("LulzSec").
result_type("recent").each do |r| puts r.text end
@LulzSec why not stop posting <bleep> and get a full time job! MYSQLi isn't 
hacking you <bleep>.
...
irb(main):007:0>

A seguir, vejamos o esquema para um usuário no Twitter. Também é possível fazer isso por meio do IRB, mas reformatarei o resultado para ilustrar de forma mais simples a anatomia de um usuário do Twitter. A Listagem 2 mostra o resultado da impressão da estrutura do usuário que, no Ruby, é um Hashie::Mash. Essa estrutura é útil porque permite que um objeto tenha acessos de método para chaves de hash (um objeto aberto). Como é possível ver na listagem 2, esse objeto contém uma série de informações (informações específicas do usuário e de renderização), incluindo o status atual do usuário (com informações de codificação geográfica). Um tweet também contém um grande volume de informações e é possível visualizá-las facilmente gerando essas informações usando a classe user_timeline .

Listagem 2. Anatomia de um usuário do Twitter (perspectiva do Ruby)
irb(main):007:0> puts Twitter.user("MTimJones")
<#Hashie::Mash 
  contributors_enabled=false 
  created_at="Wed Oct 08 20:40:53 +0000 2008" 
  default_profile=false default_profile_image=false 
  description="Platform Architect and author (Linux, Embedded, Networking, AI)."
  favourites_count=1 
  follow_request_sent=nil 
  followers_count=148 
  following=nil 
  friends_count=96 
  geo_enabled=true 
  id=16655901 id_str="16655901" 
  is_translator=false 
  lang="en" 
  listed_count=10 
  location="Colorado, USA" 
  name="M. Tim Jones" 
  notifications=nil 
  profile_background_color="1A1B1F" 
  profile_background_image_url="..."
  profile_background_image_url_https="..." 
  profile_background_tile=false 
  profile_image_url="http://a0.twimg.com/profile_images/851508584/bio_mtjones_normal.JPG" 
  profile_image_url_https="..." 
  profile_link_color="2FC2EF" 
  profile_sidebar_border_color="181A1E" profile_sidebar_fill_color="252429" 
  profile_text_color="666666" 
  profile_use_background_image=true 
  protected=false 
  screen_name="MTimJones" 
  show_all_inline_media=false 
  status=<#Hashie::Mash 
    contributors=nil coordinates=nil 
    created_at="Sat Jul 02 02:03:24 +0000 2011" 
    favorited=false 
    geo=nil 
    id=86978247602094080 id_str="86978247602094080" 
    in_reply_to_screen_name="AnonymousIRC" 
    in_reply_to_status_id=nil in_reply_to_status_id_str=nil 
    in_reply_to_user_id=225663702 in_reply_to_user_id_str="225663702" 
    place=<#Hashie::Mash 
      attributes=<#Hashie::Mash> 
      bounding_box=<#Hashie::Mash 
        coordinates=[[[-105.178387, 40.12596], 
                      [-105.034397, 40.12596], 
                      [-105.034397, 40.203495], 
                      [-105.178387, 40.203495]]] 
        type="Polygon"
      > 
      country="United States" country_code="US" 
      full_name="Longmont, CO" 
      id="2736a5db074e8201" 
      name="Longmont" place_type="city" 
      url="http://api.twitter.com/1/geo/id/2736a5db074e8201.json"
    > 
    retweet_count=0 
    retweeted=false 
    source="web" 
    text="@AnonymousIRC @anonymouSabu @LulzSec @atopiary @Anonakomis Practical reading 
          for future reference... LULZ \"Prison 101\" http://t.co/sf8jIH9" truncated=false
  >
  statuses_count=79 
  time_zone="Mountain Time (US & Canada)" 
  url="http://www.mtjones.com" 
  utc_offset=-25200 
  verified=false
>
=> nil
irb(main):008:0>

E esse é o fim do tour rápido. Agora, vamos explorar alguns scripts simples que podem ser usados para coletar e visualizar dados usando Ruby e a API do Twitter. Ao longo do caminho, você conhecerá alguns dos conceitos do Twitter, como autenticação e limitação de taxa.


Mineração de dados do Twitter

As seções a seguir apresentam vários scripts para coletar e apresentar dados disponíveis por meio da API do Twitter. Esses scripts têm como foco a simplicidade, mas é possível estendê-los e combiná-los para criar novas capacidades. Além disso, essa seção explora de forma geral a API gem do Twitter, onde muitas outras capacidades estão disponíveis.

É importante notar que a API do Twitter somente permite que clientes façam um número limitado de chamadas em uma certa hora, ou seja, Twitter limita as solicitações (atualmente, não mais do que 150 por hora), o que significa que, depois de um certo volume de uso, você receberá uma mensagem de erro e deverá aguardar antes de enviar novas solicitações.

Informações do usuário

Lembre-se da listagem 2 que um grande volume de informações está disponível sobre cada usuário do Twitter. Essas informações só estão acessíveis se o usuário não estiver protegido. Vejamos como é possível extrair os dados de um usuário e apresentá-los de uma forma mais conveniente.

A Listagem 3 apresenta um script simples do Ruby para recuperar as informações de um usuário (com base em seu nome de exibição) e, a seguir, emitir alguns dos elementos mais úteis. Use o método to_s do Ruby para converter o valor em uma cadeia de caractere, conforme necessário. Observe que primeiro é preciso assegurar-se de que o usuário não está protegido; caso contrário, esses dados não estarão acessíveis.

Listagem 3. Script simples para extrair dados do usuário do Twitter (user.rb)
#!/usr/bin/env ruby
require "rubygems"
require "twitter"

screen_name = String.new ARGV[0]

a_user = Twitter.user(screen_name)

if a_user.protected != true

  puts "Username   : " + a_user.screen_name.to_s
  puts "Name       : " + a_user.name
  puts "Id         : " + a_user.id_str
  puts "Location   : " + a_user.location
  puts "User since : " + a_user.created_at.to_s
  puts "Bio        : " + a_user.description.to_s
  puts "Followers  : " + a_user.followers_count.to_s
  puts "Friends    : " + a_user.friends_count.to_s
  puts "Listed Cnt : " + a_user.listed_count.to_s
  puts "Tweet Cnt  : " + a_user.statuses_count.to_s
  puts "Geocoded   : " + a_user.geo_enabled.to_s
  puts "Language   : " + a_user.lang
  puts "URL        : " + a_user.url.to_s
  puts "Time Zone  : " + a_user.time_zone
  puts "Verified   : " + a_user.verified.to_s
  puts

  tweet = Twitter.user_timeline(screen_name).first

  puts "Tweet time : " + tweet.created_at
  puts "Tweet ID   : " + tweet.id.to_s
  puts "Tweet text : " + tweet.text

end

Para chamar esse script, assegurando-se de que ele seja executável (chmod +x user.rb), ele é chamado com um usuário. O resultado é mostrado na Listagem 4 para o usuário developerworks , mostrando as informações do usuário e o status atual (últimas informações de tweet). Observe aqui que o Twitter define seguidores como pessoas que seguem você; mas pessoas que você segue são chamadas de amigos.

Listagem 4. Amostra de saída de user.rb
$ ./user.rb developerworks
Username   : developerworks
Name       : developerworks
Id         : 16362921
Location   : 
User since : Fri Sep 19 13:10:39 +0000 2008
Bio        : IBM's premier Web site for Java, Android, Linux, Open Source, PHP, Social, 
Cloud Computing, Google, jQuery, and Web developer educational resources
Followers  : 48439
Friends    : 46299
Listed Cnt : 3801
Tweet Cnt  : 9831
Geocoded   : false
Language   : en
URL        : http://bit.ly/EQ7te
Time Zone  : Pacific Time (US & Canada)
Verified   : false

Tweet time : Sun Jul 17 01:04:46 +0000 2011
Tweet ID   : 92399309022167040
Tweet text : dW Twitter is saving #IBM over $600K per month: will #Google+ add to that? > 
http://t.co/HiRwir7 #Tech #webdesign #Socialmedia #webapp #app

Popularidade dos amigos

Veja seus amigos (pessoas que você segue) e reúna dados para entender sua popularidade. Nesse caso, você reúne seus amigos e os classifica na ordem de suas contagens de seguidores. Esse script simples é mostrado na Listagem 5.

Nesse script, depois de entender o usuário que deseja analisar (com base em seu nome de exibição), você cria um hash de usuário. Um hash do Ruby (ou array associativo) é uma estrutura de dados que permite definir a chave para armazenamento (em vez de um índice numérico simples). Seu hash, então, é indexado pelo nome de exibição do Twitter e o valor associado é a contagem de seguidores do usuário. O processo é simplesmente para iterar seus amigos e fazer hash de suas contagens de seguidores. Classifique seu hash (em ordem descendente) e emita-o como saída.

Listagem 5. Script de popularidade dos amigos (friends.rb)
#!/usr/bin/env ruby
require "rubygems"
require "twitter"

name = String.new ARGV[0]

user = Hash.new

# Iterate friends, hash their followers
Twitter.friends(name).users.each do |f|

  # Only iterate if we can see their followers
  if (f.protected.to_s != "true") 
    user[f.screen_name.to_s] = f.followers_count 
  end

enduser.sort_by {|k,v| -v}.each { |user, count| puts "#{user}, #{count}" }

A amostra de saída do script friends na Listagem 5 é mostrada na Listagem 6. Cortei a saída para economizar espaço, mas, como pode ser visto, ReadWriteWeb (RWW) e Playstation são usuários populares do Twitter em minha rede direta.

Listagem 6. Saída da tela do script friends na Listagem 5
$ ./friends.rb MTimJones
RWW, 1096862
PlayStation, 1026634
HarvardBiz, 541139
tedtalks, 526886
lifehacker, 146162
wandfc, 121683
AnonymousIRC, 117896
iTunesPodcasts, 82581
adultswim, 76188
forrester, 72945
googleresearch, 66318
Gartner_inc, 57468
developerworks, 48518

Onde estão meus seguidores?

Lembre-se da listagem 2 que o Twitter fornece uma variedade de informações de localização. Há um campo de localização que tem formato livre, definido pelo usuário, e dados de codificação geográfica opcionais. No entanto, um fuso horário definido pelo usuário também pode fornecer uma dica sobre a localização real do seguidor.

Nesse exemplo, você criará um mash-up que extrai dados de fuso horário de seus seguidores do Twitter e, a seguir, visualiza esses dados usando Google Charts. O Google Charts é um projeto interessante que permite criar uma variedade de tipos diferentes de gráficos na Web definindo o tipo de gráfico e os dados como uma solicitação de HTTP, onde o resultado é renderizado diretamente no navegador como resposta. Para instalar o gem do Ruby para o Google Charts, use a seguinte linha de comando:

$ gem install gchartrb

A Listagem 7 fornece o script para extrair dados de fuso horário e, a seguir, criar a solicitação para o Google Charts. Primeiro, diferentemente de scripts anteriores, esse script requer que você esteja autenticado no Twitter. Para tanto, é preciso registrar um aplicativo no Twitter, o que fornece um conjunto de chaves e tokens. Esses tokens podem ser aplicados ao script na Listagem 7 para extrair os dados com sucesso. Consulte a seção Recursos para obter detalhes sobre esse processo fácil.

Seguindo um padrão similar, esse script aceita um nome de exibição e, a seguir, percorre os seguidores daquele usuário. O fuso horário é extraído do seguidor atual e armazenado no hash tweetlocation . Observe que primeiro você testa se essa chave está no hash e, se estiver, incrementa o contador para aquela chave. Você também mantém uma guia com o número total de fusos horários para a criação posterior de porcentagens.

A última porção do script é a criação da URL do gráfico de setores circulares do Google. Você cria um novo PieChart e especifica algumas opções (tamanho, título e se ele é 3D). A seguir, você percorre o hash de fuso horário, emitindo dados da cadeia de caractere do fuso horário para o gráfico (removendo o símbolo & ) e a porcentagem do fuso horário do total.

Listagem 7. Criação de um gráfico de setores circulares a partir dos fusos horários dos seguidores do Twitter (followers-location.rb)
#!/usr/bin/env ruby
require "rubygems"
require "twitter"
require 'google_chart'

screen_name = String.new ARGV[0]

tweetlocation = Hash.new
timezones = 0.0

# Authenticate
Twitter.configure do |config|
  config.consumer_key = '<consumer_key>'
  config.consumer_secret = '<consumer_secret>'
  config.oauth_token = <oauth_token>'
  config.oauth_token_secret = '<oauth_token_secret>'
end

# Iterate followers, hash their location
followers = Twitter.followers.users.each do |f|

  loc = f.time_zone.to_s

  if (loc.length > 0)

    if tweetlocation.has_key?(loc)
      tweetlocation[loc] = tweetlocation[loc] + 1
    else
      tweetlocation[loc] = 1
    end

    timezones = timezones + 1.0

  endend# Create a pie chart
GoogleChart::PieChart.new('650x350', "Time Zones", false ) do |pc|

  tweetlocation.each do |loc,count|
    pc.data loc.to_s.delete("&"), (count/timezones*100).round
  end

  puts pc.to_url

end

Para executar o script da Listagem 7, forneça a ele um nome de exibição do Twitter e, a seguir, copie e cole a URL resultante em um navegador. A Listagem 8 mostra esse processo com a URL gerada resultante.

Listagem 8. Chamada do script followers-location (o resultado é uma única linha)
$ ./followers-location.rb MTimJones
http://chart.apis.google.com/chart?chl=Seoul|Santiago|Paris|Mountain+Time+(US++Canada)|
Madrid|Central+Time+(US++Canada)|Warsaw|Kolkata|London|Pacific+Time+(US++Canada)|
New+Delhi|Pretoria|Quito|Dublin|Moscow|Istanbul|Taipei|Casablanca|Hawaii|Mumbai|
International+Date+Line+West|Tokyo|Ulaan+Bataar|Vienna|Osaka|Alaska|Chennai|Bern|
Brasilia|Eastern+Time+(US++Canada)|Rome|Perth|La+Paz
&chs=650x350&chtt=Time+Zones&chd=s:KDDyKcKDOcKDKDDDDDKDDKDDDDOKK9DDD&cht=p
$

Ao colar a URL da Listagem 8 em um navegador, você obtém o resultado mostrado na figura 1.

Figura 1. Gráfico de setores circulares das localizações dos seguidores do Twitter
Gráfico de setores circulares das localizações dos seguidores do Twitter

Comportamento do usuário do Twitter

O Twitter contém um grande volume de dados que podem ser minerados para entender alguns elementos do comportamento dos usuários. Dois exemplos simples são analisá-los quando um usuário do Twitter enviar um tweet e de que aplicativo o usuário enviou o tweet. É possível usar os seguintes dois scripts simples para extrair e visualizar essas informações.

A Listagem 9 apresenta um script que percorre os tweets de um usuário particular (usando o método user_timeline ) e, a seguir, para cada tweet, extrai o dia particular no qual o tweet foi originado. Use um hash simples novamente para acumular as contagens dos dias da semana e, a seguir, gere um gráfico de barras usando o Google Charts de forma similar ao exemplo anterior do fuso horário.

Listagem 9. Criação de um gráfico de barras dos dias de tweet (tweet-days.rb)
#!/usr/bin/env ruby
require "rubygems"
require "twitter"
require "google_chart"

screen_name = String.new ARGV[0]

dayhash = Hash.new

timeline = Twitter.user_timeline(screen_name, :count => 200 )
timeline.each do |t|

  tweetday = t.created_at.to_s[0..2]

  if dayhash.has_key?(tweetday)
    dayhash[tweetday] = dayhash[tweetday] + 1
  else
    dayhash[tweetday] = 1
  end

endGoogleChart::BarChart.new('300x200', screen_name, :vertical, false) do |bc|
  bc.data "Sunday", [dayhash["Sun"]], '00000f'
  bc.data "Monday", [dayhash["Mon"]], '0000ff'
  bc.data "Tuesday", [dayhash["Tue"]], '00ff00'
  bc.data "Wednesday", [dayhash["Wed"]], '00ffff'
  bc.data "Thursday", [dayhash["Thu"]], 'ff0000'
  bc.data "Friday", [dayhash["Fri"]], 'ff00ff'
  bc.data "Saturday", [dayhash["Sat"]], 'ffff00'
  puts bc.to_url
end

A figura 2 fornece o resultado da execução do script tweet-days na Listagem 9 para a conta developerWorks. Como mostrado, quarta-feira tende a ser o dia mais ativo de tweets, com sábado e domingo sendo os menos ativos.

Figura 2. Gráfico de barras relativo da atividade de tweets por dia
Gráfico de barras relativo da atividade de tweets por dia

O próximo script determina de que origem um usuário particular envia tweets. Há várias formas de enviar tweets e esse script não codifica todos eles. Como mostra a Listagem 10, use um padrão similar para extrair a linha de tempo para um dado usuário e, a seguir, tente decodificar a origem do tweet em um hash. Use o hash posteriormente para criar um gráfico de setores circulares simples usando o Google Charts para visualizar os dados.

Listagem 10. Criação de um gráfico de setores circulares das origens dos tweets de um usuário (tweet-source.rb)
#!/usr/bin/env ruby
require "rubygems"
require "twitter"
require 'google_chart'

screen_name = String.new ARGV[0]

tweetsource = Hash.new

timeline = Twitter.user_timeline(screen_name, :count => 200 )
timeline.each do |t|

  if (t.source.rindex('blackberry')) then
    src = 'Blackberry'
  elsif (t.source.rindex('snaptu')) then
    src = 'Snaptu'
  elsif (t.source.rindex('tweetmeme')) then
    src = 'Tweetmeme'
  elsif (t.source.rindex('android')) then
    src = 'Android'
  elsif (t.source.rindex('LinkedIn')) then
    src = 'LinkedIn'
  elsif (t.source.rindex('twitterfeed')) then
    src = 'Twitterfeed'
  elsif (t.source.rindex('twitter.com')) then
    src = 'Twitter.com'
  else
    src = t.source
  end

  if tweetsource.has_key?(src)
    tweetsource[src] = tweetsource[src] + 1
  else
    tweetsource[src] = 1
  end

endGoogleChart::PieChart.new('320x200', "Tweet Source", false) do |pc|

  tweetsource.each do|source,count|
    pc.data source.to_s, count
  end

  puts "\nPie Chart"
  puts pc.to_url
end

A figura 3 fornece uma visualização de um usuário no Twitter que tem um conjunto interessante de origens de tweets. O Web site tradicional do Twitter é usado com mais frequência, com um aplicativo para celular a seguir.

Figura 3. Gráfico de setores circulares das fontes de tweet de um usuário do Twitter
Gráfico de setores circulares das fontes de tweet de um usuário do Twitter

Gráfico de seguidores

O Twitter é uma imensa rede de usuários que forma um gráfico. Como visto nos scripts, é fácil percorrer seus contatos e, a seguir, percorrer os contatos deles. Isso forma a base de um grande gráfico, mesmo nesse nível.

Para visualizar um gráfico, escolhi usar o software de visualização de gráficos GraphViz. No Ubuntu, é possível instalar facilmente essa ferramenta usando a seguinte linha de comando:

$ sudo apt-get install graphviz

O script mostrado na Listagem 11 percorre os seguidores de um usuário e, a seguir percorre os seguidores deles. A única diferença real nesse padrão é a criação do arquivo formatado com pontos do GraphViz. O GraphViz usa um formato de script simples para definir gráficos, que você emitirá como parte de sua enumeração dos usuários do Twitter. Como mostrado, você define um gráfico simplesmente especificando os relacionamentos dos nós.

Listagem 11. Visualização de um gráfico de seguidores do Twitter (followers-graph.rb)
#!/usr/bin/env ruby
require "rubygems"
require "twitter"
require 'google_chart'

screen_name = String.new ARGV[0]

tweetlocation = Hash.new

# Authenticate
Twitter.configure do |config|
  config.consumer_key = '<consumer_key>'
  config.consumer_secret = '<consumer_secret>'
  config.oauth_token = '<oauth_token>'
  config.oauth_token_secret = '<oauth_token_secret>'
end

my_file = File.new("graph.dot", "w")

my_file.puts "graph followers {"
my_file.puts "  node [ fontname=Arial, fontsize=6 ];"

# Iterate followers, hash their location
followers = Twitter.followers(screen_name, :count=>10 ).users.each do |f|

  # Only iterate if we can see their followers
  if (f.protected.to_s != "true")

    my_file.puts "  \"" + screen_name + "\" -- \"" + f.screen_name.to_s + "\""

    followers2 = Twitter.followers(f.screen_name, :count =>10 ).users.each do |f2|

      my_file.puts "    \"" + f.screen_name.to_s + "\" -- \"" +
                    f2.screen_name.to_s + "\""

    endendendmy_file.puts "}"

Execute o script da Listagem 11 nos resultados de um usuário em um arquivo dot para, a seguir, gerar uma imagem usando o GraphViz. Primeiro, chame o script do Ruby para reunir os dados do gráfico (armazenado como graph.dot); depois, use o GraphViz para gerar a imagem do gráfico (aqui, usando circo, que especifica um layout circular). O processo de geração dessa imagem é definido da seguinte forma:

$ ./followers-graph.rb MTimJones
$ circo graph.dot -Tpng -o graph.png

A imagem resultante é mostrada na figura 4. Observe que os gráficos do Twitter tendem a ser grandes, portanto restringi o gráfico ao minimizar o número de usuários e seus seguidores a enumerar (conforme a opção :count na Listagem 11).

Figura 4. Amostra do gráfico de seguidores do Twitter (subconjunto extremo)
Amostra do gráfico de seguidores do Twitter (subconjunto extremo)

Informações de localização

Quando ativado, o Twitter coleta dados de geolocalização sobre você e seus tweets. Esses dados consistem em informações de latitude e longitude que podem ser usadas para determinar um usuário ou de onde um tweet foi originado. Além disso, pesquisas podem incorporar essas informações para que possa identificar locais ou pessoas com base em uma localização definida ou em sua localização.

Nem todos os usuários ou tweets têm dados de geolocalização ativados (por questões de privacidade), mas essas informações servem como uma dimensão interessante para a experiência geral do Twitter. Vejamos um script que permite visualizar com dados de geolocalização, bem como outro que permite pesquisar com essas informações.

No primeiro script (mostrado na Listagem 12), você obtém dados de latitude e longitude de um usuário (lembre-se da caixa delimitadora da listagem 2). Apesar de a caixa delimitadora ser um polígono definindo a área representada para o usuário, simplifiquei e usei um ponto desses dados. Com esses dados, gerei uma função JavaScript simples em um arquivo HTML simples. Esse código JavaScript interage com o Google Maps para apresentar um mapa superior dessa localização (com os dados de latitude e longitude extraídos do usuário do Twitter).

Listagem 12. Script do Ruby para criar um mapa de um usuário (where-am-i.rb)
#!/usr/bin/env ruby
require "rubygems"
require "twitter"

Twitter.configure do |config|
  config.consumer_key = '<consumer_key>
  config.consumer_secret = '<consumer_secret>
  config.oauth_token = '<oauth_token>
  config.oauth_token_secret = '<token_secret>
end

screen_name = String.new ARGV[0]

a_user = Twitter.user(screen_name)

if a_user.geo_enabled == true

  long = a_user.status.place.bounding_box.coordinates[0][0][0];
  lat  = a_user.status.place.bounding_box.coordinates[0][0][1];

  my_file = File.new("test.html", "w")

  my_file.puts "<!DOCTYPE html>
  my_file.puts "<html><head>
  my_file.puts "<meta name=\"viewport\" content=\"initial-scale=1.0, user-scalable=no\"/>"
  my_file.puts "<style type=\"text/css\">"
  my_file.puts "html { height: 100% }"
  my_file.puts "body { height: 100%; margin: 0px; padding: 0px }"
  my_file.puts "#map_canvas { height: 100% }"
  my_file.puts "</style>"
  my_file.puts "<script type=\"text/javascript\""
  my_file.puts "src=\"http://maps.google.com/maps/api/js?sensor=false\">"
  my_file.puts "</script>"
  my_file.puts "<script type=\"text/javascript\">"
  my_file.puts "function initialize() {"
  my_file.puts "var latlng = new google.maps.LatLng(" + lat.to_s + ", " + long.to_s + ");"
  my_file.puts "var myOptions = {"
  my_file.puts "zoom: 12,"
  my_file.puts "center: latlng,"
  my_file.puts "mapTypeId: google.maps.MapTypeId.HYBRID"
  my_file.puts "};"
  my_file.puts "var map = new google.maps.Map(document.getElementById(\"map_canvas\"),"
  my_file.puts "myOptions);"
  my_file.puts "}"
  my_file.puts "</script>"
  my_file.puts "</head>"
  my_file.puts "<body onload=\"initialize()\">"
  my_file.puts "<div id=\"map_canvas\" style=\"width:100%; height:100%\"></div>"
  my_file.puts "</body>"
  my_file.puts "</html>"

elseputs "no geolocation data available."

end

O script na Listagem 12 é executado simplesmente como :

$ ./where-am-i.rb MTimJones

O arquivo HTML resultante é renderizado por meio de um navegador, como:

$ firefox test.html

Esse script pode falhar se não houver informações de localização disponíveis; mas, se ele for bem-sucedido, é gerado um arquivo HTML que pode ser lido por um navegador para renderizar o mapa. A figura 5 apresenta a imagem resultante do mapa, que mostra uma porção de Front Range do norte do Colorado, EUA.

Figura 5. Amostra de imagem renderizada a partir do script na Listagem 12
Amostra de imagem renderizada a partir do script na Listagem 12

Com a geolocalização, também é possível pesquisar o Twitter para identificar usuários e tweets relacionados a uma localização particular. A API Search do Twitter permite que informações de codificação geográfica restrinjam seus resultados. O exemplo seguinte, mostrado na Listagem 13 , extrai dados de latitude e longitude para um usuário e, a seguir, usa esses dados para buscar tweets dentro de um raio de 5 milhas daquele local.

Listagem 13. Busca de tweets locais com dados de latitude e longitude (tweets-local.rb)
#!/usr/bin/env ruby
require "rubygems"
require "twitter"

Twitter.configure do |config|
  config.consumer_key = '<consumer_key>'
  config.consumer_secret = '<consumer_secret>'
  config.oauth_token = '<oauth_token>'
  config.oauth_token_secret = '<oauth_token_secret>'
end

screen_name = String.new ARGV[0]

a_user = Twitter.user(screen_name)

if a_user.geo_enabled == true

  long = a_user.status.place.bounding_box.coordinates[0][0][0]
  lat  = a_user.status.place.bounding_box.coordinates[0][0][1]

  Array tweets = Twitter::Search.new.geocode(lat, long, "5mi").fetch

  tweets.each do |t|

    puts t.from_user + " | " + t.text

  endend

O resultado do script na Listagem 13 é mostrado na Listagem 14. Esse é um subconjunto dos tweets, dada a frequência de tweeters que existe.

Listagem 14. Visualização de tweets locais dentro de 5 milhas de minha localização
$ ./tweets-local.rb MTimJones
Breesesummer | @DaltonOls did he answer u
LongmontRadMon | 60 CPM, 0.4872 uSv/h, 0.6368 uSv/h, 2 time(s) over natural radiation
graelston | on every street there is a memory; a time and place we can never be again.
Breesesummer | #I'minafight with @DaltonOls to see who will marry @TheCodySimpson I will 
marry him!!! :/
_JennieJune_ | ok I'm done, goodnight everyone!
Breesesummer | @DaltonOls same
_JennieJune_ | @sylquejr sleep well!
Breesesummer | @DaltonOls ok let's see what he says
LongmontRadMon | 90 CPM, 0.7308 uSv/h, 0.7864 uSv/h, 2 time(s) over natural radiation
Breesesummer | @TheCodySimpson would u marry me or @DaltonOls
natcapsolutions | RT hlovins: The scientific rebuttal to the silly Forbes release this 
morning: Misdiagnosis of Surface Temperatu... http://bit.ly/nRpLJl
$

Indo além

Esse artigo apresentou uma série de scripts simples para extração de dados do Twitter usando a linguagem Ruby. A ênfase foi no desenvolvimento e apresentação de scripts simples para ilustrar as ideias fundamentais, mas é possível fazer muito mais. Por exemplo, também é possível usar a API para explorar as redes de seus amigos e identificar os usuários mais populares do Twitter que sejam de seu interesse. Outra área interessante é a mineração dos tweets em si, usando dados de geolocalização para entender comportamentos ou eventos com base em localização (como epidemias de gripes). Esse artigo apenas introduziu o tema, mas sinta-se à vontade para comentar com seus próximos mash-ups. O Ruby e o gem do Twitter torna simples desenvolver mash-ups ou painéis úteis para suas necessidades de mineração de dados.

Recursos

Aprender

  • Web site oficial da linguagem é a fonte isolada para notícias, informações, releases, documentação e suporte da comunidade da linguagem Ruby. Dado o crescente uso do Ruby em estruturas da Web (como Ruby on Rails), também é possível conhecer as mais recentes vulnerabilidades de segurança e suas soluções.
  • O site de codificação social Github fornece a fonte original do gem do Twitter. Nesse site, é possível acessar o código fonte, a documentação e a lista de distribuição do gem do Twitter para o Ruby.
  • Registrar um aplicativo do Twitter é necessário para usar certos elementos da API do Twitter. O processo é gratuito e permite acessar alguns dos elementos mais úteis da API.
  • O tutorial da API JavaScript do Google Maps mostra como usar o Google Maps para renderizar mapas de vários tipos usando dados de geolocalização fornecidas pelo usuário. O JavaScript usado nesse artigo foi baseado no código de exemplo "Hello World" fornecido.
  • Zona de software livre do developerWorks fornece muitas informações sobre ferramentas de software livre e de como utilizar tecnologias de software livre.
  • developerWorks no Twitter: Siga-nos e siga esse autor em M. Tim Jones.
  • Demos on demand do developerWorks: acompanhe e saiba com demos que vão da instalação de produtos e de configuração para iniciantes a funcionalidades avançadas para desenvolvedores experientes.

Obter produtos e tecnologias

  • O gem do Twitter para Ruby , desenvolvido por John Nunemaker, fornece uma interface útil para o serviço Twitter que se integra de forma eficiente na linguagem Ruby.
  • A API Google Chart é um serviço útil que fornece a capacidade de criar gráficos ricos e complexos usando uma variedade de estilos e opções. Esse serviço fornece uma API por meio da qual resulta uma URL que é renderizada no site do Google.
  • O wrapper do Ruby para a API Google Chart fornece uma interface do Ruby para a API Google Charts pra a criação de gráficos úteis dentro do Ruby.
  • Avalie os produtos IBM da maneira que for melhor para você: faça download da versão de teste de um produto, avalie um produto on-line, use-o em um ambiente de nuvem ou passe algumas horas na SOA Sandbox aprendendo a implementar de forma eficiente a arquitetura orientada a serviços.

Discutir

  • comunidade do developerWorks: Conecte-se a outros usuários do developerWorks enquanto explora os blogs, fóruns, grupos e wikis voltados para desenvolvedores.

Comentários

developerWorks: Conecte-se

Los campos obligatorios están marcados con un asterisco (*).


Precisa de um ID IBM?
Esqueceu seu ID IBM?


Esqueceu sua senha?
Alterar sua senha

Ao clicar em Enviar, você concorda com os termos e condições do developerWorks.

 


A primeira vez que você entrar no developerWorks, um perfil é criado para você. Informações no seu perfil (seu nome, país / região, e nome da empresa) é apresentado ao público e vai acompanhar qualquer conteúdo que você postar, a menos que você opte por esconder o nome da empresa. Você pode atualizar sua conta IBM a qualquer momento.

Todas as informações enviadas são seguras.

Elija su nombre para mostrar



Ao se conectar ao developerWorks pela primeira vez, é criado um perfil para você e é necessário selecionar um nome de exibição. O nome de exibição acompanhará o conteúdo que você postar no developerWorks.

Escolha um nome de exibição de 3 - 31 caracteres. Seu nome de exibição deve ser exclusivo na comunidade do developerWorks e não deve ser o seu endereço de email por motivo de privacidade.

Los campos obligatorios están marcados con un asterisco (*).

(Escolha um nome de exibição de 3 - 31 caracteres.)

Ao clicar em Enviar, você concorda com os termos e condições do developerWorks.

 


Todas as informações enviadas são seguras.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=80
Zone=Software livre
ArticleID=765898
ArticleTitle=Mineração de dados com Ruby e Twitter
publish-date=10192011