web-dev-qa-db-fra.com

Scrapy avec Privoxy et Tor: comment renouveler IP

J'ai affaire à Scrapy, Privoxy et Tor. J'ai tout installé et fonctionne correctement. Mais Tor se connecte à chaque fois avec la même IP, donc je peux facilement être banni. Est-il possible de dire à Tor de se reconnecter toutes les X secondes ou connexions?

Merci!

EDIT sur la configuration: Pour le pool d'agent utilisateur, j'ai fait ceci: http://tangww.com/2013/06/UsingRandomAgent/ (J'ai dû mettre un _ init _.py file comme il est dit dans les commentaires), et pour Privoxy et Tor j'ai suivi http://www.andrewwatters.com/privoxy/ = (J'ai dû créer manuellement l'utilisateur privé et le groupe privé avec le terminal). Ça a marché :)

Mon araignée est la suivante:

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(),
            }

Dans settings.py j'ai une rotation d'agent utilisateur et 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
    }

Dans middlewares.py, j'ai ajouté:

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'])

Et je pense que c'est tout ...

EDIT II ---

Ok, j'ai changé mon fichier middlewares.py comme dans le blog @ Tomáš Linhart dit de:

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'])

À

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)

Mais maintenant, c'est vraiment lent, et ne semble pas changer l'ip ...

16
user7499416

Cette article de blog pourrait vous aider un peu car elle traite du même problème.

EDIT: Basé sur une exigence concrète (nouvelle IP pour chaque demande ou après [~ # ~] n [~ # ~] requêtes), appelez le set_new_ip dans process_request méthode du middleware. Notez cependant que cet appel à set_new_ip la fonction ne doit pas toujours garantir une nouvelle IP (il y a un lien vers le FAQ avec explication).

EDIT2: Le module avec la classe ProxyMiddleware ressemblerait à ceci:

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'])
9
Tomáš Linhart

Mais Tor se connecte avec la même IP à chaque fois

C'est une fonctionnalité Tor documentée :

Une chose importante à noter est que un nouveau circuit ne signifie pas nécessairement une nouvelle adresse IP . Les chemins sont sélectionnés au hasard sur la base d'heuristiques comme la vitesse et la stabilité. Il n'y a que tant de grandes sorties dans le réseau Tor, il n'est donc pas rare de réutiliser une sortie que vous avez eu précédemment.

C'est la raison pour laquelle l'utilisation du code ci-dessous peut entraîner la réutilisation de la même adresse IP.

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 vous aide à gérer ce comportement. Admission - j'ai écrit TorIpChanger.

J'ai également élaboré un guide sur la façon d'utiliser Python avec Tor et Privoxy: https://Gist.github.com/DusanMadar/8d11026b7ce0bce6a67f7dd87b999f6b .


Voici un exemple d'utilisation de TorIpChanger (pip install toripchanger) dans votre 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'])

Ou, si vous souhaitez utiliser une adresse IP différente après 10 demandes, vous pouvez faire quelque chose comme ci-dessous.

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'])
7
Dušan Maďar