> **Источник:** https://python-all.ru/2.7/library/urllib.html
>
> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.

---

# 20.5. [`urllib`](https://python-all.ru/2.7/library/urllib.html#module-urllib) – Открытие произвольных ресурсов по URL

> **Примечание**
>
> Модуль [`urllib`](https://python-all.ru/2.7/library/urllib.html#module-urllib) разделён на части и переименован в Python 3 в `urllib.request`, `urllib.parse` и `urllib.error`. Инструмент [2to3](https://python-all.ru/2.7/glossary.html#term-2to3) автоматически адаптирует импорты при преобразовании исходников в Python 3. Также обратите внимание, что функция `urllib.request.urlopen()` в Python 3 эквивалентна [`urllib2.urlopen()`](https://python-all.ru/2.7/library/urllib2.html#urllib2.urlopen), а [`urllib.urlopen()`](https://python-all.ru/2.7/library/urllib.html#urllib.urlopen) удалена.

Данный модуль предоставляет высокоуровневый интерфейс для получения данных через Всемирную паутину. В частности, функция [`urlopen()`](https://python-all.ru/2.7/library/urllib.html#urllib.urlopen) похожа на встроенную функцию [`open()`](https://python-all.ru/2.7/library/functions.html#open), но принимает универсальные указатели ресурсов (URL) вместо имён файлов. Имеются некоторые ограничения: она может открывать URL только для чтения, и операции поиска (seek) недоступны.

> **См. также**
>
> Для высокоуровневого интерфейса HTTP-клиента рекомендуется [пакет Requests](https://python-all.ru/2.7/library/urllib.html).

Изменено в версии 2.7.9: Для HTTPS URI [`urllib`](https://python-all.ru/2.7/library/urllib.html#module-urllib) по умолчанию выполняет все необходимые проверки сертификатов и имён хостов.

> **Предупреждение**
>
> Для версий Python ранее 2.7.9 urllib не проверяет сертификаты серверов для HTTPS URI. Используйте на свой страх и риск!

## 20.5.1. Высокоуровневый интерфейс

#### `urllib.urlopen(url[, data[, proxies[, context]]])`

Открывает сетевой объект, обозначенный URL, для чтения. Если URL не имеет идентификатора схемы или имеет `file:` в качестве идентификатора схемы, открывается локальный файл (без [универсальных новых строк](https://python-all.ru/2.7/glossary.html#term-universal-newlines)); в противном случае открывается сокет к серверу где-то в сети. Если соединение не удалось, возникает исключение [`IOError`](https://python-all.ru/2.7/library/exceptions.html#exceptions.IOError). Если всё прошло успешно, возвращается файлоподобный объект. Он поддерживает следующие методы: `read()`, [`readline()`](https://python-all.ru/2.7/library/readline.html#module-readline), `readlines()`, `fileno()`, `close()`, `info()`, `getcode()` и `geturl()`. Также есть правильная поддержка протокола [итератора](https://python-all.ru/2.7/glossary.html#term-iterator). Одно предостережение: метод `read()` при опущенном или отрицательном аргументе size может не дочитать до конца потока данных; в общем случае нет хорошего способа определить, что весь поток из сокета прочитан.

За исключением методов `info()`, `getcode()` и `geturl()`, эти методы имеют тот же интерфейс, что и для файловых объектов – см. раздел [Файловые объекты](https://python-all.ru/2.7/library/stdtypes.html#bltin-file-objects) в данном руководстве. (Однако это не встроенный файловый объект, поэтому его нельзя использовать в тех немногих местах, где требуется настоящий встроенный файловый объект.)

Метод `info()` возвращает экземпляр класса [`mimetools.Message`](https://python-all.ru/2.7/library/mimetools.html#mimetools.Message), содержащий метаинформацию, связанную с URL. Когда метод HTTP, эти заголовки являются теми, что возвращаются сервером в начале полученной HTML-страницы (включая Content-Length и Content-Type). Когда метод FTP, заголовок Content-Length будет присутствовать, если (как это теперь обычно) сервер вернул длину файла в ответ на запрос получения по FTP. Заголовок Content-Type будет присутствовать, если можно угадать MIME-тип. Когда метод local-file, возвращаемые заголовки будут включать Date, представляющую время последнего изменения файла, Content-Length с размером файла и Content-Type с предположением о типе файла. См. также описание модуля [`mimetools`](https://python-all.ru/2.7/library/mimetools.html#module-mimetools).

Метод `geturl()` возвращает реальный URL страницы. В некоторых случаях HTTP-сервер перенаправляет клиента на другой URL. Функция [`urlopen()`](https://python-all.ru/2.7/library/urllib.html#urllib.urlopen) обрабатывает это прозрачно, но в некоторых случаях вызывающему коду нужно знать, на какой URL был перенаправлен клиент. Метод `geturl()` можно использовать для получения этого URL перенаправления.

Метод `getcode()` возвращает код состояния HTTP, отправленный с ответом, или `None`, если URL не является HTTP URL.

Если *url* использует идентификатор схемы `http:`, необязательный аргумент *data* может быть задан для указания `POST` запроса (обычно тип запроса `GET`). Аргумент *data* должен быть в стандартном формате *application/x-www-form-urlencoded*; см. функцию [`urlencode()`](https://python-all.ru/2.7/library/urllib.html#urllib.urlencode) ниже.

Функция [`urlopen()`](https://python-all.ru/2.7/library/urllib.html#urllib.urlopen) прозрачно работает с прокси, не требующими аутентификации. В среде Unix или Windows установите переменные окружения `http_proxy` или `ftp_proxy` в URL, идентифицирующий прокси-сервер, перед запуском интерпретатора Python. Например (`'%'` – это приглашение командной строки):

```python
% http_proxy="http://www.someproxy.com:3128"
% export http_proxy
% python
...
```

Переменная окружения `no_proxy` может использоваться для указания хостов, которые не должны достигаться через прокси; если она установлена, это должен быть разделённый запятыми список суффиксов имён хостов, опционально с добавлением `:port`, например `cern.ch,ncsa.uiuc.edu,some.host:8080`.

В среде Windows, если не заданы переменные окружения прокси, настройки прокси берутся из раздела Internet Settings реестра.

В среде Mac OS X [`urlopen()`](https://python-all.ru/2.7/library/urllib.html#urllib.urlopen) получает информацию о прокси из OS X System Configuration Framework, которой можно управлять через панель Network в Системных настройках.

В качестве альтернативы необязательный аргумент *proxies* можно использовать для явного указания прокси. Он должен быть словарём, отображающим имена схем в URL прокси; пустой словарь означает, что прокси не используются, а `None` (значение по умолчанию) приводит к использованию настроек прокси из окружения, как обсуждалось выше. Например:

```python
# Используйте http://www.someproxy.com:3128 для HTTP-проксирования
proxies = {'http': 'http://www.someproxy.com:3128'}
filehandle = urllib.urlopen(some_url, proxies=proxies)
# Не используйте никаких прокси
filehandle = urllib.urlopen(some_url, proxies={})
# Используйте прокси из окружения – обе версии эквивалентны
filehandle = urllib.urlopen(some_url, proxies=None)
filehandle = urllib.urlopen(some_url)
```

Прокси, требующие аутентификации для использования, в настоящее время не поддерживаются; это считается ограничением реализации.

Параметр *context* может быть установлен в экземпляр [`ssl.SSLContext`](https://python-all.ru/2.7/library/ssl.html#ssl.SSLContext) для настройки параметров SSL, которые используются, если [`urlopen()`](https://python-all.ru/2.7/library/urllib.html#urllib.urlopen) устанавливает HTTPS-соединение.

Изменено в версии 2.3: Добавлена поддержка *proxies*.

Изменено в версии 2.6: Добавлен `getcode()` к возвращаемому объекту и поддержка переменной окружения `no_proxy`.

Изменено в версии 2.7.9: Добавлен параметр *context*. Все необходимые проверки сертификатов и имён хостов выполняются по умолчанию.

Устарело с версии 2.6: Функция [`urlopen()`](https://python-all.ru/2.7/library/urllib.html#urllib.urlopen) удалена в Python 3 в пользу [`urllib2.urlopen()`](https://python-all.ru/2.7/library/urllib2.html#urllib2.urlopen).

#### `urllib.urlretrieve(url[, filename[, reporthook[, data[, context]]]])`

Копирует сетевой объект, обозначенный URL, в локальный файл, если это необходимо. Если URL указывает на локальный файл или существует допустимая кэшированная копия объекта, объект не копируется. Возвращает кортеж `(filename, headers)`, где *filename* – это имя локального файла, в котором можно найти объект, а *headers* – то, что вернул метод `info()` объекта, возвращённого [`urlopen()`](https://python-all.ru/2.7/library/urllib.html#urllib.urlopen) (для удалённого объекта, возможно, кэшированного). Исключения те же, что и для [`urlopen()`](https://python-all.ru/2.7/library/urllib.html#urllib.urlopen).

Второй аргумент, если присутствует, задаёт местоположение файла для копирования (если отсутствует, местоположением будет временный файл с автоматически сгенерированным именем). Третий аргумент, если присутствует, является вызываемым объектом, который будет вызван один раз при установлении сетевого соединения и один раз после каждого последующего чтения блока. Вызываемый объект будет получать три аргумента: количество переданных блоков на данный момент, размер блока в байтах и общий размер файла. Третий аргумент может быть `-1` на старых FTP-серверах, которые не возвращают размер файла в ответ на запрос получения.

Если *url* использует идентификатор схемы `http:`, необязательный аргумент *data* может быть задан для указания `POST` запроса (обычно тип запроса `GET`). Аргумент *data* должен быть в стандартном формате *application/x-www-form-urlencoded*; см. функцию [`urlencode()`](https://python-all.ru/2.7/library/urllib.html#urllib.urlencode) ниже.

Параметр *context* может быть установлен в экземпляр [`ssl.SSLContext`](https://python-all.ru/2.7/library/ssl.html#ssl.SSLContext) для настройки параметров SSL, которые используются, если [`urlretrieve()`](https://python-all.ru/2.7/library/urllib.html#urllib.urlretrieve) устанавливает HTTPS-соединение.

Изменено в версии 2.5: [`urlretrieve()`](https://python-all.ru/2.7/library/urllib.html#urllib.urlretrieve) будет вызывать [`ContentTooShortError`](https://python-all.ru/2.7/library/urllib.html#urllib.ContentTooShortError), когда обнаружит, что объём доступных данных меньше ожидаемого (который равен размеру, указанному в заголовке *Content-Length*). Это может произойти, например, при прерывании загрузки.

*Content-Length* рассматривается как нижняя граница: если есть ещё данные для чтения, [`urlretrieve()`](https://python-all.ru/2.7/library/urllib.html#urllib.urlretrieve) читает больше данных, но если доступно меньше данных, он вызывает исключение.

В этом случае вы всё ещё можете получить загруженные данные – они хранятся в атрибуте `content` экземпляра исключения.

Если заголовок *Content-Length* не был предоставлен, [`urlretrieve()`](https://python-all.ru/2.7/library/urllib.html#urllib.urlretrieve) не может проверить размер загруженных данных и просто возвращает их. В этом случае остаётся только предполагать, что загрузка прошла успешно.

Изменено в версии 2.7.9: Добавлен параметр *context*. Все необходимые проверки сертификатов и имен хостов выполняются по умолчанию.

#### `urllib._urlopener`

Публичные функции [`urlopen()`](https://python-all.ru/2.7/library/urllib.html#urllib.urlopen) и [`urlretrieve()`](https://python-all.ru/2.7/library/urllib.html#urllib.urlretrieve) создают экземпляр класса [`FancyURLopener`](https://python-all.ru/2.7/library/urllib.html#urllib.FancyURLopener) и используют его для выполнения запрошенных действий. Чтобы переопределить это поведение, программисты могут создать подкласс [`URLopener`](https://python-all.ru/2.7/library/urllib.html#urllib.URLopener) или [`FancyURLopener`](https://python-all.ru/2.7/library/urllib.html#urllib.FancyURLopener), а затем присвоить экземпляр этого класса переменной `urllib._urlopener` перед вызовом нужной функции. Например, приложения могут захотеть указать другой заголовок *User-Agent*, нежели тот, что определяет [`URLopener`](https://python-all.ru/2.7/library/urllib.html#urllib.URLopener). Это можно сделать с помощью следующего кода:

```python
import urllib

class AppURLopener(urllib.FancyURLopener):
    version = "App/1.7"

urllib._urlopener = AppURLopener()
```

#### `urllib.urlcleanup()`

Очищает кэш, который мог быть накоплен предыдущими вызовами [`urlretrieve()`](https://python-all.ru/2.7/library/urllib.html#urllib.urlretrieve).

## 20.5.2. Вспомогательные функции

#### `urllib.quote(string[, safe])`

Заменяет специальные символы в *строке* с помощью экранирования `%xx`. Буквы, цифры и символы `'_.-'` никогда не экранируются. По умолчанию эта функция предназначена для экранирования сегмента пути URL. Необязательный параметр *safe* задает дополнительные символы, которые не следует экранировать; его значение по умолчанию – `'/'`.

Пример: `quote('/~connolly/')` даёт `'/%7econnolly/'`.

#### `urllib.quote_plus(string[, safe])`

Как [`quote()`](https://python-all.ru/2.7/library/urllib.html#urllib.quote), но также заменяет пробелы знаками плюс, что требуется для квотирования значений HTML-форм при формировании строки запроса для URL. Знаки плюса в исходной строке экранируются, если они не включены в *safe*. Кроме того, значение по умолчанию для *safe* не равно `'/'`.

#### `urllib.unquote(string)`

Заменяет управляющие последовательности `%xx` на эквивалентные им одиночные символы.

Пример: `unquote('/%7Econnolly/')` даёт `'/~connolly/'`.

#### `urllib.unquote_plus(string)`

Как [`unquote()`](https://python-all.ru/2.7/library/urllib.html#urllib.unquote), но также заменяет знаки плюс пробелами, что требуется для расквотирования значений HTML-форм.

#### `urllib.urlencode(query[, doseq])`

Преобразует объект отображения (mapping) или последовательность кортежей из двух элементов в строку с «процентным кодированием», подходящую для передачи в качестве необязательного аргумента *data* функции [`urlopen()`](https://python-all.ru/2.7/library/urllib.html#urllib.urlopen), описанной выше. Это полезно для передачи словаря полей формы в запросе `POST`. Результирующая строка представляет собой серию пар `key=value`, разделенных символами `'&'`, где и *ключ*, и *значение* квотируются с помощью [`quote_plus()`](https://python-all.ru/2.7/library/urllib.html#urllib.quote_plus). Когда в качестве аргумента *query* используется последовательность кортежей из двух элементов, первый элемент каждого кортежа – ключ, а второй – значение. Само значение может быть последовательностью, и в этом случае, если необязательный параметр *doseq* имеет значение `True`, для каждого элемента последовательности-значения генерируются отдельные пары `key=value`, разделенные `'&'`. Порядок параметров в закодированной строке будет соответствовать порядку кортежей параметров в последовательности. Модуль [`urlparse`](https://python-all.ru/2.7/library/urlparse.html#module-urlparse) предоставляет функции `parse_qs()` и `parse_qsl()`, которые используются для разбора строк запроса в структуры данных Python.

#### `urllib.pathname2url(path)`

Преобразует имя пути *path* из локального синтаксиса в форму, используемую в компоненте пути URL. Эта функция не создает полный URL. Возвращаемое значение уже будет закодировано с помощью функции [`quote()`](https://python-all.ru/2.7/library/urllib.html#urllib.quote).

#### `urllib.url2pathname(path)`

Преобразует компонент пути *path* из URL с процентным кодированием в локальный синтаксис пути. Эта функция не принимает полный URL. Для декодирования *path* используется [`unquote()`](https://python-all.ru/2.7/library/urllib.html#urllib.unquote).

#### `urllib.getproxies()`

Эта вспомогательная функция возвращает словарь, сопоставляющий схему с URL прокси-сервера. Она сканирует переменные окружения с именем `<scheme>_proxy` (без учета регистра) сначала во всех операционных системах, а если не находит их, ищет информацию о прокси в системных конфигурациях Mac OS X и в реестре Windows. Если существуют переменные окружения как в нижнем, так и в верхнем регистре (и они различаются), предпочтение отдается нижнему регистру.

> **Примечание**
>
> Если установлена переменная окружения `REQUEST_METHOD`, что обычно указывает на выполнение скрипта в CGI-среде, переменная окружения `HTTP_PROXY` (в верхнем регистре `_PROXY`) будет проигнорирована. Это связано с тем, что эта переменная может быть вставлена клиентом через HTTP-заголовок «Proxy:». Если необходимо использовать HTTP-прокси в CGI-среде, либо явно используйте `ProxyHandler`, либо убедитесь, что имя переменной указано в нижнем регистре (или, по крайней мере, суффикс `_proxy`).

> **Примечание**
>
> Модуль urllib также предоставляет некоторые вспомогательные функции, такие как splittype, splithost и другие, для разбора URL на составные части. Однако рекомендуется использовать [`urlparse`](https://python-all.ru/2.7/library/urlparse.html#module-urlparse) для разбора URL, а не эти функции напрямую. В Python 3 эти вспомогательные функции не доступны из модуля `urllib.parse`.

## 20.5.3. Объекты URL Opener

#### `class urllib.URLopener([proxies[, context[, **x509]]])`

Базовый класс для открытия и чтения URL. Если не требуется поддержка открытия объектов с использованием схем, отличных от `http:`, `ftp:` или `file:`, вероятно, стоит использовать [`FancyURLopener`](https://python-all.ru/2.7/library/urllib.html#urllib.FancyURLopener).

По умолчанию класс [`URLopener`](https://python-all.ru/2.7/library/urllib.html#urllib.URLopener) отправляет заголовок *User-Agent* со значением `urllib/VVV`, где *VVV* – это номер версии [`urllib`](https://python-all.ru/2.7/library/urllib.html#module-urllib). Приложения могут задать собственный заголовок *User-Agent*, создав подкласс [`URLopener`](https://python-all.ru/2.7/library/urllib.html#urllib.URLopener) или [`FancyURLopener`](https://python-all.ru/2.7/library/urllib.html#urllib.FancyURLopener) и установив атрибут класса [`version`](https://python-all.ru/2.7/library/urllib.html#urllib.URLopener.version) в соответствующее строковое значение в определении подкласса.

Необязательный параметр *proxies* должен быть словарём, сопоставляющим имена схем с URL прокси. Пустой словарь полностью отключает прокси. Значение по умолчанию – `None`; в этом случае используются настройки прокси из окружения (если они есть), как описано выше в определении [`urlopen()`](https://python-all.ru/2.7/library/urllib.html#urllib.urlopen).

Параметр *context* может быть экземпляром [`ssl.SSLContext`](https://python-all.ru/2.7/library/ssl.html#ssl.SSLContext). Если он задан, то определяет настройки SSL, которые открыватель использует для HTTPS-соединений.

Дополнительные именованные параметры, собранные в *x509*, могут использоваться для аутентификации клиента при использовании схемы `https:`. Поддерживаются ключевые слова *key\_file* и *cert\_file* для указания SSL-ключа и сертификата; оба необходимы для поддержки аутентификации клиента.

Объекты [`URLopener`](https://python-all.ru/2.7/library/urllib.html#urllib.URLopener) возбуждают исключение [`IOError`](https://python-all.ru/2.7/library/exceptions.html#exceptions.IOError), если сервер возвращает код ошибки.

Изменено в версии 2.7.9: Добавлен параметр *context*. Все необходимые проверки сертификатов и имен хостов выполняются по умолчанию.

#### `open(fullurl[, data])`

Открывает *fullurl*, используя соответствующий протокол. Этот метод настраивает кеш и информацию о прокси, а затем вызывает соответствующий метод open с переданными аргументами. Если схема не распознана, вызывается [`open_unknown()`](https://python-all.ru/2.7/library/urllib.html#urllib.URLopener.open_unknown). Аргумент *data* имеет то же значение, что и аргумент *data* метода [`urlopen()`](https://python-all.ru/2.7/library/urllib.html#urllib.urlopen).

#### `open_unknown(fullurl[, data])`

Переопределяемый интерфейс для открытия неизвестных типов URL.

#### `retrieve(url[, filename[, reporthook[, data]]])`

Извлекает содержимое *url* и помещает его в *filename*. Возвращаемое значение – кортеж, состоящий из локального имени файла и либо объекта [`mimetools.Message`](https://python-all.ru/2.7/library/mimetools.html#mimetools.Message), содержащего заголовки ответа (для удаленных URL), либо `None` (для локальных URL). Затем вызывающий код должен открыть и прочитать содержимое *filename*. Если *filename* не указан и URL ссылается на локальный файл, возвращается исходное имя файла. Если URL не локальный и *filename* не указан, имя файла генерируется функцией [`tempfile.mktemp()`](https://python-all.ru/2.7/library/tempfile.html#tempfile.mktemp) с суффиксом, соответствующим суффиксу последнего компонента пути исходного URL. Если задан *reporthook*, он должен быть функцией, принимающей три числовых параметра. Она будет вызываться после каждого блока данных, считанного из сети. *reporthook* игнорируется для локальных URL.

Если *url* использует идентификатор схемы `http:`, можно задать необязательный аргумент *data* для указания запроса типа `POST` (обычно тип запроса – `GET`). Аргумент *data* должен иметь стандартный формат *application/x-www-form-urlencoded*; см. функцию [`urlencode()`](https://python-all.ru/2.7/library/urllib.html#urllib.urlencode) ниже.

#### `version`

Переменная, задающая пользовательский агент объекта opener. Чтобы [`urllib`](https://python-all.ru/2.7/library/urllib.html#module-urllib) сообщал серверам, что он является определённым пользовательским агентом, установите это значение в подклассе как переменную класса или в конструкторе перед вызовом конструктора базового класса.

#### `class urllib.FancyURLopener(...)`

[`FancyURLopener`](https://python-all.ru/2.7/library/urllib.html#urllib.FancyURLopener) является подклассом [`URLopener`](https://python-all.ru/2.7/library/urllib.html#urllib.URLopener), обеспечивающим стандартную обработку следующих HTTP-кодов ответа: 301, 302, 303, 307 и 401. Для перечисленных кодов 30x используется заголовок *Location* для получения фактического URL. Для кода 401 (требуется аутентификация) выполняется базовая HTTP-аутентификация. Для кодов 30x количество рекурсий ограничено значением атрибута *maxtries*, которое по умолчанию равно 10.

Для всех остальных кодов ответа вызывается метод `http_error_default()`, который можно переопределить в подклассах для соответствующей обработки ошибки.

> **Примечание**
>
> В соответствии с буквой [**RFC 2616**](https://python-all.ru/2.7/library/urllib.html), ответы 301 и 302 на POST-запросы не должны автоматически перенаправляться без подтверждения пользователем. На практике браузеры всё же допускают автоматическое перенаправление таких ответов, заменяя POST на GET, и [`urllib`](https://python-all.ru/2.7/library/urllib.html#module-urllib) воспроизводит это поведение.

Параметры конструктора такие же, как для [`URLopener`](https://python-all.ru/2.7/library/urllib.html#urllib.URLopener).

> **Примечание**
>
> При выполнении базовой аутентификации экземпляр [`FancyURLopener`](https://python-all.ru/2.7/library/urllib.html#urllib.FancyURLopener) вызывает свой метод [`prompt_user_passwd()`](https://python-all.ru/2.7/library/urllib.html#urllib.FancyURLopener.prompt_user_passwd). Реализация по умолчанию запрашивает у пользователя необходимую информацию на управляющем терминале. Подкласс может переопределить этот метод для обеспечения более подходящего поведения, если это необходимо.

Класс [`FancyURLopener`](https://python-all.ru/2.7/library/urllib.html#urllib.FancyURLopener) предоставляет один дополнительный метод, который следует перегрузить для обеспечения соответствующего поведения:

#### `prompt_user_passwd(host, realm)`

Возвращает информацию, необходимую для аутентификации пользователя на указанном хосте в заданной области безопасности. Возвращаемое значение должно быть кортежем `(user, password)`, который можно использовать для базовой аутентификации.

Реализация запрашивает эту информацию на терминале; приложение должно переопределить этот метод, чтобы использовать подходящую модель взаимодействия в локальной среде.

#### `exception urllib.ContentTooShortError(msg[, content])`

Это исключение возникает, когда функция [`urlretrieve()`](https://python-all.ru/2.7/library/urllib.html#urllib.urlretrieve) обнаруживает, что объем загруженных данных меньше ожидаемого (указанного в заголовке *Content-Length*). Атрибут `content` хранит загруженные (и предположительно усеченные) данные.

Новое в версии 2.5.

## 20.5.4. [`urllib`](https://python-all.ru/2.7/library/urllib.html#module-urllib) Ограничения

>

- В настоящее время поддерживаются только следующие протоколы: HTTP (версии 0.9 и 1.0), FTP и локальные файлы.
- Функция кэширования [`urlretrieve()`](https://python-all.ru/2.7/library/urllib.html#urllib.urlretrieve) отключена, пока я не найду время реализовать правильную обработку заголовков срока действия.
- Должна быть функция для проверки, находится ли определённый URL в кэше.
- Для обратной совместимости, если URL указывает на локальный файл, но файл не удаётся открыть, URL интерпретируется заново с использованием протокола FTP. Это иногда может приводить к запутанным сообщениям об ошибках.
- Функции [`urlopen()`](https://python-all.ru/2.7/library/urllib.html#urllib.urlopen) и [`urlretrieve()`](https://python-all.ru/2.7/library/urllib.html#urllib.urlretrieve) могут вызывать произвольно длинные задержки при ожидании установки сетевого соединения. Это означает, что с помощью этих функций сложно построить интерактивный веб-клиент без использования потоков.
- Данные, возвращаемые [`urlopen()`](https://python-all.ru/2.7/library/urllib.html#urllib.urlopen) или [`urlretrieve()`](https://python-all.ru/2.7/library/urllib.html#urllib.urlretrieve), представляют собой необработанные данные, возвращенные сервером. Это могут быть двоичные данные (например, изображение), обычный текст или HTML. Протокол HTTP предоставляет информацию о типе в заголовке ответа, который можно проверить, посмотрев на заголовок *Content-Type*. Если возвращенные данные – HTML, можно воспользоваться модулем [`htmllib`](https://python-all.ru/2.7/library/htmllib.html#module-htmllib) для его разбора.
- Код, обрабатывающий протокол FTP, не может различить файл и каталог. Это может привести к неожиданному поведению при попытке чтения URL, указывающего на недоступный файл. Если URL заканчивается на `/`, предполагается, что он ссылается на каталог, и будет обработан соответствующим образом. Но если попытка чтения файла приводит к ошибке 550 (означает, что URL не найден или недоступен, часто из-за прав доступа), то путь рассматривается как каталог, чтобы обработать случай, когда каталог указан URL, но завершающий `/` опущен. Это может привести к вводящим в заблуждение результатам при попытке получить файл, права на чтение которого делают его недоступным; FTP-код попытается прочитать его, завершится ошибкой 550, а затем выполнит вывод списка каталога для этого недоступного файла. Если требуется тонкий контроль, стоит рассмотреть использование модуля [`ftplib`](https://python-all.ru/2.7/library/ftplib.html#module-ftplib), создание подкласса [`FancyURLopener`](https://python-all.ru/2.7/library/urllib.html#urllib.FancyURLopener) или изменение *\_urlopener* в соответствии со своими потребностями.
- Этот модуль не поддерживает использование прокси, требующих аутентификации. Возможно, эта возможность будет реализована в будущем.
- Хотя модуль [`urllib`](https://python-all.ru/2.7/library/urllib.html#module-urllib) содержит (недокументированные) функции для разбора и сборки URL-строк, рекомендуемый интерфейс для работы с URL находится в модуле [`urlparse`](https://python-all.ru/2.7/library/urlparse.html#module-urlparse).

## 20.5.5. Примеры

Вот пример сеанса, в котором используется метод `GET` для получения URL с параметрами:

```python
>>> import urllib
>>> params = urllib.urlencode({'spam': 1, 'eggs': 2, 'bacon': 0})
>>> f = urllib.urlopen("http://www.musi-cal.com/cgi-bin/query?%s" % params)
>>> print f.read()
```

В следующем примере вместо этого используется метод `POST`:

```python
>>> import urllib
>>> params = urllib.urlencode({'spam': 1, 'eggs': 2, 'bacon': 0})
>>> f = urllib.urlopen("http://www.musi-cal.com/cgi-bin/query", params)
>>> print f.read()
```

В следующем примере используется явно указанный HTTP-прокси, переопределяющий настройки окружения:

```python
>>> import urllib
>>> proxies = {'http': 'http://proxy.example.com:8080/'}
>>> opener = urllib.FancyURLopener(proxies)
>>> f = opener.open("http://www.python.org")
>>> f.read()
```

В следующем примере прокси не используются вовсе, переопределяя настройки окружения:

```python
>>> import urllib
>>> opener = urllib.FancyURLopener({})
>>> f = opener.open("http://www.python.org/")
>>> f.read()
```
