【问题标题】:Execute python script using urllib2 from PHP behind Proxy使用 urllib2 从 Proxy 后面的 PHP 执行 python 脚本
【发布时间】:2013-06-14 18:46:04
【问题描述】:

我有一个 Python 脚本,它使用 urllib2 从外部站点检索数据。 我在需要代理身份验证的公司网络上。

在命令行上时,我可以在 .bashrc 中导出代理设置,以允许脚本通过代理退出并发出请求。

所以脚本确实在代理后面工作。

问题来了: 我需要从网站上的 php 脚本调用这个 Python 脚本。 我已经尝试了几种方法来通过调用脚本来实现这一点: exec()、popen()、shell_exec()

我无法让脚本返回任何结果。 拖尾时 /var/log/httpd/error** 我可以看到正在生成的错误:

urllib2.URLError: <urlopen error [Errno 110] Connection timed out>, referer:

这与我在 .bashrc 中设置代理之前收到的错误相同

我已将 suPHP 设置并配置为以特定用户身份运行脚本。 我还设置了所有文件,包括该用户拥有的 python 脚本,并调整了权限,尝试 +x 并且出于测试目的不安全地设置为 777。

我可以从网站的同一目录运行一个 php 脚本,并验证 Apache 是否在此用户下运行,只需简单:

echo exec('whoami');

我还可以使用相同的设置从同一个 PHP 页面执行一个简单的 Python 脚本,该设置只打印到标准输出,我可以将该值返回到网页,所以我知道我可以使用这种方法执行 Python 脚本。

在命令行中,我使用与运行 Apache 的用户相同的用户,并在该帐户中设置代理,但是从网页执行时脚本仍然无法正确执行,仍然仅适用于 CLI。

只是为了测试,我在 Python 脚本中添加了一行写入文件,目的是将数据写入我需要返回的文件,并认为我可以在之后读取该文件。 我注意到,文件的创建工作,但没有数据写入它,因为 urllib2 代码超时并且从不写入文件。

知道如何让我的 PHP 脚本执行这个需要代理访问的 Python 脚本吗?

我需要明确告诉 urllib2 使用代理吗? 我正在使用的 urllib2 例程是 Python 模块的一部分,该模块被编码为仅使用操作系统的代理设置,而且我知道它可以工作,因为我可以在 CLI 的 Apache 用户下执行它。

非常感谢任何帮助。

【问题讨论】:

    标签: php python apache urllib2


    【解决方案1】:

    要通知 urllib2 使用代理,您可以使用 ProxyHandler:

    proxy = urllib2.ProxyHandler({'http': '127.0.0.1'})
    opener = urllib2.build_opener(proxy)
    urllib2.install_opener(opener)
    urllib2.urlopen('http://www.google.com')
    

    令人惊讶的是,您必须明确地这样做,因为urlopen 的文档说:

    此外,如果检测到代理设置(例如,设置了 *_proxy 环境变量,如 http_proxy),则默认安装 ProxyHandler 并确保通过代理处理请求。

    您是否在脚本运行的环境中正确设置了 http_proxy 环境变量?


    您将在上一个问题中找到有关如何将代理与 urllib2 一起使用的更多信息:Proxy with urllib2

    【讨论】:

    • 是的。假设我的 apache 用户名为“bob”。我已经进入 bob,并将 http_proxy 设置为“bob”,它占 .bashrc。我还可以在登录“bob”时执行脚本。 urllib2 确实检测到此代理设置并执行,但它仅在通过命令行执行时才以这种方式工作。
    • @luskbo 不确定是否理解。但是...通常 CGI 脚本使用一组非常有限的环境变量运行。也许 http_proxy 没有在那个上下文中设置?
    • @luskbo 对于 Apache,有一个 SetEnv 指令可以控制 CGI 的环境变量。看看吧httpd.apache.org/docs/2.2/env.html
    • 首先,最终修复它的是显式设置代理值。不知道为什么 urllib2 没有像它应该做的那样采用操作系统设置值,但是从 php 执行它的一些事情打破了这一点。我的 SetEvn 中包含 php 和 python 的路径,所以我不确定这是怎么回事。 SetEnv PATH /usr/bin:/usr/local/bin:/bin:/usr/bin/python:/usr/bin/php 但是在这种情况下明确设置代理确实有效,所以谢谢!!!
    【解决方案2】:

    您可以尝试将显式代理设置传递给您的 Python 脚本,看看是否可以为您解决问题。我最近编写了一个脚本,允许您使用可能对这种情况有用的命令行参数设置代理设置。脚本的重要部分如下:

    # Import the required libraries
    from urllib import urlencode
    from urllib2 import Request, urlopen, URLError, ProxyHandler, build_opener, install_opener
    import argparse
    
    # Set up our argument parser
    parser = argparse.ArgumentParser(description='Does stuff through a proxy')
    parser.add_argument('webAddr', type=str, help='Web address of target server')
    parser.add_argument('--proxServ', metavar='SERV', type=str, help='Web address of proxy server, i.e. http://proxy.server.com:80')
    parser.add_argument('--proxType', metavar='TYPE', type=str, default='http', help='Type of proxy server, i.e. http')
    
    # Get the arguments from the parser
    args = parser.parse_args()
    
    # Define data to pass to server (could generate this from arguments as well)
    values = {'name': 'data'}   # generate data to pass to server
    
    # Define proxy settings if proxy server is input.
    if args.proxServ:       # set up the proxy server support
        proxySupport = ProxyHandler({args.proxType: args.proxServ})
        opener = build_opener(proxySupport)
        install_opener(opener)
    
    # Set up the data object
    data = urlencode(values)
    data = data.encode('utf-8')
    
    # Send request to the server and receive response, with error handling!
    try:
        req = Request(args.webAddr, data)
    
        # Read the response and print to a file
        response = urlopen(req)
        print response.read()
    
    except URLError, e:
        if hasattr(e, 'reason'):    # URL error case
            # a tuple containing error code and text error message
            print 'Error: Failed to reach a server.'
            print 'Reason: ', e.reason
        elif hasattr(e, 'code'):    # HTTP error case
            # HTTP error code, see section 10 of RFC 2616 for details
            print 'Error: The server could not fulfill the request.'
            print 'Error code: ', e.code
    

    urllib2 应该使用您的系统设置进行任何代理处理,但我想有时这可能无法按您希望的方式工作。明确定义设置可能不会受到伤害。您也可以查看this document 了解更多信息。

    【讨论】:

    • 我会试一试并评论结果。非常感谢。
    • 太棒了,很高兴听到它有帮助!
    猜你喜欢
    • 2018-01-29
    • 2015-10-26
    • 1970-01-01
    • 2015-03-22
    • 2021-12-06
    • 1970-01-01
    • 2019-09-23
    • 1970-01-01
    相关资源
    最近更新 更多