Jak sprawić, by Żądania Pythona działały przez proxy Socks

83

Używam wspaniałej biblioteki Requests w moim skrypcie Python:

import requests
r = requests.get("some-site.com")
print r.text

Chciałbym używać proxy skarpet. Ale Requests obsługuje teraz tylko proxy HTTP.

Jak mogę to zrobić?

lithuak
źródło

Odpowiedzi:

116

Nowoczesny sposób:

pip install -U requests[socks]

następnie

import requests

resp = requests.get('http://go.to', 
                    proxies=dict(http='socks5://user:pass@host:port',
                                 https='socks5://user:pass@host:port'))
dvska
źródło
3
Uważaj, gdy używasz proxy SOCKS, requesocks wysyła żądania HTTP z pełnym adresem URL (np. „GET example.com HTTP / 1.1” zamiast „GET / HTTP / 1.1”) i takie zachowanie może powodować problemy. Niestety wydaje się, że na razie nie ma lepszego rozwiązania.
a3nm,
Ponadto nie znalazłem sposobu na użycie nazwy użytkownika i hasła w ustawieniach proxy. Musiałem uciekać się do urllib2.
Obejmują
9
Używam zsh i muszę to zrobić, w bash -c "pip install -U requests[socks]"przeciwnym razie zsh będzie narzekać zsh: no matches found: requests[socks].
Bruce Sun
3
W systemie Windows potrzebujesz również: pip install win-inet-pton
rstaveley
4
@BruceSun pip install 'requests[socks]'wystarczyłoby
bakatrouble
55

Od requestswersji 2.10.0 , wydanej 29.04.2016, requestsobsługuje SOCKS.

Wymaga PySocks , które można zainstalować z pip install pysocks.

Przykładowe użycie:

import requests
proxies = {'http': "socks5://myproxy:9191"}
requests.get('http://example.org', proxies=proxies)
Jim
źródło
3
pip install -U requests[socks] jest
enogh
8
W moim przypadku same żądania pip install -U [socks] nie działają. pip install pysocks jest koniecznością.
DenMark
Aby wymusić ręczną aktualizację twojej wersji requestsdo wersji obsługującej SOCKS (> 2.10.0), uruchom pip: pip install requests==2.18.4(2.18.4 w momencie pisania tego), ale sprawdź: pypi. python.org/pypi/requests dla najnowszej wersji (ta strona powinna pokazać w górnym nagłówku, jaka jest najnowsza stabilna wersja).
ntk4
Jestem z @DenMark w tej sprawie. Mój laptop roboczy to Mac i żąda [skarpetek] po prostu rażąco odmówił zainstalowania dla mnie bez względu na to, co próbowałem ... Pysocks magicznie wszystko naprawił.
Jeremy Logan
W moim przypadku występuje sockskonflikt nazwy modułu z qBittorrent, potrzebuję usunąć / przenieść ~/.local/share/data/qBittorrent/nova3/socks.pyi usunąć to socks.pyc, aby rozwiązać komunikat o błędzie module 'socks' has no attribute 'create_connection'i bad magic number in 'socks':odpowiednio.
Owoce
45

Na wypadek, gdyby ktoś wypróbował wszystkie te starsze odpowiedzi i nadal ma problemy, takie jak:

