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'])
И я думаю, что это все...
РЕДАКТИРОВАТЬ II ---
Хорошо, я изменил свой файл 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'])
к
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-адрес... Я сделал это хорошо, или что-то не так?
2 ответа
Этот пост в блоге может помочь вам немного, поскольку он имеет дело с той же проблемой.
РЕДАКТИРОВАТЬ: на основе конкретного требования (новый 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'])
Но 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'])