Scrapy con Privoxy y Tor: cómo renovar IP

Estoy tratando con Scrapy, Privoxy y Tor. Tengo todo instalado y funcionando correctamente. Pero Tor se conecta con la misma IP cada vez, por lo que puedo ser baneado fácilmente. ¿Es posible decirle a Tor que vuelva a conectar cada X segundos o conexiones?

¡Gracias!

EDITAR sobre la configuración: Para el grupo de agentes de usuario, hice esto: http://tangww.com/2013/06/UsingRandomAgent/ (Tuve que poner un archivo _ init _.py como se dice en los comentarios), y para Privoxy y Tor seguí http://www.andrewwatters.com/privoxy/ (tuve que crear el usuario privado y el grupo privado manualmente con el terminal). Funcionó 🙂

Mi araña es esta:

from scrapy.contrib.spiders import CrawlSpider from scrapy.selector import Selector from scrapy.http import Request class YourCrawler(CrawlSpider): name = "spider_name" start_urls = [ 'https://example.com/listviews/titles.php', ] allowed_domains = ["example.com"] def parse(self, response): # go to the urls in the list s = Selector(response) page_list_urls = s.xpath('///*[@id="tab7"]/article/header/h2/a/@href').extract() for url in page_list_urls: yield Request(response.urljoin(url), callback=self.parse_following_urls, dont_filter=True) # Return back and go to bext page in div#paginat ul li.next a::attr(href) and begin again next_page = response.css('ul.pagin li.presente ~ li a::attr(href)').extract_first() if next_page is not None: next_page = response.urljoin(next_page) yield Request(next_page, callback=self.parse) # For the urls in the list, go inside, and in div#main, take the div.ficha > div.caracteristicas > ul > li def parse_following_urls(self, response): #Parsing rules go here for each_book in response.css('main#main'): yield { 'editor': each_book.css('header.datos1 > ul > li > h5 > a::text').extract(), } 

En settings.py tengo una rotación de agente de usuario y privoxy:

 DOWNLOADER_MIDDLEWARES = { #user agent 'scrapy.contrib.downloadermiddleware.useragent.UserAgentMiddleware' : None, 'spider_name.comm.rotate_useragent.RotateUserAgentMiddleware' :400, #privoxy 'scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware': 110, 'spider_name.middlewares.ProxyMiddleware': 100 } 

En middlewares.py he añadido:

 class ProxyMiddleware(object): def process_request(self, request, spider): request.meta['proxy'] = 'http://127.0.0.1:8118' spider.log('Proxy : %s' % request.meta['proxy']) 

Y creo que eso es todo …

EDITAR II —

Ok, cambié mi archivo middlewares.py como en el blog @ Tomáš Linhart dijo desde:

 class ProxyMiddleware(object): def process_request(self, request, spider): request.meta['proxy'] = 'http://127.0.0.1:8118' spider.log('Proxy : %s' % request.meta['proxy']) 

A

 from stem import Signal from stem.control import Controller class ProxyMiddleware(object): def process_request(self, request, spider): request.meta['proxy'] = 'http://127.0.0.1:8118' spider.log('Proxy : %s' % request.meta['proxy']) def set_new_ip(): with Controller.from_port(port=9051) as controller: controller.authenticate(password='tor_password') controller.signal(Signal.NEWNYM) 

Pero ahora es muy lento, y no parece cambiar la dirección IP … ¿Lo hice bien o algo está mal?

Esta publicación del blog puede ayudarte un poco, ya que trata el mismo problema.

EDITAR: Basado en un requisito concreto (nueva IP para cada solicitud o después de N solicitudes), ponga la llamada apropiada a set_new_ip en el método process_request del middleware. Sin embargo, set_new_ip en set_new_ip que la llamada a la función set_new_ip no siempre tiene que garantizar una nueva IP (hay un enlace a las preguntas frecuentes con una explicación).

EDIT2: El módulo con la clase ProxyMiddleware se vería así:

 from stem import Signal from stem.control import Controller def _set_new_ip(): with Controller.from_port(port=9051) as controller: controller.authenticate(password='tor_password') controller.signal(Signal.NEWNYM) class ProxyMiddleware(object): def process_request(self, request, spider): _set_new_ip() request.meta['proxy'] = 'http://127.0.0.1:8118' spider.log('Proxy : %s' % request.meta['proxy']) 

Pero Tor se conecta con la misma IP cada vez.

Esa es una característica documentada de Tor :

Es importante tener en cuenta que un nuevo circuito no necesariamente significa una nueva dirección IP . Las rutas se seleccionan aleatoriamente en función de heurísticas como la velocidad y la estabilidad. Solo hay tantas salidas grandes en la red Tor, por lo que no es raro reutilizar una salida que haya tenido anteriormente.

Esa es la razón por la que el uso del código a continuación puede resultar en la reutilización de la misma dirección IP nuevamente.

 from stem import Signal from stem.control import Controller with Controller.from_port(port=9051) as controller: controller.authenticate(password='tor_password') controller.signal(Signal.NEWNYM) 

https://github.com/DusanMadar/TorIpChanger le ayuda a administrar este comportamiento. Admisión – escribí TorIpChanger .

También he preparado una guía sobre cómo usar Python con Tor y Privoxy: https://gist.github.com/DusanMadar/8d11026b7ce0bce6a67f7dd87b999f6b .

Este es un ejemplo de cómo puede usar TorIpChanger ( pip install toripchanger ) en su ProxyMiddleware .

 from toripchanger import TorIpChanger # A Tor IP will be reused only after 10 different IPs were used. ip_changer = TorIpChanger(reuse_threshold=10) class ProxyMiddleware(object): def process_request(self, request, spider): ip_changer.get_new_ip() request.meta['proxy'] = 'http://127.0.0.1:8118' spider.log('Proxy : %s' % request.meta['proxy']) 

O, si desea usar una IP diferente después de 10 solicitudes, puede hacer algo como a continuación.

 from toripchanger import TorIpChanger # A Tor IP will be reused only after 10 different IPs were used. ip_changer = TorIpChanger(reuse_threshold=10) class ProxyMiddleware(object): _requests_count = 0 def process_request(self, request, spider): self._requests_count += 1 if self._requests_count > 10: self._requests_count = 0 ip_changer.get_new_ip() request.meta['proxy'] = 'http://127.0.0.1:8118' spider.log('Proxy : %s' % request.meta['proxy'])