Как я могу получить новый ip от tor каждый запрос в потоках?

Я пытаюсь использовать 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 попадает в разные процессы?


person kshnkvn    schedule 24.06.2019    source источник
comment
попробуйте добавить time.sleep(1) после вызова `get_new_ip()   -  person Sebastien D    schedule 24.06.2019
comment
@SebastienD пробовал - не помогает   -  person kshnkvn    schedule 24.06.2019


Ответы (2)


Если вам нужны разные IP-адреса для каждого подключения, вы также можете использовать изоляцию потока. через SOCKS, указав разные комбинации прокси username:password для каждого соединения.

С помощью этого метода вам нужен только один экземпляр 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 — это случайный одноразовый номер для каждого уникального собственного домена.

Если вы сканируете один и тот же сайт и вам нужны случайные IP-адреса, используйте случайную комбинацию имени пользователя и пароля для каждого сеанса. Если вы сканируете случайные домены и хотите использовать один и тот же канал для запросов к домену, используйте метод Tor Browser domain:randompassword для учетных данных.

person drew010    schedule 30.06.2019
comment
прежде всего спасибо за это (+1), кажется, это работает, и IP действительно меняется! однако в моем случае Cloudflare поймал меня, попросив включить куки, есть идеи? - person pcko1; 15.12.2020
comment
на самом деле проблема возникает из-за переделки session.proxies - person pcko1; 15.12.2020
comment
@pcko1 я не уверен. Возможно, просто доступ к сайту с помощью Cloudflare через Tor отключает какую-то защиту, которая хочет показать вам капчу или выполнить какое-то специальное обнаружение браузера. Достаточно плохо просматривать большинство сайтов Cloudflare в браузере Tor, не говоря уже об использовании запросов. - person drew010; 15.12.2020

У вас есть только один прокси-сервер, который прослушивает порт 9050. Все 3 процесса отправляют запросы параллельно через этот прокси-сервер, поэтому они используют один и тот же IP-адрес.

Что происходит:

  1. Все 3 процесса просят прокси получить новый IP
  2. Прокси-сервер либо запросит новый IP-адрес 3 раза, получит 3 ответа и применит последний, либо распознает, что уже ожидает новый IP-адрес, и проигнорирует 2 запроса, отвечая на 3 из них вместе. Это будет зависеть от реализации прокси.
  3. Процессы отправляют свои запросы через прокси, что приводит к тому же IP-адресу.
  4. Процессы завершаются и инициируются еще 3 процесса. Промыть и повторить.

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


EDIT:

Возможное решение с использованием блокировок и при условии, что в фоновом режиме работают 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()
person Luiz Ferraz    schedule 24.06.2019
comment
Ну, я так и думал. Но можно ли как-то обойти это? - person kshnkvn; 24.06.2019
comment
@kshnkvn Я добавил, как бы я решил это в ответ - person Luiz Ferraz; 24.06.2019