使用Python连接SOCKS5认证代理服务器,并在本地端口转发为HTTP代理的脚本。

为解决 Proxy SwitchyOmega 无法连接带密码认证的 SOCKS5 服务器的问题,我们可以使用 Python 编写一个脚本来连接 SOCKS5 服务器,并在本地转发为 HTTP 服务器。

  1. 配置 SOCKS5 代理服务器的连接信息。
  2. 实现一个 HTTP 代理服务器,将请求通过 SOCKS5 代理进行转发。
  3. 启动 HTTP 代理服务器,并在终端显示上传和下载数据量。

以下是具体步骤和代码实现。

1. 安装所需库

首先,请确保你已经安装了以下库:

1
pip install requests pysocks

如果报错,请尝试备用安装环境库

1
2
pip install altgraph==0.17.4 anyio==4.3.0 appdirs==1.4.4 argon2-cffi==23.1.0 argon2-cffi-bindings==21.2.0 arrow==1.3.0 astroid==3.1.0 asttokens==2.4.1 async-lru==2.0.4 async-timeout==4.0.3 attrs==23.2.0 Babel==2.14.0 beautifulsoup4==4.12.3 bleach==6.1.0 bleak==0.22.1 bleak-winrt==1.2.0 certifi==2024.2.2 cffi==1.16.0 charset-normalizer==3.3.2 click==8.1.7 colorama==0.4.6 comm==0.2.2 contourpy==1.2.0 cryptography==41.0.4 cycler==0.12.1 debugpy==1.8.1 decorator==5.1.1 defusedxml==0.7.1 dill==0.3.8 enum-compat==0.0.3 exceptiongroup==1.2.0 executing==2.0.1 fastjsonschema==2.19.1 fonttools==4.50.0 fqdn==1.5.1 fuzzywuzzy==0.18.0 h11==0.14.0 httpcore==1.0.4 httpx==0.27.0 idna==3.6 importlib_metadata==7.1.0 importlib_resources==6.3.1 ipykernel==6.29.3 ipython==8.18.1 ipywidgets==8.1.2 isoduration==20.11.0 isort==5.13.2 jedi==0.19.1 Jinja2==3.1.3 json5==0.9.24 jsonpointer==2.4 jsonschema==4.21.1 jsonschema-specifications==2023.12.1 jupyter==1.0.0 jupyter-console==6.6.3 jupyter-events==0.10.0 jupyter-lsp==2.2.4 jupyter_client==8.6.1 jupyter_core==5.7.2 jupyter_server==2.13.0 jupyter_server_terminals==0.5.3 jupyterlab==4.1.5 jupyterlab_pygments==0.3.0 jupyterlab_server==2.25.4 jupyterlab_widgets==3.0.10 keyboard==0.13.5 keyring==23.0.0 kiwisolver==1.4.5 Levenshtein==0.25.1 MarkupSafe==2.1.5 matplotlib==3.8.3 matplotlib-inline==0.1.6 mccabe==0.7.0 mistune==3.0.2 MouseInfo==0.1.3 nbclient==0.10.0 nbconvert==7.16.3 nbformat==5.10.3 nest-asyncio==1.6.0 notebook==7.1.2 notebook_shim==0.2.4 npyscreen==4.10.5 ntplib==0.4.0 numpy==1.26.4 opencv-python==4.9.0.80 overrides==7.7.0 packaging==24.0 pandas==1.1.5 pandocfilters==1.5.1 parso==0.8.3 pefile==2023.2.7 pillow==10.2.0 platformdirs==4.2.0 prometheus_client==0.20.0 prompt-toolkit==3.0.43 psutil==5.9.8 pure-eval==0.2.2 PyAutoGUI==0.9.54 PyBluez==0.30 pychrome==0.2.4 pycookiecheat==0.6.0 pycparser==2.21 pyee==11.1.0 pygatt==4.0.5 PyGetWindow==0.0.9 Pygments==2.17.2 pyinstaller==6.6.0 pyinstaller-hooks-contrib==2024.5 pylint==3.1.0 PyMsgBox==1.0.9 pynput==1.7.6 pyparsing==3.1.2 pyperclip==1.8.2 pypiwin32==223 pyppeteer==2.0.0 PyRect==0.2.0 PyScreeze==0.1.30 pyserial==3.5 PySocks==1.7.1 pytesseract==0.3.10 python-dateutil==2.9.0.post0 python-json-logger==2.0.7 python-Levenshtein==0.25.1 pytweening==1.2.0 pytz==2024.1 pywin32==306 pywin32-ctypes==0.2.2 pywinpty==2.0.13 PyYAML==6.0.1 pyzmq==25.1.2 qtconsole==5.5.1 QtPy==2.4.1 rapidfuzz==3.9.0 referencing==0.34.0 requests==2.31.0 rfc3339-validator==0.1.4 rfc3986-validator==0.1.1 rpds-py==0.18.0 Send2Trash==1.8.2 six==1.16.0 sniffio==1.3.1 soupsieve==2.5 stack-data==0.6.3 terminado==0.18.1 tinycss2==1.2.1 tomli==2.0.1 tomlkit==0.12.5 tornado==6.4 tqdm==4.66.4 traitlets==5.14.2 types-python-dateutil==2.9.0.20240316 typing_extensions==4.10.0 uri-template==1.3.0 urllib3==1.26.18 wcwidth==0.2.13 webcolors==1.13 webencodings==0.5.1 websocket-client==1.7.0 websockets==10.4 widgetsnbextension==4.0.10 zipp==3.18.1

