Universidad de Oviedo   Programa de extensión universitaria




     CLOUD COMPUTING.
DESARROLLO DE APLICACIONES Y
        MINERÍA WEB


                               Miguel Fernández Fernández
                                miguelff@innova.uniovi.es
Screen scraping
Porqué screen scraping
  La Web es fundamentalmente para
         humanos (HTML)
Porqué screen scraping
  La Web es fundamentalmente para
         humanos (HTML)
Porqué screen scraping
                  La Web es fundamentalmente para
                         humanos (HTML)
<table width="100%" cellspacing="1" cellpadding="1" border="0" align="center">
<tbody>
          <tr>
            <td valign="middle" align="center" colspan="5">
          </td></tr><tr>
            <td align="center" class="cabe"> Hora Salida </td>
            <td align="center" class="cabe"> Hora Llegada </td>
            <td align="center" class="cabe"> Línea </td>
            <td align="center" class="cabe"> Tiempo de Viaje </td>
            <td align="center" class="cabe"> </td>
          </tr>

           <tr>
...
             <td   align="center" class="color1">06.39</td>
             <td   align="center" class="color2">07.15</td>
             <td   class="color3">C1 </td>
             <td   align="center" class="color1">0.36</td>
             <td   align="center" class="rojo3"> </td>
           </tr>
</tbody>
Porqué screen scraping
  La Web es fundamentalmente para
         humanos (HTML)
Porqué screen scraping
   La Web es fundamentalmente para
          humanos (HTML)

Pero no está diseñada para ser procesada
   por máquinas (XML, JSON, CSV...)
Porqué screen scraping
    La Web es fundamentalmente para
           humanos (HTML)

Pero no está diseñada para ser procesada
   por máquinas (XML, JSON, CSV...)

<horario>
    <viaje>
        <salida format="hh:mm">06:39</salida>
        <llegada format="hh:mm">07:15</llegada>
        <duracion format="minutes">36</duracion>
        <linea>C1</linea>
    </viaje>
</horario>
Porqué screen scraping
 No siempre disponemos de una API
Porqué screen scraping
    No siempre disponemos de una API




Necesitamos simular el comportamiento humano
Porqué screen scraping
    No siempre disponemos de una API




Necesitamos simular el comportamiento humano


 Interpretar
    HTML
Porqué screen scraping
    No siempre disponemos de una API




Necesitamos simular el comportamiento humano


                   Realizar
 Interpretar
                interacciones
    HTML
                  (Navegar)
Porqué screen scraping
    No siempre disponemos de una API




Necesitamos simular el comportamiento humano


                   Realizar
 Interpretar
                interacciones   Ser un Ninja
    HTML
                  (Navegar)
                                           Evitar DoS
Selección de las herramientas
                ¿Con qué lenguaje vamos a trabajar?

                      Java                   .NET               Ruby           Python

                                                                net/http
   URL                                    System.Net.                           urllib
                  java.net.URL                                 open-uri
 fetching                               HTTPWebRequest                          urllib2
                                                             rest-open-uri
    DOM         javax.swing.text.html                        HTree / ReXML
   parsing          TagSoup
      /
                                        HTMLAgilityPack         HPricot      BeautifulSoup
                   NekoHTML                                   RubyfulSoup
transversing


                                           System.Text.
 Regexp         java.util.regexp        RegularExpressions
                                                                Regexp            re


  --- Librerías de terceras partes. No forman parte de la API del lenguaje.
Selección de las herramientas


       ¿Con qué lenguaje vamos a trabajar?



    Duck typing + Reflexión = Syntactic Sugar
Selección de las herramientas


       ¿Con qué lenguaje vamos a trabajar?

      Lenguajes dinámicos facilitan la codificación


    Duck typing + Reflexión = Syntactic Sugar
Java
import     javax.swing.text.html.*;
import     javax.swing.text.Element;
import     javax.swing.text.ElementIterator;
import     java.net.URL;
import     java.io.InputStreamReader;
import     java.io.Reader;

