首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在Python3.0中使用授权通过http下载文件,解决bug?

如何在Python3.0中使用授权通过http下载文件,解决bug?
EN

Stack Overflow用户
提问于 2008-12-27 21:45:48
回答 3查看 19.6K关注 0票数 9

我有一个我想继续使用的脚本,但看起来我要么不得不为Python3中的bug找到一些解决办法,要么降级回2.6,因此也不得不降级其他脚本……

希望这里有人已经找到了解决办法。

问题是,由于Python3.0中关于字节和字符串的新变化,显然并不是所有的库代码都经过了测试。

我有一个从web服务器下载页面的脚本。在python2.6中,此脚本将用户名和密码作为url的一部分进行传递,但在python3.0中,这不再起作用。

例如,如下所示:

代码语言:javascript
复制
import urllib.request;
url = "http://username:password@server/file";
urllib.request.urlretrieve(url, "temp.dat");

失败,并出现此异常:

代码语言:javascript
复制
Traceback (most recent call last):
  File "C:\Temp\test.py", line 5, in <module>
    urllib.request.urlretrieve(url, "test.html");
  File "C:\Python30\lib\urllib\request.py", line 134, in urlretrieve
    return _urlopener.retrieve(url, filename, reporthook, data)
  File "C:\Python30\lib\urllib\request.py", line 1476, in retrieve
    fp = self.open(url, data)
  File "C:\Python30\lib\urllib\request.py", line 1444, in open
    return getattr(self, name)(url)
  File "C:\Python30\lib\urllib\request.py", line 1618, in open_http
    return self._open_generic_http(http.client.HTTPConnection, url, data)
  File "C:\Python30\lib\urllib\request.py", line 1576, in _open_generic_http
    auth = base64.b64encode(user_passwd).strip()
  File "C:\Python30\lib\base64.py", line 56, in b64encode
    raise TypeError("expected bytes, not %s" % s.__class__.__name__)
TypeError: expected bytes, not str

显然,Base64编码现在需要字节数并输出一个字符串,因此构建username:password字符串并试图对其进行Base64编码以进行简单授权的urlretrieve (或其中的一些代码)失败。

如果我尝试使用urlopen,如下所示:

代码语言:javascript
复制
import urllib.request;
url = "http://username:password@server/file";
f = urllib.request.urlopen(url);
contents = f.read();

然后它会失败,并出现以下异常:

代码语言:javascript
复制
Traceback (most recent call last):
  File "C:\Temp\test.py", line 5, in <module>
    f = urllib.request.urlopen(url);
  File "C:\Python30\lib\urllib\request.py", line 122, in urlopen
    return _opener.open(url, data, timeout)
  File "C:\Python30\lib\urllib\request.py", line 359, in open
    response = self._open(req, data)
  File "C:\Python30\lib\urllib\request.py", line 377, in _open
    '_open', req)
  File "C:\Python30\lib\urllib\request.py", line 337, in _call_chain
    result = func(*args)
  File "C:\Python30\lib\urllib\request.py", line 1082, in http_open
    return self.do_open(http.client.HTTPConnection, req)
  File "C:\Python30\lib\urllib\request.py", line 1051, in do_open
    h = http_class(host, timeout=req.timeout) # will parse host:port
  File "C:\Python30\lib\http\client.py", line 620, in __init__
    self._set_hostport(host, port)
  File "C:\Python30\lib\http\client.py", line 632, in _set_hostport
    raise InvalidURL("nonnumeric port: '%s'" % host[i+1:])
http.client.InvalidURL: nonnumeric port: 'password@server'

显然,这个“下一代url检索库”中的url解析并不知道如何处理url中的用户名和密码。

我还有其他选择吗?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2008-12-27 22:04:53

直接从Py3k文档获取:http://docs.python.org/dev/py3k/library/urllib.request.html#examples

代码语言:javascript
复制
import urllib.request
# Create an OpenerDirector with support for Basic HTTP Authentication...
auth_handler = urllib.request.HTTPBasicAuthHandler()
auth_handler.add_password(realm='PDQ Application',
                          uri='https://mahler:8092/site-updates.py',
                          user='klem',
                          passwd='kadidd!ehopper')
opener = urllib.request.build_opener(auth_handler)
# ...and install it globally so it can be used with urlopen.
urllib.request.install_opener(opener)
urllib.request.urlopen('http://www.example.com/login.html')
票数 22
EN

Stack Overflow用户

发布于 2008-12-28 01:21:20

我的建议是将2.*分支保留为生产分支,直到您可以对3.0版本进行排序。

在迁移到Python3.0之前,我将等待一段时间。似乎有很多人在赶时间,但我只想把一切都理顺,并选择一个像样的第三方库。这可能需要一年,可能需要18个月,但“升级”的压力对我来说真的很低。

票数 0
EN

Stack Overflow用户

发布于 2021-03-25 17:51:47

您可以使用requests.get下载文件。尝试下面的示例代码:

代码语言:javascript
复制
import requests
from requests.auth import HTTPBasicAuth

def download_file(user_name, user_pwd, url, file_path):
    file_name = url.rsplit('/', 1)[-1]
    with requests.get(url, stream = True, auth = HTTPBasicAuth(user_name, user_pwd)) as response:
        with open(file_path + "/" + file_name, 'wb') as f:
            for chunk in response.iter_content(chunk_size = 8192):
                f.write(chunk)

# You will download the login.html file to /home/dan/
download_file("dan", "password", "http://www.example.com/login.html", "/home/dan/")

好好享受吧!!

与:https://stackoverflow.com/a/66796358/9265663相同

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/395451

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档