¿Alguien sabe de un buen rastreador web basado en Python que pueda usar?
-
03-07-2019 - |
Pregunta
Tengo la tentación de escribir la mía, pero en este momento no tengo suficiente tiempo. He visto la lista de Wikipedia de rastreadores de código abierto 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 de antemano. Además, ¡esta es mi primera pregunta SO!
Solución
- Mechanize 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 script simple creado sobre Mechanize
- BeautifulSoup + urllib2 también funciona bastante bien.
- Scrapy parece un proyecto extremadamente prometedor; es nuevo.
Otros consejos
Utilice Scrapy .
Es un marco de rastreador web basado en trenzas. Todavía en desarrollo pesado pero ya funciona. Tiene muchas golosinas:
- Compatibilidad incorporada 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 usando middlewares, extensiones y tuberías
- Amplia gama de middlewares integrados y extensiones para el manejo de compresión, caché, cookies, autenticación, suplantación de agente de usuario, manejo de robots.txt, estadísticas, restricción de profundidad de rastreo, etc.
- consola de shell de raspado interactivo, muy útil para desarrollar y depurar
- Consola de administración web para monitorear 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 que se agregaron hoy en el mininova del sitio, usando un Selector de 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 = x.x("//h1/text()").extract()
torrent.description = x.x("//div[@id='description']").extract()
torrent.size = x.x("//div[@id='info-left']/p[2]/text()[2]").extract()
return [torrent]
Compruebe el HarvestMan , un rastreador web de múltiples hilos escrito en Python, también consulte el módulo spider.py .
Y aquí puede encontrar ejemplos de código para crear un rastreador web simple .
He usado Ruya y lo encontré bastante bien.
He pirateado la secuencia de comandos anterior para incluir una página de inicio de sesión, ya que la necesitaba para acceder a un sitio de drupal. No es bonita, 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 <file with URLs to fetch> [<# 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 <file with URLs to fetch> [<# 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 Utiliza BeautifulSoup y urllib2. Nada demasiado sofisticado, solo lee todo lo que un href construye una lista y la recorre.