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

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

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

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

1. 安装所需库

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

pip install requests pysocks

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

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 的文件,内容如下:

[SOCKS5]
HOST=your_socks5_proxy_host
PORT=your_socks5_proxy_port
USERNAME=your_username
PASSWORD=your_password

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

3. 编写代码

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

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. 运行代理服务器

在终端运行代理服务器:

python socks5_http_proxy.py

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

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

5. 使用代理服务器

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

结语

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

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。