我如何从线程中的每个请求中获取新的 ip?
How i can get new ip from tor every requests in threads?
我尝试使用 TOR 代理进行抓取,在一个线程中一切正常,但这很慢。
我尝试做一些简单的事情:
def get_new_ip():
with Controller.from_port(port = 9051) as controller:
controller.authenticate(password="password")
controller.signal(Signal.NEWNYM)
time.sleep(controller.get_newnym_wait())
def check_ip():
get_new_ip()
session = requests.session()
session.proxies = {'http': 'socks5h://localhost:9050', 'https': 'socks5h://localhost:9050'}
r = session.get('http://httpbin.org/ip')
r.text
with Pool(processes=3) as pool:
for _ in range(9):
pool.apply_async(check_ip)
pool.close()
pool.join()
当我 运行 它时,我看到输出:
{"origin": "95.179.181.1, 95.179.181.1"}
{"origin": "95.179.181.1, 95.179.181.1"}
{"origin": "95.179.181.1, 95.179.181.1"}
{"origin": "151.80.53.232, 151.80.53.232"}
{"origin": "151.80.53.232, 151.80.53.232"}
{"origin": "151.80.53.232, 151.80.53.232"}
{"origin": "145.239.169.47, 145.239.169.47"}
{"origin": "145.239.169.47, 145.239.169.47"}
{"origin": "145.239.169.47, 145.239.169.47"}
为什么会这样?如何为每个线程分配自己的 IP?
顺便说一下,我尝试了像 TorRequests、TorCtl 这样的库,结果是一样的。
我了解到 TOR 在发布新 IP 之前似乎有延迟,但为什么相同的 IP 会进入不同的进程?
您只有一个代理,它正在侦听端口 9050。所有 3 个进程都通过该代理并行发送请求,因此它们共享相同的 IP。
发生的事情是:
- 所有 3 个进程都要求代理获取新 IP
- 代理要么请求一个新 IP 3 次,收到 3 个响应并应用最后一个响应,要么它会认识到它已经在等待一个新 IP 并忽略其中 2 个请求,同时响应其中的 3 个。这将取决于代理实施。
- 进程通过代理发送它们的请求,这导致相同的 IP。
- 流程完成,另外3个流程启动。冲洗并重复。
这就是为什么 3 个请求的每个块的 IP 都相同的原因。
您需要 3 个独立的代理才能同时拥有 3 个不同的 IP。
编辑:
使用锁并假设后台有 3 个代理 运行 的可能解决方案:
import contextlib, threading, time
_controller_ports = [
# (Controller Lock, connection port, management port)
(threading.Lock(), 9050, 9051),
(threading.Lock(), 9060, 9061),
(threading.Lock(), 9070, 9071),
]
def get_new_ip_for(port):
with Controller.from_port(port=port) as controller:
controller.authenticate(password="password")
controller.signal(Signal.NEWNYM)
time.sleep(controller.get_newnym_wait())
@contextlib.contextmanager
def get_port_with_new_ip():
while True:
for lock, con_port, manage_port in _controller_ports:
if lock.acquire(blocking=False):
get_new_ip_for(manage_port)
yield con_port
lock.release()
break
time.sleep(1)
def check_ip():
with get_port_with_new_ip() as port:
session = requests.session()
session.proxies = {'http': f'socks5h://localhost:{port}', 'https': f'socks5h://localhost:{port}'}
r = session.get('http://httpbin.org/ip')
print(r.text)
with Pool(processes=3) as pool:
for _ in range(9):
pool.apply_async(check_ip)
pool.close()
pool.join()
如果您希望每个连接使用不同的 IP,您还可以通过为每个连接指定不同的代理 username:password
组合,在 SOCKS 上使用 Stream Isolation。
使用这种方法,您只需要一个 Tor 实例,并且每个请求客户端可以使用具有不同出口节点的不同流。
为了设置它,为每个 requests.session
对象添加唯一的代理凭据,如下所示:socks5h://username:password@localhost:9050
import random
from multiprocessing import Pool
import requests
def check_ip():
session = requests.session()
creds = str(random.randint(10000,0x7fffffff)) + ":" + "foobar"
session.proxies = {'http': 'socks5h://{}@localhost:9050'.format(creds), 'https': 'socks5h://{}@localhost:9050'.format(creds)}
r = session.get('http://httpbin.org/ip')
print(r.text)
with Pool(processes=8) as pool:
for _ in range(9):
pool.apply_async(check_ip)
pool.close()
pool.join()
Tor 浏览器通过将凭据设置为 firstpartydomain:randompassword
在 per-domain 的基础上隔离流,其中 randompassword 是每个唯一的第一方域的随机随机数。
如果您正在抓取同一个站点并且想要随机 IP,则对每个会话使用随机 username:password 组合。如果您正在抓取随机域并希望对域的请求使用相同的电路,请使用 Tor 浏览器的 domain:randompassword
方法获取凭据。
我尝试使用 TOR 代理进行抓取,在一个线程中一切正常,但这很慢。 我尝试做一些简单的事情:
def get_new_ip():
with Controller.from_port(port = 9051) as controller:
controller.authenticate(password="password")
controller.signal(Signal.NEWNYM)
time.sleep(controller.get_newnym_wait())
def check_ip():
get_new_ip()
session = requests.session()
session.proxies = {'http': 'socks5h://localhost:9050', 'https': 'socks5h://localhost:9050'}
r = session.get('http://httpbin.org/ip')
r.text
with Pool(processes=3) as pool:
for _ in range(9):
pool.apply_async(check_ip)
pool.close()
pool.join()
当我 运行 它时,我看到输出:
{"origin": "95.179.181.1, 95.179.181.1"}
{"origin": "95.179.181.1, 95.179.181.1"}
{"origin": "95.179.181.1, 95.179.181.1"}
{"origin": "151.80.53.232, 151.80.53.232"}
{"origin": "151.80.53.232, 151.80.53.232"}
{"origin": "151.80.53.232, 151.80.53.232"}
{"origin": "145.239.169.47, 145.239.169.47"}
{"origin": "145.239.169.47, 145.239.169.47"}
{"origin": "145.239.169.47, 145.239.169.47"}
为什么会这样?如何为每个线程分配自己的 IP? 顺便说一下,我尝试了像 TorRequests、TorCtl 这样的库,结果是一样的。
我了解到 TOR 在发布新 IP 之前似乎有延迟,但为什么相同的 IP 会进入不同的进程?
您只有一个代理,它正在侦听端口 9050。所有 3 个进程都通过该代理并行发送请求,因此它们共享相同的 IP。
发生的事情是:
- 所有 3 个进程都要求代理获取新 IP
- 代理要么请求一个新 IP 3 次,收到 3 个响应并应用最后一个响应,要么它会认识到它已经在等待一个新 IP 并忽略其中 2 个请求,同时响应其中的 3 个。这将取决于代理实施。
- 进程通过代理发送它们的请求,这导致相同的 IP。
- 流程完成,另外3个流程启动。冲洗并重复。
这就是为什么 3 个请求的每个块的 IP 都相同的原因。
您需要 3 个独立的代理才能同时拥有 3 个不同的 IP。
编辑:
使用锁并假设后台有 3 个代理 运行 的可能解决方案:
import contextlib, threading, time
_controller_ports = [
# (Controller Lock, connection port, management port)
(threading.Lock(), 9050, 9051),
(threading.Lock(), 9060, 9061),
(threading.Lock(), 9070, 9071),
]
def get_new_ip_for(port):
with Controller.from_port(port=port) as controller:
controller.authenticate(password="password")
controller.signal(Signal.NEWNYM)
time.sleep(controller.get_newnym_wait())
@contextlib.contextmanager
def get_port_with_new_ip():
while True:
for lock, con_port, manage_port in _controller_ports:
if lock.acquire(blocking=False):
get_new_ip_for(manage_port)
yield con_port
lock.release()
break
time.sleep(1)
def check_ip():
with get_port_with_new_ip() as port:
session = requests.session()
session.proxies = {'http': f'socks5h://localhost:{port}', 'https': f'socks5h://localhost:{port}'}
r = session.get('http://httpbin.org/ip')
print(r.text)
with Pool(processes=3) as pool:
for _ in range(9):
pool.apply_async(check_ip)
pool.close()
pool.join()
如果您希望每个连接使用不同的 IP,您还可以通过为每个连接指定不同的代理 username:password
组合,在 SOCKS 上使用 Stream Isolation。
使用这种方法,您只需要一个 Tor 实例,并且每个请求客户端可以使用具有不同出口节点的不同流。
为了设置它,为每个 requests.session
对象添加唯一的代理凭据,如下所示:socks5h://username:password@localhost:9050
import random
from multiprocessing import Pool
import requests
def check_ip():
session = requests.session()
creds = str(random.randint(10000,0x7fffffff)) + ":" + "foobar"
session.proxies = {'http': 'socks5h://{}@localhost:9050'.format(creds), 'https': 'socks5h://{}@localhost:9050'.format(creds)}
r = session.get('http://httpbin.org/ip')
print(r.text)
with Pool(processes=8) as pool:
for _ in range(9):
pool.apply_async(check_ip)
pool.close()
pool.join()
Tor 浏览器通过将凭据设置为 firstpartydomain:randompassword
在 per-domain 的基础上隔离流,其中 randompassword 是每个唯一的第一方域的随机随机数。
如果您正在抓取同一个站点并且想要随机 IP,则对每个会话使用随机 username:password 组合。如果您正在抓取随机域并希望对域的请求使用相同的电路,请使用 Tor 浏览器的 domain:randompassword
方法获取凭据。