public class HTMLParser
{
  public static void main( String[] argv ) throws Exception
  {
    URL url = new URL( "http://java.sun.com" );
    HTMLEditorKit kit = new HTMLEditorKit();
    HTMLDocument doc = (HTMLDocument) kit.createDefaultDocument();
    doc.putProperty("IgnoreCharsetDirective", Boolean.TRUE);
    Reader HTMLReader = new InputStreamReader(url.openConnection().getInputStream());
    kit.read(HTMLReader, doc, 0);

        ElementIterator it = new ElementIterator(doc);
        Element elem;

        while( elem = it.next() != null )
        {
          if( elem.getName().equals( "img") )
          {
            String s = (String) elem.getAttributes().getAttribute(HTML.Attribute.SRC);
            if( s != null )
              System.out.println (s );
          }
        }
        System.exit(0);
    }
}
Ruby
require   'rubygems'
require   'open-uri'
require   'htree'
require   'rexml/document'

 open("http://java.sun.com",:proxy=>"http://localhost:8080") do |page|
     page_content = page.read()
     doc = HTree(page_content).to_rexml
     doc.root.each_element('//img') {|elem| puts elem.attribute('src').value }
 end
Selección de las herramientas                  Ruby
 rest-open-uri
                 Nos permitirá hacer peticiones a
HTree + REXML     URLs y extraer su contenido
    Hpricot
                 extiende open-uri para soportar
  RubyfulSoup              más verbos
WWW:Mechanize
Selección de las herramientas                 Ruby
                  HTree crea un árbol de
 rest-open-uri   objetos a partir de código
                           HTML
HTree + REXML

    Hpricot
                    HTree#to_rexml
                 Convierte el árbol a un árbol
  RubyfulSoup              REXML
WWW:Mechanize    REXML puede navegarse con
                        XPath 2.0
HTree+REXML
require   'rubygems'
require   'open-uri'
require   'htree'
require   'rexml/document'

 open("http://www.google.es/search?q=ruby",:proxy=>"http://localhost:8080") do |page|
     page_content = page.read()
     doc = HTree(page_content).to_rexml
     doc.root.each_element('//a[@class=l]') {|elem| puts elem.attribute('href').value }
 end




                                 Runtime: 7.06s.
Selección de las herramientas                         Ruby
                               Scanner implementado en C
 rest-open-uri
                                      (Muy rápido)
HTree + REXML
                             Genera un DOM con su
    Hpricot                propio sistema de navegación
  RubyfulSoup    como Jquery(selectores CSS y XPath*)

WWW:Mechanize                   Funcionalidad equivalente a
                                     Htree + REXML

                   http://hpricot.com/
HPricot

require 'rubygems'
require 'hpricot'
require 'open-uri'

doc = Hpricot(open('http://www.google.com/search?q=ruby',:proxy=>'http://localhost:8080'))
links = doc/"//a[@class=l]"
links.map.each {|link| puts link.attributes['href']}




                                  Runtime: 3.71s
Selección de las herramientas                         Ruby
                            Scanner implementado en C
 rest-open-uri
                                   (Muy rápido)
HTree + REXML
                             Genera un DOM con su
    Hpricot                propio sistema de navegación
  RubyfulSoup    co mo Jquery
                            (selectores CSS y XPath*)

WWW:Mechanize                   Funcionalidad equivalente a
                                     Htree + REXML

                  http://hpricot.com/
Selección de las herramientas                         Ruby
                            Scanner implementado en C
 rest-open-uri
                                   (Muy rápido)
    Hpricot
                             Genera un DOM con su
  RubyfulSoup              propio sistema de navegación
WWW:Mechanize    co mo Jquery
                            (selectores CSS y XPath*)

                                Funcionalidad equivalente a
                                     Htree + REXML

                  http://hpricot.com/
Selección de las herramientas                Ruby
 rest-open-uri
                 Ofrece la misma funcionalidad que
    Hpricot              HTree + REXML
  RubyfulSoup

WWW:Mechanize
Rubyful Soup
require 'rubygems'
require 'rubyful_soup'
require 'open-uri'

open("http://www.google.com/search?q=ruby",:proxy=>"http://localhost:8080") do |page|
  page_content = page.read()
  soup = BeautifulSoup.new(page_content)
  result = soup.find_all('a', :attrs => {'class' => 'l'})
  result.each { |tag| puts tag['href'] }
end




                                Runtime: 4.71s
Selección de las herramientas                Ruby
 rest-open-uri
                 Ofrece la misma funcionalidad que
    Hpricot              HTree + REXML
  RubyfulSoup

WWW:Mechanize
Selección de las herramientas                Ruby
 rest-open-uri
                 Ofrece la misma funcionalidad que
    Hpricot              HTree + REXML
  RubyfulSoup     Menor rendimiento que Hpricot
