Localproxy-优雅地在Python中使用代理

2024-08-04T06:26:09Z | 2 分钟阅读 | 更新于 2024-08-04T06:26:09Z

@ Evens Xia

Localproxy 使用指南

先上 repo 地址:https://github.com/EvensXia/localproxy

最近因为工作原因,经常需要在代码中访问 HuggingFace,目前访问 HF 主要是通过配置环境变量的方式,以下是常用的几种方法:

常见使用代理的方法

1. 临时使用

命令行直接执行:

export http_proxy=http://proxy-server:port
export https_proxy=https://proxy-server:port

或者:

http_proxy=http://proxy-server:port https_proxy=https://proxy-server:port python xxx.py

2. 配置终端环境变量

将代理设置添加到 .bashrc 文件中:

echo "export http_proxy=http://proxy-server:port" >> ~/.bashrc
echo "export https_proxy=https://proxy-server:port" >> ~/.bashrc

以上方法虽然可以使用,但都不太灵活。临时使用的方式需要每次都要配置脚本,而写死在终端配置里又不能做到细分应用。因此,想设计一个在 Python 中优雅地使用代理的方案。


localproxy

设计思路

我需要一个简单的命令行工具来配置和使用代理,并且能够将配置保存到文件中,人工也方便修改。

需求

  1. 需要一个cli命令脚本,支持list/set/clear等方式配置代理
  2. 需要将proxy配置保存到用户目录中(这里需要考虑多系统之间的差异)
  3. 在代码中能够最简单地调用从而修改环境变量实现代理的使用
  4. *可以用cli命令执行python代码

实现

  • 需求1+4:localproxy/cli.py

    这里最开始使用的还是click的方案,后来发现click实现杂糅式的命令行有点复杂,所以改成了原始的sys.argvargparse,先解析argv[1],如果不是.py的Python脚本,则进入命令行解析; 命令行主要需要支持以下几种形式:

    localproxy set/list/clear [arg1 arg2]
    localproxy xxx.py [args...]
    localproxy -m/-c module.name/"python code" [args...]
    

    解析过程实现(这里还额外增加了.py的help说明):

    def main():
        parser = argparse.ArgumentParser(
            description="Local Proxy CLI\n\n"
                        "To run a Python script directly: \n"
                        "  localproxy <script.py> [args]\n\n"
                        "Sub-commands:")
    
        subparsers = parser.add_subparsers(dest="command", help="Sub-commands")
        set_parser = subparsers.add_parser("set", help="Set a proxy configuration")
        set_parser.add_argument("protocol", type=str, help="Protocol to set (e.g., http, https)")
        set_parser.add_argument("address", type=str, help="Proxy address (e.g., http://proxy.example.com:8080)")
        set_parser.set_defaults(func=set_proxy)
        subparsers.add_parser("list", help="List existing proxy configurations").set_defaults(func=list_proxies)
        subparsers.add_parser("clear", help="Clear all proxy configurations").set_defaults(func=clear_proxies)
        parser.add_argument("-m", "--module", nargs="+", help="Module to run")
        parser.add_argument("-c", "--code", nargs="+", help="Code to run")
    
        if len(sys.argv) > 1 and sys.argv[1].endswith(".py"):
            original_args = sys.argv[1:]
            run_script(original_args[0], original_args[1:])
        else:
            args, _ = parser.parse_known_args()
            if args.command == "set":
                set_proxy(args.protocol, args.address)
            elif args.command:
                args.func()
            elif args.module:
                run_module(args.module[0], args.module[1:])
            elif args.code:
                run_code(args.code[0], args.code[1:])
            else:
                parser.print_help()
    
  • 需求2+3:localproxy/proxy.py 代码:

    import os
    
    import toml
    
    
    class ProxyConfig:
        def __init__(self, config_file):
            self.config_file = config_file
    
        def load(self):
            """Load proxy configuration from the file."""
            if os.path.exists(self.config_file):
                with open(self.config_file, 'r') as f:
                    return toml.load(f)
            return {}
    
        def save(self, proxies):
            """Save proxy configuration to the file."""
            os.makedirs(os.path.dirname(self.config_file), exist_ok=True)
            with open(self.config_file, 'w') as f:
                toml.dump(proxies, f)
    
    
    def init():
        """Apply proxy settings to os.environ."""
        config = ProxyConfig(os.path.expanduser("~/.local_proxy/proxy.toml"))
        proxies = config.load()
        for protocol, address in proxies.items():
            os.environ[f"{protocol}_proxy"] = address
    

    这里使用了os.path.expanduser~符号来确定系统的用户目录; init函数主要提供给导入式的使用方式使用。


使用案例

如在huggingface中加载squad数据集,可以这么写:

from datasets import load_dataset
from localproxy import proxy

proxy.init()

load_dataset(path='squad', split="train")

而在cli命令中,就不需要使用额外的代码,以上还可以用这种方式实现:

from datasets import load_dataset

load_dataset(path='squad', split="train")

代码中不使用代理,保存成load_squad.py 命令行中:

localproxy load_squad.py

可以实现同样的应用代理的效果。

© 2024 Evens Xia's Blog

🌱 Powered by Hugo with theme Dream.

About Me

欢迎来到我的博客

简介

你好,我叫 EvensXia,这是我的博客。我会不定时将我自己认为有意思的事情放在这上面,有一些是技术性的,有一些则是有关生活类的。当然,你也可以投稿。我正努力打造一个有趣的网站。


Welcome to My Blog

Introduction

Hello, my name is EvensXia, and this is my blog. I will occasionally post things that I find interesting here. Some are technical, while others are related to life. Of course, you can also contribute. I’m working hard to create an engaging website.

社交链接