我的计算机上运行着多个Tor客户端,每个客户端都可以通过自己的端口访问(当前端口为9050-9054)。我希望通过这些Tor客户端同时请求大量URL,并设置速率限制,以便在任何给定的Tor端口上每N秒钟只发出一个请求,并且每个端口都使用一个唯一的退出节点(也就是说,从来没有两个tor端口同时从同一个IP发出请求)。
其目标是能够从受IP限制的网站/API中刮取,使请求看起来来自多个不同的IP,每个IP以最大的速度消费。匿名并不是真正的目标-- Tor的使用仅仅是为了创建大量的is来欺骗速率限制者认为这是一群不同的用户请求数据。因此,例如,如果API限制在每秒一个请求,并且我有10个正在以这个速率请求的tor客户机运行,那么我可以以最高速率的10倍提出请求.
下面是我到目前为止拥有的代码,它同时通过我的Tor客户机池获取所有URL:
import requests
from concurrent.futures import ThreadPoolExecutor, as_completed
from time import sleep
from datetime import datetime
from threading import Lock
import logging
logging.basicConfig(filename='log.txt', level=logging.DEBUG)
tor_ports = ['9050', '9051', '9052', '9053', '9054']
port_locks = {port: Lock() for port in tor_ports}
delay = 1 # wait N seconds between requests on same port
ua_string = 'Mozilla/5.0 (X11; Linux x86_64; rv:59.0) Gecko/20100101 Firefox/59.0'
# Create a new HTTP Requests Session routed through one of our Tor proxies
def newTorSession(port):
assert port in tor_ports
session = requests.session()
session.proxies = {'http': 'socks5://127.0.0.1:' + port,
'https': 'socks5://127.0.0.1:' + port}
return session
# Go through the list of all Tor proxies and return one that isn't locked
def getFreeTorPort(hangtime):
start = datetime.now()
while (datetime.now() - start).total_seconds() < hangtime:
for port in tor_ports:
if port_locks[port].locked():
next; # port in use ... try the next one
else:
port_locks[port].acquire()
return port
return None # this is when we exceed hangtime ... should be an exception we catch
# URL to fetch, and how long to sleep() after request
def torGet(url, delay):
port = getFreeTorPort(60)
session = newTorSession(port)
try:
response = session.get(url, headers = {'User-Agent': ua_string})
except requests.exception.RequestException as e:
logging.warning("Request of URL " + url + " failed with exception: " + e)
sleep(delay) # Pause for `delay` seconds after request
port_locks[port].release()
return response
# given a list of URLs, use multiple threads with own tor client to GET items
def torGetConcurrent(urls):
responses = []
with ThreadPoolExecutor(max_workers=len(tor_ports)) as executor:
futures = [executor.submit(torGet, url, delay) for url in urls]
responses = [f.result() for f in as_completed(futures)]
return responses我的问题是,如何确保每个Tor客户端总是使用不同的退出IP?也就是说,我想确保如果我运行10个tor客户端,我将始终使用10个唯一的退出节点。按照我目前设置的方式,有时会有多个客户端使用相同的出口,这导致我超过了每个IP的速率限制。我知道,我可以在ExitNodes字段中为每个客户端显式指定torrc字段中的退出节点列表,但我想知道是否有一种方法可以通过python脚本检查这一点,因为我不想手动使用退出节点列表来更新配置文件,而且只要它们都是唯一的,我也不关心它们使用的是哪些退出节点。
谢谢!
发布于 2018-03-28 20:41:46
我不一定会说Tor有“大量的I”。目前约有850个出口可用,其中一些出口可能超载,无法使用。
无论如何,尝试为所有出口(几个网站发布这些列表)或您想要使用的国家的出口建立指纹列表,并将每个tor客户端的ExitNodes配置设置为特定的指纹,以便它们没有一个同时使用相同的指纹。这将比向各个客户端发送NEWNYM信号更成功,希望它们没有一个同时重叠,并且必须运行缓慢的检查来查看任何给定客户端正在使用的出口。
编辑:
要执行我描述的操作,获取一个出口列表(即https://check.torproject.org/exit-addresses或https://torstatus.blutmagie.de/)并将它们拉到您选择的列表中,这样您就可以随意选择唯一的指纹列表,然后使用词干连接到每个实例的控制端口。连接后,将每个实例的配置值ExitNodes设置为指纹之一。ExitNodes可以是国家、节点列表,也可以是单个节点。当设置为单个节点时,您基本上是将该中继用作出口的客户端。这确保两个客户端不会同时使用相同的出口继电器。一旦你准备好循环它们,设置ExitNodes到一个新的指纹,并调用SIGNAL NEWNYN来构建新的电路。
这样做可能比检查每个实例并强制一个新的IP (如果其中任何一个是相同的话)更快。这样就不可能有一个实例在会话之间构建一个新的电路,并且在不知道的情况下使用重复的IP。
目前,如果不检查外部站点上的IP,就无法使用Python或任何其他语言获取退出IP或指纹。通常可以关闭的是使用控制端口查看活动电路的列表,从中提取退出指纹,并从目录状态请求中找到它的IP。由于Tor可以同时具有多个电路,所以您无法判断您的脚本可能使用哪一个。
https://stackoverflow.com/questions/49527625
复制相似问题