¿Alguien sabe de un buen rastreador web basado en Python que pueda usar?

Tengo la tentación de escribir la mía, pero en este momento no tengo suficiente tiempo. He visto la lista de rastreadores de código abierto de Wikipedia, pero preferiría algo escrito en Python. Me doy cuenta de que probablemente podría usar una de las herramientas en la página de Wikipedia y envolverla en Python. Podría terminar haciendo eso: si alguien tiene algún consejo sobre cualquiera de esas herramientas, estoy dispuesto a escuchar acerca de ellas. He usado Heritrix a través de su interfaz web y me pareció bastante engorroso. Definitivamente no usaré una API de navegador para mi próximo proyecto.

Gracias por adelantado. Además, esta es mi primera pregunta SO!

  • Mecanizar es mi favorito; excelentes capacidades de navegación de alto nivel (llenado y envío de formularios súper simples).
  • Twill es un lenguaje de scripting simple construido sobre Mechanize
  • BeautifulSoup + urllib2 también funciona bastante bien.
  • Scrapy parece un proyecto extremadamente prometedor; es nuevo.

Utilice Scrapy .

Es un marco de rastreador web basado en trenzas. Todavía en desarrollo pesado pero ya funciona. Tiene muchas golosinas

  • Compatibilidad integrada para analizar HTML, XML, CSV y Javascript
  • Un canal de medios para raspar elementos con imágenes (o cualquier otro medio) y descargar los archivos de imágenes también
  • Soporte para extender Scrapy conectando su propia funcionalidad mediante middlewares, extensiones y tuberías
  • Amplia gama de middlewares incorporados y extensiones para el manejo de compresión, caché, cookies, autenticación, falsificación de agente de usuario, manejo de robots.txt, estadísticas, restricción de profundidad de rastreo, etc.
  • Consola interactiva de raspado, muy útil para desarrollar y depurar
  • Consola de gestión web para monitorizar y controlar tu bot.
  • Consola Telnet para acceso de bajo nivel al proceso Scrapy

Código de ejemplo para extraer información sobre todos los archivos de torrent agregados hoy en el sitio de mininova torrent, mediante el uso de un selector XPath en el HTML devuelto:

class Torrent(ScrapedItem): pass class MininovaSpider(CrawlSpider): domain_name = 'mininova.org' start_urls = ['http://www.mininova.org/today'] rules = [Rule(RegexLinkExtractor(allow=['/tor/\d+']), 'parse_torrent')] def parse_torrent(self, response): x = HtmlXPathSelector(response) torrent = Torrent() torrent.url = response.url torrent.name = xx("//h1/text()").extract() torrent.description = xx("//div[@id='description']").extract() torrent.size = xx("//div[@id='info-left']/p[2]/text()[2]").extract() return [torrent] 

Compruebe que HarvestMan , un rastreador web de múltiples subprocesos escrito en Python, también eche un vistazo al módulo spider.py .

Y aquí puede encontrar ejemplos de código para construir un rastreador web simple.

He usado Ruya y lo encontré bastante bien.

He pirateado el script anterior para incluir una página de inicio de sesión, ya que la necesitaba para acceder a un sitio drupal. No es bonito, pero puede ayudar a alguien por ahí.

 #!/usr/bin/python import httplib2 import urllib import urllib2 from cookielib import CookieJar import sys import re from HTMLParser import HTMLParser class miniHTMLParser( HTMLParser ): viewedQueue = [] instQueue = [] headers = {} opener = "" def get_next_link( self ): if self.instQueue == []: return '' else: return self.instQueue.pop(0) def gethtmlfile( self, site, page ): try: url = 'http://'+site+''+page response = self.opener.open(url) return response.read() except Exception, err: print " Error retrieving: "+page sys.stderr.write('ERROR: %s\n' % str(err)) return "" return resppage def loginSite( self, site_url ): try: cj = CookieJar() self.opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj)) url = 'http://'+site_url params = {'name': 'customer_admin', 'pass': 'customer_admin123', 'opt': 'Log in', 'form_build_id': 'form-3560fb42948a06b01d063de48aa216ab', 'form_id':'user_login_block'} user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)' self.headers = { 'User-Agent' : user_agent } data = urllib.urlencode(params) response = self.opener.open(url, data) print "Logged in" return response.read() except Exception, err: print " Error logging in" sys.stderr.write('ERROR: %s\n' % str(err)) return 1 def handle_starttag( self, tag, attrs ): if tag == 'a': newstr = str(attrs[0][1]) print newstr if re.search('http', newstr) == None: if re.search('mailto', newstr) == None: if re.search('#', newstr) == None: if (newstr in self.viewedQueue) == False: print " adding", newstr self.instQueue.append( newstr ) self.viewedQueue.append( newstr ) else: print " ignoring", newstr else: print " ignoring", newstr else: print " ignoring", newstr def main(): if len(sys.argv)!=3: print "usage is ./minispider.py site link" sys.exit(2) mySpider = miniHTMLParser() site = sys.argv[1] link = sys.argv[2] url_login_link = site+"/node?destination=node" print "\nLogging in", url_login_link x = mySpider.loginSite( url_login_link ) while link != '': print "\nChecking link ", link # Get the file from the site and link retfile = mySpider.gethtmlfile( site, link ) # Feed the file into the HTML parser mySpider.feed(retfile) # Search the retfile here # Get the next link in level traversal order link = mySpider.get_next_link() mySpider.close() print "\ndone\n" if __name__ == "__main__": main() 

