Документация Python неофициальный перевод

urllib2.md

451 строк · 36.0 КБ · обычная страница · сырой текст · скачать

1> **Источник:** https://python-all.ru/3.11/howto/urllib2.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# HOWTO получение интернет-ресурсов с помощью пакета urllib89**Автор:**1011[Michael Foord](https://python-all.ru/3.11/howto/urllib2.html)1213## Введение1415Связанные статьи1617Возможно, вам также будет полезна следующая статья о получении веб-ресурсов с помощью Python:1819- [Базовая аутентификация](https://python-all.ru/3.11/howto/urllib2.html)2021  > Учебник по *базовой аутентификации* с примерами на Python.2223**urllib.request** – это модуль Python для получения URL (Uniform Resource Locators). Он предоставляет очень простой интерфейс в виде функции *urlopen*. Она позволяет получать URL с использованием различных протоколов. Также доступен несколько более сложный интерфейс для обработки типовых ситуаций, таких как базовая аутентификация, куки, прокси и т. д. Они реализованы через объекты, называемые обработчиками и открывателями.2425urllib.request поддерживает получение URL для множества «схем URL» (определяемых строкой перед `":"` в URL – например, `"ftp"` – это схема URL для `"ftp://python.org/"`) с использованием соответствующих сетевых протоколов (например, FTP, HTTP). Данное руководство сосредоточено на наиболее распространённом случае – HTTP.2627Для простых случаев *urlopen* очень прост в использовании. Но как только при открытии HTTP-URL возникают ошибки или нестандартные ситуации, потребуется некоторое понимание протокола передачи гипертекста (HTTP). Наиболее полным и авторитетным справочником по HTTP является [**RFC 2616**](https://python-all.ru/3.11/howto/urllib2.html). Это технический документ, не предназначенный для лёгкого чтения. Данное HOWTO призвано проиллюстрировать использование *urllib* с достаточным количеством деталей по HTTP, чтобы помочь разобраться. Оно не заменяет документацию [`urllib.request`](https://python-all.ru/3.11/library/urllib.request.html#module-urllib.request), а дополняет её.2829## Загрузка URL3031Простейший способ использования urllib.request выглядит так:3233```python34import urllib.request35with urllib.request.urlopen('http://python.org/') as response:36   html = response.read()37```3839Если вы хотите получить ресурс по URL и сохранить его во временное расположение, это можно сделать с помощью функций [`shutil.copyfileobj()`](https://python-all.ru/3.11/library/shutil.html#shutil.copyfileobj) и [`tempfile.NamedTemporaryFile()`](https://python-all.ru/3.11/library/tempfile.html#tempfile.NamedTemporaryFile):4041```python42import shutil43import tempfile44import urllib.request4546with urllib.request.urlopen('http://python.org/') as response:47    with tempfile.NamedTemporaryFile(delete=False) as tmp_file:48        shutil.copyfileobj(response, tmp_file)4950with open(tmp_file.name) as html:51    pass52```5354Многие случаи использования urllib будут столь же просты (заметим, что вместо URL вида 'http:' можно было бы использовать URL, начинающийся с 'ftp:', 'file:' и т.д.). Однако цель этого руководства – объяснить более сложные случаи, сосредоточившись на HTTP.5556HTTP основан на запросах и ответах: клиент отправляет запросы, а серверы присылают ответы. urllib.request отражает это с помощью объекта `Request`, представляющего отправляемый HTTP-запрос. В простейшей форме вы создаёте объект Request, указывающий URL для получения. Вызов `urlopen` с этим объектом Request возвращает объект ответа для запрошенного URL. Этот ответ является файлоподобным объектом, что позволяет, например, вызвать `.read()` для него:5758```python59import urllib.request6061req = urllib.request.Request('http://python.org/')62with urllib.request.urlopen(req) as response:63   the_page = response.read()64```6566Обратите внимание, что urllib.request использует тот же интерфейс Request для обработки всех схем URL. Например, можно сделать FTP-запрос так:6768```python69req = urllib.request.Request('ftp://example.com/')70```7172В случае HTTP есть две дополнительные возможности, которые предоставляют объекты Request: во-первых, можно передавать данные, которые будут отправлены серверу. Во-вторых, можно передавать дополнительную информацию («метаданные») *о* данных или о самом запросе на сервер – эта информация отправляется как HTTP-заголовки. Рассмотрим каждую из них по порядку.7374### Данные7576Иногда требуется отправить данные на URL (часто URL будет ссылаться на CGI-скрипт или другое веб-приложение). В HTTP это обычно делается с помощью того, что называется **POST**-запросом. Именно так часто поступает браузер, когда вы отправляете заполненную HTML-форму в интернете. Не все POST-запросы должны приходить из форм: можно использовать POST для передачи произвольных данных в собственное приложение. В типичном случае HTML-форм данные нужно закодировать стандартным образом, а затем передать объекту Request в качестве аргумента `data`. Кодирование выполняется с помощью функции из библиотеки [`urllib.parse`](https://python-all.ru/3.11/library/urllib.parse.html#module-urllib.parse).7778```python79import urllib.parse80import urllib.request8182url = 'http://www.someserver.com/cgi-bin/register.cgi'83values = {'name' : 'Michael Foord',84          'location' : 'Northampton',85          'language' : 'Python' }8687data = urllib.parse.urlencode(values)88data = data.encode('ascii') # data должна быть типа bytes89req = urllib.request.Request(url, data)90with urllib.request.urlopen(req) as response:91   the_page = response.read()92```9394Обратите внимание, что иногда требуются другие кодировки (например, для загрузки файлов из HTML-форм – подробнее см. [Спецификацию HTML, раздел «Отправка формы»](https://python-all.ru/3.11/howto/urllib2.html)).9596Если не передавать аргумент `data`, urllib использует **GET**-запрос. Одно из различий между GET- и POST-запросами в том, что POST-запросы часто имеют «побочные эффекты»: они изменяют состояние системы (например, размещают заказ на сайте для доставки). Хотя стандарт HTTP указывает, что POST-запросы предназначены для того, чтобы *всегда* вызывать побочные эффекты, а GET-запросы – *никогда*, ничто не мешает GET-запросу иметь побочные эффекты, а POST-запросу – не иметь. Данные также можно передавать в HTTP GET-запросе, кодируя их прямо в URL.9798Это делается следующим образом:99100```python101>>> import urllib.request102>>> import urllib.parse103>>> data = {}104>>> data['name'] = 'Somebody Here'105>>> data['location'] = 'Northampton'106>>> data['language'] = 'Python'107>>> url_values = urllib.parse.urlencode(data)108>>> print(url_values)  # Порядок может отличаться от указанного ниже.  109name=Somebody+Here&language=Python&location=Northampton110>>> url = 'http://www.example.com/example.cgi'111>>> full_url = url + '?' + url_values112>>> data = urllib.request.urlopen(full_url)113```114115Обратите внимание, что полный URL создаётся добавлением `?` к URL, после которого следуют закодированные значения.116117### Заголовки118119Здесь будет рассмотрен один конкретный HTTP-заголовок, чтобы проиллюстрировать, как добавлять заголовки в HTTP-запросы.120121Некоторые сайты [\[1\]](https://python-all.ru/3.11/howto/urllib2.html#id8) не любят, когда их просматривают программы, либо отправляют разные версии разным браузерам [\[2\]](https://python-all.ru/3.11/howto/urllib2.html#id9). По умолчанию urllib идентифицирует себя как `Python-urllib/x.y` (где `x` и `y` – номера старшей и младшей версии релиза Python, например `Python-urllib/2.5`), что может сбить сайт с толку или просто не работать. Браузер идентифицирует себя через заголовок `User-Agent`[\[3\]](https://python-all.ru/3.11/howto/urllib2.html#id10). При создании объекта Request можно передать словарь заголовков. Следующий пример делает тот же запрос, что и выше, но идентифицирует себя как версию Internet Explorer [\[4\]](https://python-all.ru/3.11/howto/urllib2.html#id11).122123```python124import urllib.parse125import urllib.request126127url = 'http://www.someserver.com/cgi-bin/register.cgi'128user_agent = 'Mozilla/5.0 (Windows NT 6.1; Win64; x64)'129values = {'name': 'Michael Foord',130          'location': 'Northampton',131          'language': 'Python' }132headers = {'User-Agent': user_agent}133134data = urllib.parse.urlencode(values)135data = data.encode('ascii')136req = urllib.request.Request(url, data, headers)137with urllib.request.urlopen(req) as response:138   the_page = response.read()139```140141Ответ также имеет два полезных метода. См. раздел [info и geturl](https://python-all.ru/3.11/howto/urllib2.html#info-and-geturl), который следует после того, как мы рассмотрим, что происходит, когда что-то идёт не так.142143## Обработка исключений144145*urlopen* возбуждает [`URLError`](https://python-all.ru/3.11/library/urllib.error.html#urllib.error.URLError), когда не может обработать ответ (хотя, как обычно в Python API, могут также возбуждаться встроенные исключения, такие как [`ValueError`](https://python-all.ru/3.11/library/exceptions.html#ValueError), [`TypeError`](https://python-all.ru/3.11/library/exceptions.html#TypeError) и т.д.).146147[`HTTPError`](https://python-all.ru/3.11/library/urllib.error.html#urllib.error.HTTPError) является подклассом [`URLError`](https://python-all.ru/3.11/library/urllib.error.html#urllib.error.URLError), возбуждаемым в конкретном случае HTTP URL.148149Классы исключений экспортируются из модуля [`urllib.error`](https://python-all.ru/3.11/library/urllib.error.html#module-urllib.error).150151### URLError152153Часто URLError возникает из-за отсутствия сетевого соединения (нет маршрута к указанному серверу) или потому что указанный сервер не существует. В этом случае возбуждённое исключение будет иметь атрибут 'reason', который представляет собой кортеж, содержащий код ошибки и текстовое сообщение об ошибке.154155например156157```python158>>> req = urllib.request.Request('http://www.pretend_server.org')159>>> try: urllib.request.urlopen(req)160... except urllib.error.URLError as e:161...     print(e.reason)      162...163(4, 'getaddrinfo failed')164```165166### HTTPError167168Каждый HTTP-ответ от сервера содержит числовой «код состояния». Иногда код состояния указывает, что сервер не может выполнить запрос. Обработчики по умолчанию обрабатывают некоторые из таких ответов (например, если ответ представляет собой «перенаправление», которое просит клиента получить документ по другому URL, urllib обработает это). Для тех, которые не может обработать, urlopen возбудит [`HTTPError`](https://python-all.ru/3.11/library/urllib.error.html#urllib.error.HTTPError). Типичные ошибки включают «404» (страница не найдена), «403» (запрос запрещён) и «401» (требуется аутентификация).169170См. раздел 10 в [**RFC 2616**](https://python-all.ru/3.11/howto/urllib2.html) для справки по всем кодам ошибок HTTP.171172Возбуждённый экземпляр [`HTTPError`](https://python-all.ru/3.11/library/urllib.error.html#urllib.error.HTTPError) будет иметь целочисленный атрибут 'code', который соответствует ошибке, отправленной сервером.173174#### Коды ошибок175176Поскольку обработчики по умолчанию обрабатывают перенаправления (коды в диапазоне 300), а коды в диапазоне 100–299 указывают на успех, обычно вы будете видеть только коды ошибок в диапазоне 400–599.177178[`http.server.BaseHTTPRequestHandler.responses`](https://python-all.ru/3.11/library/http.server.html#http.server.BaseHTTPRequestHandler.responses) – это полезный словарь кодов ответа, который показывает все коды ответа, используемые [**RFC 2616**](https://python-all.ru/3.11/howto/urllib2.html). Словарь воспроизведён здесь для удобства179180```python181# Таблица, сопоставляющая коды ответов с сообщениями; записи имеют182# вид {code: (shortmessage, longmessage)}.183responses = {184    100: ('Continue', 'Request received, please continue'),185    101: ('Switching Protocols',186          'Switching to new protocol; obey Upgrade header'),187188    200: ('OK', 'Request fulfilled, document follows'),189    201: ('Created', 'Document created, URL follows'),190    202: ('Accepted',191          'Request accepted, processing continues off-line'),192    203: ('Non-Authoritative Information', 'Request fulfilled from cache'),193    204: ('No Content', 'Request fulfilled, nothing follows'),194    205: ('Reset Content', 'Clear input form for further input.'),195    206: ('Partial Content', 'Partial content follows.'),196197    300: ('Multiple Choices',198          'Object has several resources -- see URI list'),199    301: ('Moved Permanently', 'Object moved permanently -- see URI list'),200    302: ('Found', 'Object moved temporarily -- see URI list'),201    303: ('See Other', 'Object moved -- see Method and URL list'),202    304: ('Not Modified',203          'Document has not changed since given time'),204    305: ('Use Proxy',205          'You must use proxy specified in Location to access this '206          'resource.'),207    307: ('Temporary Redirect',208          'Object moved temporarily -- see URI list'),209210    400: ('Bad Request',211          'Bad request syntax or unsupported method'),212    401: ('Unauthorized',213          'No permission -- see authorization schemes'),214    402: ('Payment Required',215          'No payment -- see charging schemes'),216    403: ('Forbidden',217          'Request forbidden -- authorization will not help'),218    404: ('Not Found', 'Nothing matches the given URI'),219    405: ('Method Not Allowed',220          'Specified method is invalid for this server.'),221    406: ('Not Acceptable', 'URI not available in preferred format.'),222    407: ('Proxy Authentication Required', 'You must authenticate with '223          'this proxy before proceeding.'),224    408: ('Request Timeout', 'Request timed out; try again later.'),225    409: ('Conflict', 'Request conflict.'),226    410: ('Gone',227          'URI no longer exists and has been permanently removed.'),228    411: ('Length Required', 'Client must specify Content-Length.'),229    412: ('Precondition Failed', 'Precondition in headers is false.'),230    413: ('Request Entity Too Large', 'Entity is too large.'),231    414: ('Request-URI Too Long', 'URI is too long.'),232    415: ('Unsupported Media Type', 'Entity body in unsupported format.'),233    416: ('Requested Range Not Satisfiable',234          'Cannot satisfy request range.'),235    417: ('Expectation Failed',236          'Expect condition could not be satisfied.'),237238    500: ('Internal Server Error', 'Server got itself in trouble'),239    501: ('Not Implemented',240          'Server does not support this operation'),241    502: ('Bad Gateway', 'Invalid responses from another server/proxy.'),242    503: ('Service Unavailable',243          'The server cannot process the request due to a high load'),244    504: ('Gateway Timeout',245          'The gateway server did not receive a timely response'),246    505: ('HTTP Version Not Supported', 'Cannot fulfill request.'),247    }248```249250При возникновении ошибки сервер отвечает, возвращая HTTP код ошибки *и* страницу с ошибкой. Можно использовать экземпляр [`HTTPError`](https://python-all.ru/3.11/library/urllib.error.html#urllib.error.HTTPError) как ответ на возвращённой странице. Это означает, что помимо атрибута code, у него также есть методы read, geturl и info, как у возвращаемых модулем `urllib.response`:251252```python253>>> req = urllib.request.Request('http://www.python.org/fish.html')254>>> try:255...     urllib.request.urlopen(req)256... except urllib.error.HTTPError as e:257...     print(e.code)258...     print(e.read())  259...260404261b'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"262  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\n\n\n<html263  ...264  <title>Page Not Found</title>\n265  ...266```267268### Резюме269270Итак, если вы хотите быть готовым к [`HTTPError`](https://python-all.ru/3.11/library/urllib.error.html#urllib.error.HTTPError) *или* [`URLError`](https://python-all.ru/3.11/library/urllib.error.html#urllib.error.URLError), есть два основных подхода. Второй подход предпочтительнее.271272#### Способ 1273274```python275from urllib.request import Request, urlopen276from urllib.error import URLError, HTTPError277req = Request(someurl)278try:279    response = urlopen(req)280except HTTPError as e:281    print('The server couldn\'t fulfill the request.')282    print('Error code: ', e.code)283except URLError as e:284    print('We failed to reach a server.')285    print('Reason: ', e.reason)286else:287    # всё в порядке288```289290> **Примечание**291>292> `except HTTPError` *должен* идти первым, иначе `except URLError` *также* перехватит [`HTTPError`](https://python-all.ru/3.11/library/urllib.error.html#urllib.error.HTTPError).293294#### Способ 2295296```python297from urllib.request import Request, urlopen298from urllib.error import URLError299req = Request(someurl)300try:301    response = urlopen(req)302except URLError as e:303    if hasattr(e, 'reason'):304        print('We failed to reach a server.')305        print('Reason: ', e.reason)306    elif hasattr(e, 'code'):307        print('The server couldn\'t fulfill the request.')308        print('Error code: ', e.code)309else:310    # всё в порядке311```312313## info и geturl314315Ответ, возвращаемый urlopen (или экземпляр [`HTTPError`](https://python-all.ru/3.11/library/urllib.error.html#urllib.error.HTTPError)), имеет два полезных метода `info()` и `geturl()` и определён в модуле [`urllib.response`](https://python-all.ru/3.11/library/urllib.request.html#module-urllib.response).316317- **geturl** – возвращает реальный URL полученной страницы. Это полезно, поскольку `urlopen` (или используемый объект opener) мог выполнить перенаправление. URL полученной страницы может не совпадать с запрошенным URL.318- **info** – возвращает объект, подобный словарю, который описывает полученную страницу, в частности заголовки, отправленные сервером. В настоящее время это экземпляр [`http.client.HTTPMessage`](https://python-all.ru/3.11/library/http.client.html#http.client.HTTPMessage).319320Типичные заголовки включают ‘Content-length’, ‘Content-type’ и т.д. Смотрите [Краткий справочник HTTP-заголовков](https://python-all.ru/3.11/howto/urllib2.html) для полезного списка HTTP-заголовков с краткими пояснениями их значения и использования.321322## Открыватели и обработчики323324При получении URL используется opener (экземпляр, возможно, запутанно названного [`urllib.request.OpenerDirector`](https://python-all.ru/3.11/library/urllib.request.html#urllib.request.OpenerDirector)). Обычно используется стандартный opener – через `urlopen`, – но можно создавать собственные opener'ы. Opener'ы используют обработчики. Вся «тяжёлая работа» выполняется обработчиками. Каждый обработчик знает, как открывать URL для определённой схемы URL (http, ftp и т.д.) или как обрабатывать аспект открытия URL, например HTTP-перенаправления или HTTP-cookies.325326Стоит создавать собственные opener'ы, если нужно получать URL с установленными определёнными обработчиками, например чтобы получить opener, обрабатывающий cookies, или opener, не обрабатывающий перенаправления.327328Чтобы создать opener, создайте экземпляр `OpenerDirector`, а затем вызывайте `.add_handler(some_handler_instance)` несколько раз.329330В качестве альтернативы можно использовать `build_opener` – удобную функцию для создания объектов opener одним вызовом. `build_opener` по умолчанию добавляет несколько обработчиков, но предоставляет быстрый способ добавить ещё и/или переопределить стандартные обработчики.331332Другие типы обработчиков могут обрабатывать прокси, аутентификацию и другие распространённые, но слегка специализированные ситуации.333334`install_opener` можно использовать, чтобы сделать объект `opener` (глобальным) стандартным opener'ом. Это означает, что вызовы `urlopen` будут использовать установленный opener.335336Объекты opener имеют метод `open`, который можно вызывать напрямую для получения URL так же, как функцию `urlopen`: нет необходимости вызывать `install_opener`, кроме как для удобства.337338## Базовая аутентификация339340Для иллюстрации создания и установки обработчика мы будем использовать `HTTPBasicAuthHandler`. Для более подробного обсуждения этой темы – включая объяснение того, как работает базовая аутентификация, – смотрите [Руководство по базовой аутентификации](https://python-all.ru/3.11/howto/urllib2.html).341342Когда требуется аутентификация, сервер отправляет заголовок (а также код ошибки 401) с запросом аутентификации. В нём указывается схема аутентификации и «realm». Заголовок выглядит так: `WWW-Authenticate: SCHEME realm="REALM"`.343344например345346```text347WWW-Authenticate: Basic realm="cPanel Users"348```349350Затем клиент должен повторить запрос, включив в него соответствующие имя и пароль для данной области в качестве заголовка. Это и есть «базовая аутентификация». Чтобы упростить этот процесс, можно создать экземпляр `HTTPBasicAuthHandler` и opener для использования этого обработчика.351352`HTTPBasicAuthHandler` использует объект, называемый менеджером паролей, для обработки соответствия URL и областей паролям и именам пользователей. Если известно, какая область (из заголовка аутентификации, отправленного сервером), то можно использовать `HTTPPasswordMgr`. Часто область не важна. В этом случае удобно использовать `HTTPPasswordMgrWithDefaultRealm`. Это позволяет указать имя пользователя и пароль по умолчанию для URL. Они будут использованы при отсутствии альтернативной комбинации для конкретной области. Это указывается передачей `None` в качестве аргумента realm методу `add_password`.353354URL верхнего уровня – это первый URL, требующий аутентификации. URL «глубже», чем переданный в .add\_password(), также будут соответствовать.355356```python357# создать менеджер паролей358password_mgr = urllib.request.HTTPPasswordMgrWithDefaultRealm()359360# Добавить имя пользователя и пароль.361# Если бы мы знали realm, мы могли бы использовать его вместо None.362top_level_url = "http://example.com/foo/"363password_mgr.add_password(None, top_level_url, username, password)364365handler = urllib.request.HTTPBasicAuthHandler(password_mgr)366367# создать "opener" (экземпляр OpenerDirector)368opener = urllib.request.build_opener(handler)369370# использовать opener для получения URL371opener.open(a_url)372373# Установить opener.374# Теперь все вызовы urllib.request.urlopen будут использовать наш opener.375urllib.request.install_opener(opener)376```377378> **Примечание**379>380> В приведённом выше примере мы передали только наш `HTTPBasicAuthHandler` в `build_opener`. По умолчанию открыватели имеют обработчики для обычных ситуаций – `ProxyHandler` (если установлена настройка прокси, например переменная окружения `http_proxy`), `UnknownHandler`, `HTTPHandler`, `HTTPDefaultErrorHandler`, `HTTPRedirectHandler`, `FTPHandler`, `FileHandler`, `DataHandler`, `HTTPErrorProcessor`.381382`top_level_url` на самом деле *либо* полный URL (включая компонент схемы 'http:' и имя хоста и, опционально, номер порта), например `"http://example.com/"`, *либо* «authority» (т.е. имя хоста, опционально включая номер порта), например `"example.com"` или `"example.com:8080"` (последний пример включает номер порта). Authority, если присутствует, НЕ должен содержать компонент «userinfo» – например `"joe:password@example.com"` некорректно.383384## Прокси385386**urllib** автоматически определяет настройки прокси и использует их. Это происходит через `ProxyHandler`, который является частью обычной цепочки обработчиков при обнаружении настройки прокси. Обычно это хорошо, но бывают случаи, когда это может быть нежелательно [\[5\]](https://python-all.ru/3.11/howto/urllib2.html#id12). Один из способов – настроить собственный `ProxyHandler` без определённых прокси. Это делается аналогично настройке обработчика [базовой аутентификации](https://python-all.ru/3.11/howto/urllib2.html):387388```python389>>> proxy_support = urllib.request.ProxyHandler({})390>>> opener = urllib.request.build_opener(proxy_support)391>>> urllib.request.install_opener(opener)392```393394> **Примечание**395>396> В настоящее время `urllib.request` *не* поддерживает получение `https`-адресов через прокси. Однако это можно включить, расширив urllib.request, как показано в рецепте [\[6\]](https://python-all.ru/3.11/howto/urllib2.html#id13).397398> **Примечание**399>400> `HTTP_PROXY` будет проигнорирован, если установлена переменная `REQUEST_METHOD`; смотрите документацию по [`getproxies()`](https://python-all.ru/3.11/library/urllib.request.html#urllib.request.getproxies).401402## Сокеты и уровни403404Поддержка Python для получения ресурсов из сети является многоуровневой. urllib использует библиотеку [`http.client`](https://python-all.ru/3.11/library/http.client.html#module-http.client), которая, в свою очередь, использует библиотеку socket.405406Начиная с Python 2.3 можно указать, как долго сокет должен ждать ответа до истечения тайм-аута. Это может быть полезно в приложениях, которым приходится получать веб-страницы. По умолчанию модуль socket не имеет *тайм-аута* и может зависнуть. В настоящее время тайм-аут сокета не доступен на уровнях http.client или urllib.request. Однако можно установить глобальный тайм-аут по умолчанию для всех сокетов с помощью407408```python409import socket410import urllib.request411412# тайм-аут в секундах413timeout = 10414socket.setdefaulttimeout(timeout)415416# этот вызов urllib.request.urlopen теперь использует тайм-аут по умолчанию417# который мы установили в модуле socket418req = urllib.request.Request('http://www.voidspace.org.uk')419response = urllib.request.urlopen(req)420```421422---423424## Примечания425426Этот документ был проверен и доработан Джоном Ли.427428\[[1](https://python-all.ru/3.11/howto/urllib2.html#id1)\]429430Google, например.431432\[[2](https://python-all.ru/3.11/howto/urllib2.html#id2)\]433434Определение браузера (browser sniffing) – очень плохая практика для веб-дизайна: создание сайтов с использованием веб-стандартов гораздо разумнее. К сожалению, многие сайты до сих пор отправляют разные версии разным браузерам.435436\[[3](https://python-all.ru/3.11/howto/urllib2.html#id3)\]437438Пользовательский агент для MSIE 6 – *'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)'*439440\[[4](https://python-all.ru/3.11/howto/urllib2.html#id4)\]441442Подробнее о HTTP-заголовках запросов см. [Quick Reference to HTTP Headers](https://python-all.ru/3.11/howto/urllib2.html).443444\[[5](https://python-all.ru/3.11/howto/urllib2.html#id6)\]445446В моём случае на работе приходится использовать прокси для доступа в интернет. Если через этот прокси пытаться получить *localhost*-URL, он их блокирует. В IE настроено использование прокси, и urllib это подхватывает. Чтобы тестировать скрипты с локальным сервером, приходится запрещать urllib использовать прокси.447448\[[6](https://python-all.ru/3.11/howto/urllib2.html#id7)\]449450Открыватель urllib для SSL-прокси (метод CONNECT): [ASPN Cookbook Recipe](https://python-all.ru/3.11/howto/urllib2.html).451