我如何从线程中的每个请求中获取新的 ip?

Posted

技术标签:

【中文标题】我如何从线程中的每个请求中获取新的 ip?【英文标题】:How i can get new ip from tor every requests in threads? 【发布时间】:2019-06-24 09:16:11 【问题描述】:

我尝试使用 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会进入不同的进程?

【问题讨论】:

尝试在调用`get_new_ip()后添加time.sleep(1) @SebastienD 尝试过 - 没有帮助 【参考方案1】:

如果您希望每个连接使用不同的 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 来隔离每个域的流,其中 randompassword 是每个唯一第一方域的随机 nonce。

如果您正在抓取同一个站点并且想要随机 IP,则为每个会话使用随机的用户名:密码组合。如果您正在抓取随机域并希望对域的请求使用相同的电路,请使用 Tor 浏览器的 domain:randompassword 方法获取凭据。

【讨论】:

首先感谢这个(+1'd),这似乎有效并且IP确实发生了变化!但是在我的情况下,我被 Cloudflare 抓住,要求我启用 cookie,知道吗? 其实问题是因为修改了session.proxies @pcko1 我不确定。可能只是通过 Tor 访问使用 Cloudflare 的站点会触发一些防御,这些防御想要向您显示验证码或进行一些特殊的浏览器检测。在 Tor 浏览器中查看大多数 Cloudflare 网站已经够糟糕的了,更不用说使用请求了。【参考方案2】:

您只有一个代理,它正在侦听端口 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()

【讨论】:

嗯,我是这么认为的。但我能以某种方式解决这个问题吗? @kshnkvn 我将如何解决它添加到答案中

以上是关于我如何从线程中的每个请求中获取新的 ip?的主要内容,如果未能解决你的问题,请参考以下文章

如何从c中的sock结构中获取IP地址?

如何实现多线程服务器请求? C#

如何在 Django 中获取主机 IP 地址 [关闭]

如何从调用对象中获取 IP 地址

Spring中如何获取request的方法汇总及其线程安全性分析

根据 JWT 身份验证令牌中的声明验证来自请求的 IP