WWW:Mechanize
Selección de las herramientas                Ruby
 rest-open-uri
                 Ofrece la misma funcionalidad que
    Hpricot              HTree + REXML
  RubyfulSoup     Menor rendimiento que Hpricot
WWW:Mechanize      No se admiten selectores CSS
Selección de las herramientas                Ruby
                 Ofrece la misma funcionalidad que
 rest-open-uri           HTree + REXML

   Hpricot        Menor rendimiento que Hpricot
WWW:Mechanize      No se admiten selectores CSS
Selección de las herramientas                      Ruby
                 Permite realizar interacciones
 rest-open-uri
                       Rellenar y enviar formularios
   Hpricot             Seguir enlaces

WWW:Mechanize    Consigue alcanzar documentos en
                 La Web Profunda
WWW::Mechanize
require 'rubygems'
require 'mechanize'

agent = Mechanize.new
agent.set_proxy("localhost",8080)
page = agent.get('http://www.google.com')

search_form = page.forms.select{|f| f.name=="f"}.first
search_form.fields.select {|f| f.name=='q'}.first.value="ruby"
search_results = agent.submit(search_form)
search_results.links.each { |link| puts link.href if link.attributes["class"] == "l" }




                                Runtime: 5.23s
Manos a la obra
No tiene API pública

>8000 usuarios nuevos cada día

   2h de sesión promedio

   datos datos datos!
Novedades de tuenti
Paso 1: Acceder a nuestro perfil
require 'rubygems'
require 'mechanize'

agent = Mechanize.new
agent.set_proxy("localhost",8080)
#decimos que somos firefox modificando la cabecera user agent
agent.user_agent_alias='Mac FireFox'
login_page = agent.get('http://m.tuenti.com/?m=login')

#cogemos el formulario de login
login_form = login_page.forms.first
#y rellenamos los campos usuario y contraseña
login_form.fields.select{|f| f.name=="email"}.first.value="miguelfernandezfernandez@gmail.com"
login_form.fields.select{|f| f.name=="input_password"}.first.value="xxxxx"

pagina_de_inicio?=agent.submit(login_form)
Redirecciona por Javascript
Segundo intento: versión móvil
       require 'rubygems'
       require 'mechanize'

       agent = Mechanize.new
       agent.set_proxy("localhost",8080)
       #decimos que somos firefox modificando la cabecera user agent
       agent.user_agent_alias='Mac FireFox'
       login_page = agent.get('http://m.tuenti.com/?m=login')

       #cogemos el formulario de login
       login_form = login_page.forms.first
       #y rellenamos los campos usuario y contraseña
       login_form.fields.select{|f|
       f.name=="tuentiemail"}.first.value="miguelfernandezfernandez@gmail.com
       "
       login_form.fields.select{|f| f.name=="password"}.first.value="xxxxxx"

       pagina_de_inicio=agent.submit(login_form)
Eureka!
require 'rubygems'
require 'mechanize'



class TuentiAPI

  def initialize(login,password)
    @login=login
    @password=password
  end

  def inicio()
    agent = Mechanize.new
    agent.set_proxy("localhost",8080)
    #decimos que somos firefox modificando la cabecera user agent
    agent.user_agent_alias='Mac FireFox'
    login_page = agent.get('http://m.tuenti.com/?m=login')

      #cogemos el formulario de login
      login_form = login_page.forms.first
      #y rellenamos los campos usuario y contraseña
      login_form.fields.select{|f| f.name=="tuentiemail"}.first.value=@login
      login_form.fields.select{|f| f.name=="password"}.first.value=@password

    pagina_de_inicio=agent.submit(login_form)
  end

end



pagina_de_inicio=TuentiAPI.new("miguelfernandezfernandez@gmail.com","xxxxxx").inicio()
Paso 2: Obtener las fotos
<div class=”box”>


<div class=”box”>


<div class=”box”>
Paso 2: Obtener las fotos
class TuentiAPI

...

  def fotos_nuevas()
     tree=Hpricot(inicio().content)
     fotos = tree / "//a//img[@alt=Foto]"
     fotos.map!{|foto| foto.attributes["src"]}
     Set.new(fotos).to_a
   end

  private

  def inicio()
  ...
  end
end
Paso 3: Establecer el estado
Paso 3: Establecer el estado


class TuentiAPI
   ...

      def actualizar_estado(msg)
        form_actualizacion=inicio.forms.first
        form_actualizacion.fields.select{|f| f.name=="status"}.first.value=msg
        @agent.submit(form_actualizacion)
      end