Confía en mí, nada es mejor que curl … El siguiente código puede rastrear 10,000 urls en paralelo en menos de 300 segundos en Amazon EC2

PRECAUCIÓN: No golpee el mismo dominio a una velocidad tan alta …

 #! /usr/bin/env python # -*- coding: iso-8859-1 -*- # vi:ts=4:et # $Id: retriever-multi.py,v 1.29 2005/07/28 11:04:13 mfx Exp $ # # Usage: python retriever-multi.py  [<# of # concurrent connections>] # import sys import pycurl # We should ignore SIGPIPE when using pycurl.NOSIGNAL - see # the libcurl tutorial for more info. try: import signal from signal import SIGPIPE, SIG_IGN signal.signal(signal.SIGPIPE, signal.SIG_IGN) except ImportError: pass # Get args num_conn = 10 try: if sys.argv[1] == "-": urls = sys.stdin.readlines() else: urls = open(sys.argv[1]).readlines() if len(sys.argv) >= 3: num_conn = int(sys.argv[2]) except: print "Usage: %s  [<# of concurrent connections>]" % sys.argv[0] raise SystemExit # Make a queue with (url, filename) tuples queue = [] for url in urls: url = url.strip() if not url or url[0] == "#": continue filename = "doc_%03d.dat" % (len(queue) + 1) queue.append((url, filename)) # Check args assert queue, "no URLs given" num_urls = len(queue) num_conn = min(num_conn, num_urls) assert 1 <= num_conn <= 10000, "invalid number of concurrent connections" print "PycURL %s (compiled against 0x%x)" % (pycurl.version, pycurl.COMPILE_LIBCURL_VERSION_NUM) print "----- Getting", num_urls, "URLs using", num_conn, "connections -----" # Pre-allocate a list of curl objects m = pycurl.CurlMulti() m.handles = [] for i in range(num_conn): c = pycurl.Curl() c.fp = None c.setopt(pycurl.FOLLOWLOCATION, 1) c.setopt(pycurl.MAXREDIRS, 5) c.setopt(pycurl.CONNECTTIMEOUT, 30) c.setopt(pycurl.TIMEOUT, 300) c.setopt(pycurl.NOSIGNAL, 1) m.handles.append(c) # Main loop freelist = m.handles[:] num_processed = 0 while num_processed < num_urls: # If there is an url to process and a free curl object, add to multi stack while queue and freelist: url, filename = queue.pop(0) c = freelist.pop() c.fp = open(filename, "wb") c.setopt(pycurl.URL, url) c.setopt(pycurl.WRITEDATA, c.fp) m.add_handle(c) # store some info c.filename = filename c.url = url # Run the internal curl state machine for the multi stack while 1: ret, num_handles = m.perform() if ret != pycurl.E_CALL_MULTI_PERFORM: break # Check for curl objects which have terminated, and add them to the freelist while 1: num_q, ok_list, err_list = m.info_read() for c in ok_list: c.fp.close() c.fp = None m.remove_handle(c) print "Success:", c.filename, c.url, c.getinfo(pycurl.EFFECTIVE_URL) freelist.append(c) for c, errno, errmsg in err_list: c.fp.close() c.fp = None m.remove_handle(c) print "Failed: ", c.filename, c.url, errno, errmsg freelist.append(c) num_processed = num_processed + len(ok_list) + len(err_list) if num_q == 0: break # Currently no more I/O is pending, could do something in the meantime # (display a progress bar, etc.). # We just call select() to sleep until some more data is available. m.select(1.0) # Cleanup for c in m.handles: if c.fp is not None: c.fp.close() c.fp = None c.close() m.close() 

Otra araña simple usa BeautifulSoup y urllib2. Nada demasiado sofisticado, solo lee todo lo que un href construye una lista y la recorre.

pyspider.py