Screen scraping

1,508 views

Published on

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
1,508
On SlideShare
0
From Embeds
0
Number of Embeds
5
Actions
Shares
0
Downloads
15
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Screen scraping

  1. 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. 2. Screen scraping
  3. 3. Porqué screen scraping La Web es fundamentalmente para humanos (HTML)
  4. 4. Porqué screen scraping La Web es fundamentalmente para humanos (HTML)
  5. 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. 6. Porqué screen scraping La Web es fundamentalmente para humanos (HTML)
  7. 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. 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. 9. Porqué screen scraping No siempre disponemos de una API
  10. 10. Porqué screen scraping No siempre disponemos de una APINecesitamos simular el comportamiento humano
  11. 11. Porqué screen scraping No siempre disponemos de una APINecesitamos simular el comportamiento humano Interpretar HTML
  12. 12. Porqué screen scraping No siempre disponemos de una APINecesitamos simular el comportamiento humano Realizar Interpretar interacciones HTML (Navegar)
  13. 13. Porqué screen scraping No siempre disponemos de una APINecesitamos simular el comportamiento humano Realizar Interpretar interacciones Ser un Ninja HTML (Navegar) Evitar DoS
  14. 14. 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 RubyfulSouptransversing System.Text. Regexp java.util.regexp RegularExpressions Regexp re --- Librerías de terceras partes. No forman parte de la API del lenguaje.
  15. 15. Selección de las herramientas ¿Con qué lenguaje vamos a trabajar? Duck typing + Reflexión = Syntactic Sugar
  16. 16. Selección de las herramientas ¿Con qué lenguaje vamos a trabajar? Lenguajes dinámicos facilitan la codificación Duck typing + Reflexión = Syntactic Sugar
  17. 17. Javaimport 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. 18. Rubyrequire rubygemsrequire open-urirequire htreerequire 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. 19. Selección de las herramientas Ruby rest-open-uri Nos permitirá hacer peticiones aHTree + REXML URLs y extraer su contenido Hpricot extiende open-uri para soportar RubyfulSoup más verbosWWW:Mechanize
  20. 20. Selección de las herramientas Ruby HTree crea un árbol de rest-open-uri objetos a partir de código HTMLHTree + REXML Hpricot HTree#to_rexml Convierte el árbol a un árbol RubyfulSoup REXMLWWW:Mechanize REXML puede navegarse con XPath 2.0
  21. 21. HTree+REXMLrequire rubygemsrequire open-urirequire htreerequire 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. 22. 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/
  23. 23. HPricotrequire rubygemsrequire hpricotrequire open-uridoc = 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. 24. 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/
  25. 25. 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ónWWW:Mechanize co mo Jquery (selectores CSS y XPath*) Funcionalidad equivalente a Htree + REXML http://hpricot.com/
  26. 26. Selección de las herramientas Ruby rest-open-uri Ofrece la misma funcionalidad que Hpricot HTree + REXML RubyfulSoupWWW:Mechanize
  27. 27. Rubyful Souprequire rubygemsrequire rubyful_souprequire open-uriopen("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. 28. Selección de las herramientas Ruby rest-open-uri Ofrece la misma funcionalidad que Hpricot HTree + REXML RubyfulSoupWWW:Mechanize
  29. 29. Selección de las herramientas Ruby rest-open-uri Ofrece la misma funcionalidad que Hpricot HTree + REXML RubyfulSoup Menor rendimiento que HpricotWWW:Mechanize
  30. 30. Selección de las herramientas Ruby rest-open-uri Ofrece la misma funcionalidad que Hpricot HTree + REXML RubyfulSoup Menor rendimiento que HpricotWWW:Mechanize No se admiten selectores CSS
  31. 31. Selección de las herramientas Ruby Ofrece la misma funcionalidad que rest-open-uri HTree + REXML Hpricot Menor rendimiento que HpricotWWW:Mechanize No se admiten selectores CSS
  32. 32. Selección de las herramientas Ruby Permite realizar interacciones rest-open-uri Rellenar y enviar formularios Hpricot Seguir enlacesWWW:Mechanize Consigue alcanzar documentos en La Web Profunda
  33. 33. WWW::Mechanizerequire rubygemsrequire mechanizeagent = Mechanize.newagent.set_proxy("localhost",8080)page = agent.get(http://www.google.com)search_form = page.forms.select{|f| f.name=="f"}.firstsearch_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. 34. Manos a la obra
  35. 35. No tiene API pública>8000 usuarios nuevos cada día 2h de sesión promedio datos datos datos!
  36. 36. Novedades de tuenti
  37. 37. Paso 1: Acceder a nuestro perfilrequire rubygemsrequire mechanizeagent = Mechanize.newagent.set_proxy("localhost",8080)#decimos que somos firefox modificando la cabecera user agentagent.user_agent_alias=Mac FireFoxlogin_page = agent.get(http://m.tuenti.com/?m=login)#cogemos el formulario de loginlogin_form = login_page.forms.first#y rellenamos los campos usuario y contraseñalogin_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. 38. Redirecciona por Javascript
  39. 39. 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)
  40. 40. Eureka!
  41. 41. require rubygemsrequire mechanizeclass 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) endendpagina_de_inicio=TuentiAPI.new("miguelfernandezfernandez@gmail.com","xxxxxx").inicio()
  42. 42. Paso 2: Obtener las fotos
  43. 43. <div class=”box”><div class=”box”><div class=”box”>
  44. 44. Paso 2: Obtener las fotosclass 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() ... endend
  45. 45. Paso 3: Establecer el estado
  46. 46. Paso 3: Establecer el estadoclass 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) endend
  47. 47. Ninja Moves
  48. 48. 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/
  49. 49. Gracias
  50. 50. 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

×