requests.exceptions.ConnectionError: 
   SOCKSHTTPConnectionPool(host='myhost', port=80): 
   Max retries exceeded with url: /my/path 
   (Caused by NewConnectionError('<requests.packages.urllib3.contrib.socks.SOCKSConnection object at 0x106812bd0>: 
   Failed to establish a new connection: 
   [Errno 8] nodename nor servname provided, or not known',))

Może tak być, ponieważ domyślnie requestsjest skonfigurowany do rozwiązywania zapytań DNS po lokalnej stronie połączenia.

Spróbuj zmienić adres URL serwera proxy z socks5://proxyhost:1234na socks5h://proxyhost:1234. Zwróć uwagę na dodatkowe h(oznacza to rozpoznawanie nazwy hosta).

Domyślnie moduł pakietu PySocks wykonuje zdalne rozwiązywanie problemów i nie jestem pewien, dlaczego żądania spowodowały, że ich integracja była tak niewyraźnie rozbieżna, ale oto jesteśmy.

Mahmoud Hashemi
źródło
6
To był dokładnie mój problem! Dzięki!
xbeta
4
To był dokładny problem dla mnie. Nie wykonywał zapytań DNS przez proxy. Jak tylko dodałem h, wszystko działało poprawnie.
jamescampbell
1
Dzięki, socks5hpodejście jest o wiele czystsze niż obejście polegające na łataniu małp, które wcześniej martwiłem się, że będę musiał zrobić.
Darien
1
Bardzo dobrze. Nie mogłem socks5h://nigdzie znaleźć dokumentacji Pythona na serwerach proxy. Musiał szukać w niewłaściwych miejscach. Tak kocham.
Ligemer
1
@Ligemer czasami jedynym właściwym miejscem do zajrzenia jest kod. (Ale spojrzawszy na kod, zaktualizuj StackOverflow, a teraz są dwa właściwe miejsca :))
Mahmoud Hashemi
18

Musisz zainstalować pysocks , moja wersja to 1.0, a kod działa dla mnie:

import socket
import socks
import requests
ip='localhost' # change your proxy's ip
port = 0000 # change your proxy's port
socks.setdefaultproxy(socks.PROXY_TYPE_SOCKS5, ip, port)
socket.socket = socks.socksocket
url = u'http://ajax.googleapis.com/ajax/services/search/images?v=1.0&q=inurl%E8%A2%8B'
print(requests.get(url).text)
lqhcpsgbl
źródło
Świetny! Jest to wygodne, gdy chcę użyć pakietu (np. Flickrapi) przez proxy socks 5
MZD
2
Nie jest to dobry sposób na używanie proxy socks, ponieważ zmienia on domyślne gniazdo i popełnia jakiś błąd, więc jeśli tylko przetestujesz, będzie dobrze, ale nie dla prawdziwych rzeczy.
lqhcpsgbl
6

Jak tylko Python requestszostanie scalony z SOCKS5żądaniem ściągnięcia, będzie to tak proste, jak użycie proxiessłownika:

#proxy
        # SOCKS5 proxy for HTTP/HTTPS
        proxies = {
            'http' : "socks5://myproxy:9191",
            'https' : "socks5://myproxy:9191"
        }

        #headers
        headers = {

        }

        url='http://icanhazip.com/'
        res = requests.get(url, headers=headers, proxies=proxies)

Zobacz Obsługa proxy SOCKS

Inną opcją, w przypadku gdy nie możesz się doczekać, requestaż będziesz gotowy, gdy nie możesz używać requesocks- jak w GoogleAppEngine z powodu braku pwdwbudowanego modułu, jest użycie PySocks, o którym mowa powyżej:

  1. Pobierz socks.pyplik z repozytorium i umieść kopię w folderze głównym;
  2. Dodaj import socksiimport socket

W tym momencie skonfiguruj i powiąż gniazdo przed użyciem with urllib2- w następującym przykładzie:

import urllib2
import socket
import socks

socks.set_default_proxy(socks.SOCKS5, "myprivateproxy.net",port=9050)
socket.socket = socks.socksocket
res=urllib2.urlopen(url).read()
loretoparisi
źródło
2
# SOCKS5 proxy for HTTP/HTTPS
proxiesDict = {
    'http' : "socks5://1.2.3.4:1080",
    'https' : "socks5://1.2.3.4:1080"
}

# SOCKS4 proxy for HTTP/HTTPS
proxiesDict = {
    'http' : "socks4://1.2.3.4:1080",
    'https' : "socks4://1.2.3.4:1080"
}

# HTTP proxy for HTTP/HTTPS
proxiesDict = {
    'http' : "1.2.3.4:1080",
    'https' : "1.2.3.4:1080"
}
wcc526
źródło
4
Czy tak to działa w najnowszej wersji Requests? Bez requesocks?
Gtx
To jest proxiessłownik dla ostatniego requestsżądania ściągnięcia, które w tym czasie nie zostało już scalone. @see - github.com/kennethreitz/requests/pull/2953
loretoparisi
2

Zainstalowałem pysocks i małpa załatałem create_connection w urllib3, na przykład:

import socks
import socket
socks.setdefaultproxy(socks.PROXY_TYPE_SOCKS4, "127.0.0.1", 1080)

def create_connection(address, timeout=socket._GLOBAL_DEFAULT_TIMEOUT,
                      source_address=None, socket_options=None):
    """Connect to *address* and return the socket object.

    Convenience function.  Connect to *address* (a 2-tuple ``(host,
    port)``) and return the socket object.  Passing the optional
    *timeout* parameter will set the timeout on the socket instance
    before attempting to connect.  If no *timeout* is supplied, the
    global default timeout setting returned by :func:`getdefaulttimeout`
    is used.  If *source_address* is set it must be a tuple of (host, port)
    for the socket to bind as a source address before making the connection.
    An host of '' or port 0 tells the OS to use the default.
    """

    host, port = address
    if host.startswith('['):
        host = host.strip('[]')
    err = None
    for res in socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM):
        af, socktype, proto, canonname, sa = res
        sock = None
        try:
            sock = socks.socksocket(af, socktype, proto)

            # If provided, set socket level options before connecting.
            # This is the only addition urllib3 makes to this function.
            urllib3.util.connection._set_socket_options(sock, socket_options)

            if timeout is not socket._GLOBAL_DEFAULT_TIMEOUT:
                sock.settimeout(timeout)
            if source_address:
                sock.bind(source_address)
            sock.connect(sa)
            return sock

        except socket.error as e:
            err = e
            if sock is not None:
                sock.close()
                sock = None

    if err is not None:
        raise err

    raise socket.error("getaddrinfo returns an empty list")

# monkeypatch
urllib3.util.connection.create_connection = create_connection
Edward Betts
źródło
0

Mógłbym to zrobić na Linuksie.

$ pip3 install --user 'requests[socks]'
$ https_proxy=socks5://<hostname or ip>:<port> python3 -c \
> 'import requests;print(requests.get("https://httpbin.org/ip").text)'
Nizam Mohamed
źródło