end
Ninja Moves
Tor: navegando de forma
        anónima
    Red de encadenamiento de proxies

   N peticiones salen de M servidores
    Garantiza el anonimato a nivel de IP




  https://www.torproject.org/vidalia/
Gracias
Universidad de Oviedo   Programa de extensión universitaria




     CLOUD COMPUTING.
DESARROLLO DE APLICACIONES Y
        MINERÍA WEB


                               Miguel Fernández Fernández
                                miguelff@innova.uniovi.es

Screen scraping

  • 1.
    Universidad de Oviedo Programa de extensión universitaria CLOUD COMPUTING. DESARROLLO DE APLICACIONES Y MINERÍA WEB Miguel Fernández Fernández miguelff@innova.uniovi.es
  • 2.
  • 3.
    Porqué screen scraping La Web es fundamentalmente para humanos (HTML)
  • 4.
    Porqué screen scraping La Web es fundamentalmente para humanos (HTML)
  • 5.
    Porqué screen scraping La Web es fundamentalmente para humanos (HTML) <table width="100%" cellspacing="1" cellpadding="1" border="0" align="center"> <tbody> <tr> <td valign="middle" align="center" colspan="5"> </td></tr><tr> <td align="center" class="cabe"> Hora Salida </td> <td align="center" class="cabe"> Hora Llegada </td> <td align="center" class="cabe"> Línea </td> <td align="center" class="cabe"> Tiempo de Viaje </td> <td align="center" class="cabe"> </td> </tr> <tr> ... <td align="center" class="color1">06.39</td> <td align="center" class="color2">07.15</td> <td class="color3">C1 </td> <td align="center" class="color1">0.36</td> <td align="center" class="rojo3"> </td> </tr> </tbody>
  • 6.
    Porqué screen scraping La Web es fundamentalmente para humanos (HTML)
  • 7.
    Porqué screen scraping La Web es fundamentalmente para humanos (HTML) Pero no está diseñada para ser procesada por máquinas (XML, JSON, CSV...)
  • 8.
    Porqué screen scraping La Web es fundamentalmente para humanos (HTML) Pero no está diseñada para ser procesada por máquinas (XML, JSON, CSV...) <horario> <viaje> <salida format="hh:mm">06:39</salida> <llegada format="hh:mm">07:15</llegada> <duracion format="minutes">36</duracion> <linea>C1</linea> </viaje> </horario>
  • 9.
    Porqué screen scraping No siempre disponemos de una API
  • 10.
    Porqué screen scraping No siempre disponemos de una API Necesitamos simular el comportamiento humano
  • 11.
    Porqué screen scraping No siempre disponemos de una API Necesitamos simular el comportamiento humano Interpretar HTML
  • 12.
    Porqué screen scraping No siempre disponemos de una API Necesitamos simular el comportamiento humano Realizar Interpretar interacciones HTML (Navegar)
  • 13.
    Porqué screen scraping No siempre disponemos de una API Necesitamos simular el comportamiento humano Realizar Interpretar interacciones Ser un Ninja HTML (Navegar) Evitar DoS
  • 14.
    Selección de lasherramientas ¿Con qué lenguaje vamos a trabajar? Java .NET Ruby Python net/http URL System.Net. urllib java.net.URL open-uri fetching HTTPWebRequest urllib2 rest-open-uri DOM javax.swing.text.html HTree / ReXML parsing TagSoup / HTMLAgilityPack HPricot BeautifulSoup NekoHTML RubyfulSoup transversing System.Text. Regexp java.util.regexp RegularExpressions Regexp re --- Librerías de terceras partes. No forman parte de la API del lenguaje.
  • 15.
    Selección de lasherramientas ¿Con qué lenguaje vamos a trabajar? Duck typing + Reflexión = Syntactic Sugar
  • 16.
    Selección de lasherramientas ¿Con qué lenguaje vamos a trabajar? Lenguajes dinámicos facilitan la codificación Duck typing + Reflexión = Syntactic Sugar
  • 17.
    Java import javax.swing.text.html.*; import javax.swing.text.Element; import javax.swing.text.ElementIterator; import java.net.URL; import java.io.InputStreamReader; import java.io.Reader; public class HTMLParser { public static void main( String[] argv ) throws Exception { URL url = new URL( "http://java.sun.com" ); HTMLEditorKit kit = new HTMLEditorKit(); HTMLDocument doc = (HTMLDocument) kit.createDefaultDocument(); doc.putProperty("IgnoreCharsetDirective", Boolean.TRUE); Reader HTMLReader = new InputStreamReader(url.openConnection().getInputStream()); kit.read(HTMLReader, doc, 0); ElementIterator it = new ElementIterator(doc); Element elem; while( elem = it.next() != null ) { if( elem.getName().equals( "img") ) { String s = (String) elem.getAttributes().getAttribute(HTML.Attribute.SRC); if( s != null ) System.out.println (s ); } } System.exit(0); } }
  • 18.
    Ruby require 'rubygems' require 'open-uri' require 'htree' require 'rexml/document' open("http://java.sun.com",:proxy=>"http://localhost:8080") do |page| page_content = page.read() doc = HTree(page_content).to_rexml doc.root.each_element('//img') {|elem| puts elem.attribute('src').value } end
  • 19.
    Selección de lasherramientas Ruby rest-open-uri Nos permitirá hacer peticiones a HTree + REXML URLs y extraer su contenido Hpricot extiende open-uri para soportar RubyfulSoup más verbos WWW:Mechanize
  • 20.
    Selección de lasherramientas Ruby HTree crea un árbol de rest-open-uri objetos a partir de código HTML HTree + REXML Hpricot HTree#to_rexml Convierte el árbol a un árbol RubyfulSoup REXML WWW:Mechanize REXML puede navegarse con XPath 2.0
  • 21.
    HTree+REXML require 'rubygems' require 'open-uri' require 'htree' require 'rexml/document' open("http://www.google.es/search?q=ruby",:proxy=>"http://localhost:8080") do |page| page_content = page.read() doc = HTree(page_content).to_rexml doc.root.each_element('//a[@class=l]') {|elem| puts elem.attribute('href').value } end Runtime: 7.06s.
  • 22.
    Selección de lasherramientas Ruby Scanner implementado en C rest-open-uri (Muy rápido) HTree + REXML Genera un DOM con su Hpricot propio sistema de navegación RubyfulSoup como Jquery(selectores CSS y XPath*) WWW:Mechanize Funcionalidad equivalente a Htree + REXML http://hpricot.com/
  • 23.
    HPricot require 'rubygems' require 'hpricot' require'open-uri' doc = Hpricot(open('http://www.google.com/search?q=ruby',:proxy=>'http://localhost:8080')) links = doc/"//a[@class=l]" links.map.each {|link| puts link.attributes['href']} Runtime: 3.71s
  • 24.
    Selección de lasherramientas Ruby Scanner implementado en C rest-open-uri (Muy rápido) HTree + REXML Genera un DOM con su Hpricot propio sistema de navegación RubyfulSoup co mo Jquery (selectores CSS y XPath*) WWW:Mechanize Funcionalidad equivalente a Htree + REXML http://hpricot.com/
  • 25.
    Selección de lasherramientas Ruby Scanner implementado en C rest-open-uri (Muy rápido) Hpricot Genera un DOM con su RubyfulSoup propio sistema de navegación WWW:Mechanize co mo Jquery (selectores CSS y XPath*) Funcionalidad equivalente a Htree + REXML http://hpricot.com/
  • 26.
    Selección de lasherramientas Ruby rest-open-uri Ofrece la misma funcionalidad que Hpricot HTree + REXML RubyfulSoup WWW:Mechanize
  • 27.
    Rubyful Soup require 'rubygems' require'rubyful_soup' require 'open-uri' open("http://www.google.com/search?q=ruby",:proxy=>"http://localhost:8080") do |page| page_content = page.read() soup = BeautifulSoup.new(page_content) result = soup.find_all('a', :attrs => {'class' => 'l'}) result.each { |tag| puts tag['href'] } end Runtime: 4.71s
  • 28.
    Selección de lasherramientas Ruby rest-open-uri Ofrece la misma funcionalidad que Hpricot HTree + REXML RubyfulSoup WWW:Mechanize
  • 29.
    Selección de lasherramientas Ruby rest-open-uri Ofrece la misma funcionalidad que Hpricot HTree + REXML RubyfulSoup Menor rendimiento que Hpricot WWW:Mechanize
  • 30.
    Selección de lasherramientas Ruby rest-open-uri Ofrece la misma funcionalidad que Hpricot HTree + REXML RubyfulSoup Menor rendimiento que Hpricot WWW:Mechanize No se admiten selectores CSS
  • 31.
    Selección de lasherramientas Ruby Ofrece la misma funcionalidad que rest-open-uri HTree + REXML Hpricot Menor rendimiento que Hpricot WWW:Mechanize No se admiten selectores CSS
  • 32.
    Selección de lasherramientas Ruby Permite realizar interacciones rest-open-uri Rellenar y enviar formularios Hpricot Seguir enlaces WWW:Mechanize Consigue alcanzar documentos en La Web Profunda
  • 33.
    WWW::Mechanize require 'rubygems' require 'mechanize' agent= Mechanize.new agent.set_proxy("localhost",8080) page = agent.get('http://www.google.com') search_form = page.forms.select{|f| f.name=="f"}.first search_form.fields.select {|f| f.name=='q'}.first.value="ruby" search_results = agent.submit(search_form) search_results.links.each { |link| puts link.href if link.attributes["class"] == "l" } Runtime: 5.23s
  • 34.
  • 35.
    No tiene APIpública >8000 usuarios nuevos cada día 2h de sesión promedio datos datos datos!
  • 36.
  • 37.
    Paso 1: Accedera nuestro perfil require 'rubygems' require 'mechanize' agent = Mechanize.new agent.set_proxy("localhost",8080) #decimos que somos firefox modificando la cabecera user agent agent.user_agent_alias='Mac FireFox' login_page = agent.get('http://m.tuenti.com/?m=login') #cogemos el formulario de login login_form = login_page.forms.first #y rellenamos los campos usuario y contraseña login_form.fields.select{|f| f.name=="email"}.first.value="miguelfernandezfernandez@gmail.com" login_form.fields.select{|f| f.name=="input_password"}.first.value="xxxxx" pagina_de_inicio?=agent.submit(login_form)
  • 38.
  • 39.
    Segundo intento: versiónmóvil require 'rubygems' require 'mechanize' agent = Mechanize.new agent.set_proxy("localhost",8080) #decimos que somos firefox modificando la cabecera user agent agent.user_agent_alias='Mac FireFox' login_page = agent.get('http://m.tuenti.com/?m=login') #cogemos el formulario de login login_form = login_page.forms.first #y rellenamos los campos usuario y contraseña login_form.fields.select{|f| f.name=="tuentiemail"}.first.value="miguelfernandezfernandez@gmail.com " login_form.fields.select{|f| f.name=="password"}.first.value="xxxxxx" pagina_de_inicio=agent.submit(login_form)
  • 40.
  • 41.
    require 'rubygems' require 'mechanize' classTuentiAPI def initialize(login,password) @login=login @password=password end def inicio() agent = Mechanize.new agent.set_proxy("localhost",8080) #decimos que somos firefox modificando la cabecera user agent agent.user_agent_alias='Mac FireFox' login_page = agent.get('http://m.tuenti.com/?m=login') #cogemos el formulario de login login_form = login_page.forms.first #y rellenamos los campos usuario y contraseña login_form.fields.select{|f| f.name=="tuentiemail"}.first.value=@login login_form.fields.select{|f| f.name=="password"}.first.value=@password pagina_de_inicio=agent.submit(login_form) end end pagina_de_inicio=TuentiAPI.new("miguelfernandezfernandez@gmail.com","xxxxxx").inicio()
  • 42.
    Paso 2: Obtenerlas fotos
  • 43.
  • 45.
    Paso 2: Obtenerlas fotos class TuentiAPI ... def fotos_nuevas() tree=Hpricot(inicio().content) fotos = tree / "//a//img[@alt=Foto]" fotos.map!{|foto| foto.attributes["src"]} Set.new(fotos).to_a end private def inicio() ... end end
  • 46.
  • 48.
    Paso 3: Establecerel estado class TuentiAPI ... def actualizar_estado(msg) form_actualizacion=inicio.forms.first form_actualizacion.fields.select{|f| f.name=="status"}.first.value=msg @agent.submit(form_actualizacion) end end
  • 49.
  • 50.
    Tor: navegando deforma anónima Red de encadenamiento de proxies N peticiones salen de M servidores Garantiza el anonimato a nivel de IP https://www.torproject.org/vidalia/
  • 51.
  • 52.
    Universidad de Oviedo Programa de extensión universitaria CLOUD COMPUTING. DESARROLLO DE APLICACIONES Y MINERÍA WEB Miguel Fernández Fernández miguelff@innova.uniovi.es