Как скачать файл по http с авторизацией в python 3.0, обходя ошибки?

У меня есть сценарий, который я хотел бы продолжить использовать, но похоже, что мне нужно либо найти обходной путь для ошибки в Python 3, либо вернуться к версии 2.6 и, таким образом, перейти на более раннюю версию других сценариев ...

Надеюсь, кому-то здесь уже удалось найти обходной путь.

Проблема в том, что из-за новых изменений в Python 3.0, касающихся байтов и строк, не весь код библиотеки, по-видимому, протестирован.

У меня есть сценарий, который загружает страницу с веб-сервера. Этот скрипт передал имя пользователя и пароль как часть URL-адреса в Python 2.6, но в Python 3.0 это больше не работает.

Например, это:

import urllib.request;
url = "http://username:password@server/file";
urllib.request.urlretrieve(url, "temp.dat");

не работает с этим исключением:

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 теперь требует байтов и выводит строку, и, таким образом, urlretrieve (или некоторый код в нем), который создает строку имя пользователя: пароль и пытается кодировать base64 для простой авторизации, терпит неудачу.

Если вместо этого я попытаюсь использовать urlopen, например:

import urllib.request;
url = "http://username:password@server/file";
f = urllib.request.urlopen(url);
contents = f.read();

Затем это не удается с этим исключением:

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.

Какие еще варианты у меня есть?

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
9
0
19 038
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Напрямую из документов Py3k: http://docs.python.org/dev/py3k/library/urllib.request.html#examples

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')

вы хотели опубликовать этот пароль? Если нет, то предлагаю удалить ответ и опубликовать новый с фиктивными данными. Спасибо за ответ, это выглядит многообещающе.

Lasse V. Karlsen 28.12.2008 02:11

Клем, наверное, очень зол, если это его настоящий пароль :)

jb. 28.12.2008 02:38

Я бы посоветовал сохранить вашу ветку 2. * в качестве производственной, пока вы не отсортируете материал 3.0.

Я собираюсь немного подождать, прежде чем перейти на Python 3.0. Кажется, много людей спешат, но я просто хочу, чтобы все разобралось и был приличный выбор сторонних библиотек. Это может занять год, может занять 18 месяцев, но необходимость «обновления» для меня очень низка.

Вы можете использовать request.get для загрузки файла. Попробуйте пример кода:

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

Другие вопросы по теме