2. 创建配置文件

我们需要创建一个配置文件来保存SOCKS5代理的配置信息。创建一个名为 socks5.ini 的文件,内容如下:

1
2
3
4
5
[SOCKS5]
HOST=your_socks5_proxy_host
PORT=your_socks5_proxy_port
USERNAME=your_username
PASSWORD=your_password

请根据实际情况填写你的SOCKS5代理的主机、端口、用户名和密码。

3. 编写代码

以下是实现的完整代码,将其保存为 socks5_http_proxy.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
import socketserver
import http.server
import socket
import socks
import select
import threading
import time
import configparser
from urllib.parse import urlparse

# 读取SOCKS5配置文件
config = configparser.ConfigParser()
config.read('socks5.ini')

SOCKS5_PROXY_HOST = config['SOCKS5']['HOST']
SOCKS5_PROXY_PORT = int(config['SOCKS5']['PORT'])
SOCKS5_USERNAME = config['SOCKS5']['USERNAME']
SOCKS5_PASSWORD = config['SOCKS5']['PASSWORD']

# 全局变量来跟踪数据传输量
total_upload = 0
total_download = 0
current_upload = 0
current_download = 0
lock = threading.Lock()

# 设置SOCKS5代理
socks.set_default_proxy(
socks.SOCKS5,
SOCKS5_PROXY_HOST,
SOCKS5_PROXY_PORT,
username=SOCKS5_USERNAME,
password=SOCKS5_PASSWORD
)
socket.socket = socks.socksocket

class ProxyHTTPRequestHandler(http.server.BaseHTTPRequestHandler):
def log_message(self, format, *args):
return # 禁用默认的日志记录

def do_GET(self):
self.handle_http_request()

def do_POST(self):
self.handle_http_request()

def handle_http_request(self):
global total_upload, total_download, current_upload, current_download

url = self.path
parsed_url = urlparse(url)
hostname = parsed_url.hostname
port = parsed_url.port or (443 if parsed_url.scheme == 'https' else 80)

try:
conn = socks.socksocket()
conn.connect((hostname, port))

self.send_response(200)
self.end_headers()

if self.command == 'GET':
request_line = f"{self.command} {parsed_url.path}?{parsed_url.query} HTTP/1.1\r\n"
headers = "\r\n".join([f"{k}: {v}" for k, v in self.headers.items()])
conn.sendall((request_line + headers + "\r\n\r\n").encode('utf-8'))

elif self.command == 'POST':
content_length = int(self.headers['Content-Length'])
post_data = self.rfile.read(content_length)
request_line = f"{self.command} {parsed_url.path} HTTP/1.1\r\n"
headers = "\r\n".join([f"{k}: {v}" for k, v in self.headers.items()])
conn.sendall((request_line + headers + "\r\n\r\n").encode('utf-8') + post_data)

with lock:
total_upload += content_length
current_upload += content_length

response_data = b""
while True:
data = conn.recv(8192)
if not data:
break
response_data += data
self.wfile.write(data)

with lock:
total_download += len(data)
current_download += len(data)

except Exception as e:
self.send_error(500, str(e).encode('ascii', 'replace').decode())
finally:
conn.close()

def print_status():
global current_upload, current_download, total_upload, total_download
while True:
time.sleep(1)
with lock:
# 转换当前上传和下载速率为 KB/s
current_upload_kb = current_upload / 1024
current_download_kb = current_download / 1024

# 转换总上传和下载数据量为 MB 或 GB
total_upload_mb = total_upload / (1024 * 1024)
total_download_mb = total_download / (1024 * 1024)

if total_upload_mb >= 1024:
total_upload_str = f"{total_upload_mb / 1024:.2f} GB"
else:
total_upload_str = f"{total_upload_mb:.2f} MB"

if total_download_mb >= 1024:
total_download_str = f"{total_download_mb / 1024:.2f} GB"
else:
total_download_str = f"{total_download_mb:.2f} MB"

print(f"\r当前上传: {current_upload_kb:.2f} KB/s | 当前下载: {current_download_kb:.2f} KB/s | 总上传: {total_upload_str} | 总下载: {total_download_str}", end='')
current_upload = 0
current_download = 0

def start_proxy_server():
PORT = 18888
httpd = socketserver.ThreadingTCPServer(('', PORT), ProxyHTTPRequestHandler)
threading.Thread(target=httpd.serve_forever, daemon=True).start()
print(f'本地HTTP代理服务器运行在端口 {PORT}')

if __name__ == '__main__':
# 启动状态显示线程
status_thread = threading.Thread(target=print_status)
status_thread.daemon = True
status_thread.start()

# 启动代理服务器
start_proxy_server()

# 保持主线程运行
while True:
time.sleep(1)

4. 运行代理服务器

在终端运行代理服务器:

1
python socks5_http_proxy.py

你会看到类似以下的输出:

1
2
本地HTTP代理服务器运行在端口 18888
当前上传: 0.00 KB/s | 当前下载: 0.00 KB/s | 总上传: 0.00 MB | 总下载: 0.00 MB

5. 使用代理服务器

在浏览器或其他支持代理配置的应用中,将代理设置为 http://localhost:18888

结语

通过这篇教程,我们成功地创建了一个通过SOCKS5代理转发的HTTP代理服务器,并在本地端口监听。你可以根据需要进行扩展和修改,以满足特定的需求。如果你有任何问题或建议,欢迎在评论区留言。