Подтвердить что ты не робот

Scrapy с Privoxy и Tor: как обновить IP-адрес

Я имею дело с Scrapy, Privoxy и Tor. У меня все установлено и правильно работает. Но Tor соединяется с одним и тем же IP-сетью каждый раз, поэтому я могу быть легко заблокирован. Можно ли сказать Tor повторно подключить каждые X секунд или соединения?

Спасибо!

ИЗМЕНИТЬ о конфигурации: Для пула агента пользователя я сделал это: http://tangww.com/2013/06/UsingRandomAgent/ (мне пришлось поместить файл _ init _.py, как сказано в комментариях), а для Privoxy и Tor я следил за http://www.andrewwatters.com/privoxy/ (мне приходилось вручную создавать частный пользователь и частную группу с помощью терминала). Он работал:)

Мой паук таков:

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

В settings.py у меня есть поворот пользовательского агента и 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
    }

В middlewares.py я добавил:

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

И я думаю, что все...

EDIT II ---

Хорошо, я изменил свой файл middlewares.py, как в блоге @Tomáš Linhart сказал:

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)

Но теперь он очень медленный и, похоже, не меняет ip... Я сделал это нормально или что-то не так?

4b9b3361

Ответ 1

Этот пост в блоге может помочь вам немного, поскольку он имеет дело с той же проблемой.

РЕДАКТИРОВАТЬ: Основываясь на конкретных требованиях (новый IP для каждого запроса или после N запросов), поместите соответствующий вызов set_new_ip в метод process_request промежуточного программного обеспечения. Обратите внимание, однако, что вызов функции set_new_ip не всегда должен гарантировать новый IP (есть ссылка на FAQ с объяснением).

EDIT2: модуль с классом ProxyMiddleware будет выглядеть так:

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

Ответ 2

Но Tor соединяется с тем же IP каждый раз

Это документированная особенность Tor:

Важно отметить, что новый канал не обязательно означает новый IP-адрес. Пути выбираются случайным образом на основе эвристики, такой как скорость и стабильность. В сети Tor очень много больших выходов, поэтому нередко использовать выход, который вы имели ранее.

Вот почему использование кода ниже может привести к повторному использованию того же 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 помогает вам управлять этим поведением. Прием - я написал TorIpChanger.

Я также собрал руководство по использованию Python с Tor и Privoxy: https://gist.github.com/DusanMadar/8d11026b7ce0bce6a67f7dd87b999f6b.


Вот пример того, как вы можете использовать TorIpChanger (pip install toripchanger) в вашем 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'])

Или, если вы хотите использовать другой IP после 10 запросов, вы можете сделать что-то вроде ниже.

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