Python urllib 通过 TOR?

18 投票
3 回答
22363 浏览
提问于 2025-04-16 12:42

示例代码:

#!/usr/bin/python
import socks
import socket
import urllib2

socks.setdefaultproxy(socks.PROXY_TYPE_SOCKS4, "127.0.0.1", 9050, True)
socket.socket = socks.socksocket

print urllib2.urlopen("http://almien.co.uk/m/tools/net/ip/").read()

TOR在9050端口上运行一个SOCKS代理(这是它的默认设置)。请求通过TOR发送,显示的IP地址与我自己的不同。不过,TOR控制台发出了警告:

"2月28日 22:44:26.233 [警告] 你的 应用程序(使用socks4连接到80端口) 只给了Tor一个IP地址。 自己进行DNS解析的应用程序可能会泄露信息。 考虑使用Socks4A(例如通过 privoxy或socat)来替代。更多 信息,请查看 https://wiki.torproject.org/TheOnionRouter/TorFAQ#SOCKSAndDNS."

也就是说,DNS查询没有通过代理。但这不是setdefaultproxy的第四个参数应该做的事情吗?

来自 http://socksipy.sourceforge.net/readme.txt

setproxy(proxytype, addr[, port[, rdns[, username[, password]]]])

rdns - 这是一个布尔值标志, 修改DNS解析的行为。 如果设置为True,DNS解析将 在服务器上远程进行。

选择PROXY_TYPE_SOCKS4和PROXY_TYPE_SOCKS5时效果相同。

这不可能是本地DNS缓存(如果urllib2甚至支持的话),因为当我把URL换成这个电脑从未访问过的域名时,也会出现这个问题。

3 个回答

3

我写了一篇文章,里面有完整的源代码,教你怎么用 urllib2、SOCKS 和 Tor。你可以在这个链接找到它:http://blog.databigbang.com/distributed-scraping-with-multiple-tor-circuits/

希望这能帮到你解决问题。

5

问题在于你在建立socks连接之前就导入了urllib2

试试这样做:

import socks
import socket

socks.setdefaultproxy(socks.PROXY_TYPE_SOCKS4, '127.0.0.1', 9050, True)
socket.socket = socks.socksocket

import urllib2
print urllib2.urlopen("http://almien.co.uk/m/tools/net/ip/").read()

手动请求的例子:

import socks                                                         
import urlparse                                                      

SOCKS_HOST = 'localhost'                                             
SOCKS_PORT = 9050                                                    
SOCKS_TYPE = socks.PROXY_TYPE_SOCKS5                                 

url = 'http://www.whatismyip.com/automation/n09230945.asp'           
parsed = urlparse.urlparse(url)                                      


socket = socks.socksocket()                                          
socket.setproxy(SOCKS_TYPE, SOCKS_HOST, SOCKS_PORT)                  
socket.connect((parsed.netloc, 80))                                  
socket.send('''GET %(uri)s HTTP/1.1                                  
host: %(host)s                                                       
connection: close                                                    

''' % dict(                                                          
    uri=parsed.path,                                                 
    host=parsed.netloc,                                              
))                                                                   

print socket.recv(1024)                                              
socket.close()
21

问题在于,httplib.HTTPConnection 使用了 socket 模块中的一个叫做 create_connection 的辅助函数,这个函数在连接之前会通过常规的 getaddrinfo 方法进行 DNS 请求。

解决办法是自己写一个 create_connection 函数,然后在导入 urllib2 之前,把这个函数“打补丁”到 socket 模块,就像我们对待 socket 类一样。

import socks
import socket
def create_connection(address, timeout=None, source_address=None):
    sock = socks.socksocket()
    sock.connect(address)
    return sock

socks.setdefaultproxy(socks.PROXY_TYPE_SOCKS5, "127.0.0.1", 9050)

# patch the socket module
socket.socket = socks.socksocket
socket.create_connection = create_connection

import urllib2

# Now you can go ahead and scrape those shady darknet .onion sites

撰写回答