Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

[ Россум, Дрейк, Откидач ] Язык программирования Python

.pdf
Скачиваний:
300
Добавлен:
25.04.2014
Размер:
1.5 Mб
Скачать

27.1. cgi — протокол CGI

361

escape(s [, quote])

Заменяет символы ‘&’, ‘<’ и ‘>’ в строке s на соответствующие сущности HTML. Используйте эту функцию для вывода текста, который может содержать такие символы. Если задан и является истиной аргумент quote, также заменяет символ двойной кавычки (‘"’), что может быть полезно для вывода значений атрибутов (например, ‘’a href=\ + escape(url, 1) + ’»’’).

Кроме того, модуль предоставляет средства для ведения log-файла:

logfile

Если эта переменная имеет непустое значение, она определяет имя log-файла. Используется только, если переменная logfp является ложью.

logfp

Файловый (или подобный) объект, соответствующий log-файлу.

log(format [, *args])

Записывает строку ‘format % args + ’\n’’ в log-файл, определяемый значениями переменных logfile и logfp при первом вызове функции. Если в момент первого вызова этой функции обе переменный являются ложью, этот и все последующие вызовы функции ничего не делают.

27.1.4Вопросы безопасности

Существует одно важное правило: если Вы запускаете внешнюю программу или считывает или записываете файл, убедитесь, чтобы в качестве параметров соответствующих функций (например, os.system(), os.popen*(), os.exec*(), os.spawn*(), open()) не использовались произвольные строки, полученные от клиента. Не следует доверять даже частям URL и именам полей, так как они могут поступить вовсе не из Вашей формы.

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

27.1.5Установка CGI-программы

Поместите Вашу программу в каталог, предназначенный для CGI-программ (обычно это ‘cgi-bin’). Убедитесь, что пользователь, от имени которого запущен HTTP-сервер, имеет доступ на чтение и выполнение программы. В операционных системах UNIX первая строка программы должна начинаться с ‘#!’, после чего должен следовать полный путь к интерпретатору, например:

#!/usr/local/bin/python

362

Глава 27. Поддержка протоколов Internet

Для систем, отличных от UNIX, потребуется дополнительная настройка HTTP-сервера для того, чтобы он “знал”, каким образом необходимо выполнять программы на языке Python.

Если Ваша программа должна читать или записывать файлы, убедитесь, что пользователь, от имени которого запущен HTTP-сервер, имеет соответствующий доступ к каталогам и файлам. Следует также помнить, что значения переменных окружения пользователя, от имени которого будет выполняться программа (в том числе переменных PATH и PYTHONPATH) могут отличаться от тех, которые имеете Вы сами.

Для того, чтобы импортировать модули из каталогов, которые не включены в пути поиска модулей по умолчанию, измените переменную sys.path перед тем, как импортировать другие модули. Например:

import sys

sys.path.insert(0, "/usr/home/joe/lib/python")

Следует помнить, что поиск производится в каталогах в том порядке, в котором они следуют в списке sys.path. Таким образом, в приведенном примере поиск будет производиться сначала в ‘/usr/home/joe/lib/python’, а затем в путях по умолчанию.

27.1.6Отладка

К сожалению, часто CGI-программа работает в командной строке и, при этом, ведет себя странно при запуске сервером. Существует как минимум одна причина, по которой Вам следует сначала попробовать запустить программу из командной строки: это позволит Вам исключить синтаксические ошибки.

Если Ваша программа не содержит синтаксических ошибок и все же не работает, попробуйте использовать этот модуль (файл ‘cgi.py’) в качестве CGI-программы, чтобы исключить распространенные ошибки, связанные с установкой программы и настройкой сервера. Например, если файл ‘cgi.py’ установлен в стандартном каталоге ‘cgi-bin’, Вы можете послать примерно следующий запрос из браузера:

http://hostname/cgi-bin/cgi.py?name=Joe&addr=At+Home

Если при этом Вы получаете ошибку 404 — сервер не может найти программу; вероятно, необходимо установить его в другой каталог. Если же Вы получаете другую ошибку (например, 500) — у Вас проблемы с установкой программы или настройкой сервера, которые необходимо устранить перед тем, как идти дальше. И, наконец, если Вы получили форматированный вывод переменных окружения и содержимого формы (в нашем примере это поле ‘addr’ со значением ‘At home’ и поле ‘name’ со значением ‘Joe’) — файл ‘cgi.py’ установлен правильно.

Следующим шагом вызовите функцию test() модуля cgi из Вашей программы, то есть замените его код следующими двумя инструкциями:

27.2. urllib — чтение произвольных ресурсов по URL

363

import cgi cgi.test()

Вы должны получить точно такой же результат, как и при обращении к ‘cgi.py’.

Когда обычная программа на языке Python генерирует исключение, которое не обрабатывается, интерпретатор выводит информацию об исключении и прерывает выполнение. Однако вывод информации об исключении производится на стандартный поток ошибок (sys.stderr), который перенаправляется в log-файл сервера или вовсе игнорируется. Чтобы этого не происходило, Вы можете поместить в начало программы инструкцию

import sys

sys.stderr = sys.stdout

или поместить основной текст программы в блок try ... except и самостоятельно выводить информацию об исключении, например:

import cgi

print ’Content-Type: text/html\n’

try:

# пУОПЧОПК ФЕЛУФ CGI-РТПЗТБННЩ

...

except: cgi.print_exception(limit=10)

27.2urllib — чтение произвольных ресурсов по URL

Этот модуль предоставляет средства высокого уровня для чтения сетевых ресурсов, используя различные протоколы. В частности функция urlopen() ведет себя аналогично встроенной функции open(), но воспринимает URL (Uniform Resource Locator, единообразный указатель ресурса) вместо имени файла. При этом, естественно, налагаются некоторые ограничения: Вы можете открыть ресурс только для чтения и полученный “файловый” объект не имеет метода seek().

Определенные в этом модуле средства позволяют обращаться к ресурсам через proxy-сервер, не требующий аутентификации. Если proxy-сервера не указаны явно, они определяются через переменные окружения, системный реестр (Windows) или Internet Config (Macintosh). В операционных системах UNIX для использования proxy необходимо перед запуском интерпретатора установить переменные окружения (регистр букв имен переменных может быть произвольным) http_proxy, ftp_proxy и gopher_proxy равными URL, указывающим на proxy-сервера для соответствующих протоколов.

364

Глава 27. Поддержка протоколов Internet

urlopen(url [, data])

Создает и возвращает объект, реализующий чтение ресурса url. Если URL не содержит идентификатора протокола (scheme identifier) или в качестве идентификатора используется ‘file’, открывается локальный файл. В остальных случаях открывается сетевое соединение. Если соединение не может быть установлено или сервер сообщает об ошибке, генерируется исключение IOError.

По умолчанию для протокола HTTP используется метод GET. Для того, чтобы использовался метод POST, необходимо указать аргумент data с данными в формате ‘application/x-www-form-urlencoded’ (см. описание функции urlencode() ниже).

urlretrieve(url [, filename [, reporthook [, data]]])

Копирует ресурс url в локальный файл. Если URL указывает на локальный файл или кэш уже содержит свежую копию ресурса, копирование не производится. Функция возвращает кортеж вида ‘(filename, headers)’, где filename — имя локального файла с копией ресурса и headers None, если url ссылается на локальный файл, иначе — объект, возвращаемый методом info() объекта, реализующего чтение ресурса.

Аргумент filename указывает имя локального файла, в который будет производиться копирование. По умолчанию имя файла генерируется с помощью функции tempfile.mktemp(). Задав аргумент reporthook Вы можете отслеживать процесс копирования. Функция (или другой объект, поддерживающий вызов) reporthook вызывается при установлении сетевого соединения и после загрузки каждого блока ресурса с тремя аргументами: число загруженных блоков, размер блока в байтах и размер файла (-1, если размер неизвестен). Аргумент data имеет такое же значение, как и для функции urlopen().

urlcleanup()

Очищает кэш, созданный предыдущими вызовами функции urlretrieve()2.

quote(string [, safe])

Заменяет специальные символы в строке string на последовательности вида ‘%xx’ и возвращает результат. Преобразованию никогда не подвергаются буквы, цифры и символы ‘_’, ‘,’, ‘.’ и ‘-’. Аргумент safe указывает дополнительные символы, которые должны быть оставлены без изменений; по умолчанию он равен

’/’.

quote_plus(string [, safe])

Работает аналогично функции quote(), но также заменят пробелы на ‘+’, как это необходимо для обработки значений полей форм. Если символ ‘+’ не содержится в строке safe, то он заменяется на ‘%2b’.

unquote(string)

Заменяет специальные последовательности вида ‘%xx’ на соответствующие символы и возвращает результат.

2В текущих реализациях модуля кэширование по умолчанию отключено, так как еще не реализован механизм проверки срока хранения копий ресурсов.

27.2. urllib — чтение произвольных ресурсов по URL

365

unquote_plus(string)

Работает аналогично функции unquote(), но также заменяет символы ‘+’ пробелами, как это необходимо для восстановления значений полей форм.

urlencode(dict)

Возвращает строку с данными dict (отображение строк-имен переменных к строкам-значениям) в формате ‘application/x-www-form-urlencoded’. Результат может быть использован в качестве аргумента data функций urlopen() и urlretrieve() и метода open() экземпляров URLopener и производных от него классов. Эта функция полезна для преобразования значений полей формы в строку запроса. Возвращаемая строка состоит из последовательности фрагментов вида ‘key=value’ для каждой записи в словаре, разделенных символом ‘&’, где key и value обрабатываются с помощью функции quote_plus().

Объекты, реализующие чтение ресурса, помимо read(), readline(), readlines(), fileno() и close(), характерных для файловых объектов (см. раздел 11.7), имеют следующие методы:

info()

Возвращает экземпляр класса mimetools.Message, содержащий метаинформацию о ресурсе. При использовании протокола HTTP этот объект содержит информацию обо всех заголовках. При использовании протокола FTP заголовок ‘Content-Length’ будет присутствовать, если сервер посылает информацию о длине файла. При обращении к локальному файлу возвращаемый этим методом объект будет содержать заголовок ‘Date’ с датой и временем последнего изменения, заголовок ‘Content-Length’ с размером файла и заголовок ‘Content-Type’ с предполагаемым типом файла.

geturl()

Возвращает истинный URL ресурса. В некоторых случаях HTTP-сервер перенаправляет клиента на другой URL. Такие перенаправления автоматически обрабатываются, и Вы получаете ресурс с новым URL, узнать который можно с помощью этого метода.

Функции urlopen() и urlretrieve() создают и используют экземпляр класса FancyURLopener. Созданный объект сохраняется для дальнейшего использования этими функциями. Если Вам необходим более тонкий контроль — используйте FancyURLopener, URLopener или производные от них классы.

URLopener([proxies [, **x509]])

Базовый класс, реализующий чтение ресурсов. Если Вам не нужна поддержка каких-либо дополнительных протоколов — используйте класс FancyURLopener. Если задан и не равен None аргумент proxies, он должен быть отображением идентификаторов протоколов (scheme identifier) к URL соответствующих proxyсерверов и будет использован для определения способа соединения. По умолчанию URL proxy-серверов определяются по схеме, описанной в начале раздела.

366

Глава 27. Поддержка протоколов Internet

Для аутентификации при использовании протокола HTTPS должны быть указаны именованные аргументы (x509) key_file и cert_file.

FancyURLopener([proxies [, **x509]])

Этот класс является производным от класса URLopener и предоставляет обработку HTTP-ответов с кодами 301, 302 и 401. При получении ответов с кодами 301 и 302 используется заголовок ‘Location’ для переадресации на другой URL. Для ответов с кодом 401 используется базовая аутентификация. Аргументы конструктора этого класса имеют такое же значение, как и для конструктора класса

URLopener.

Экземпляры классов URLopener и FancyURLopener имеют следующие методы и атрибуты данных:

open(url [, data])

Открывает ресурс url и возвращает объект, аналогичный файловому, реализующий чтение ресурса (см. выше). Этот метод проверяет кэш, обрабатывает информацию о proxy-сервере и вызывает один из методов open_scheme(), где scheme заменяется идентификатором протокола (в котором символы ‘-’ заменены на ‘_’), или метод open_unknown(), если используемый идентификатор протокола неизвестен. Аргумент data имеет такое же значение, как и для функции urlopen().

open_unknown(url [, data])

Этот метод может быть переопределен в производном классе для обработки URL с неизвестным идентификатором протокола. Исходная реализация генерирует исключение IOError.

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

Копирует ресурс url в локальный файл. Если URL указывает на локальный файл или кэш уже содержит свежую копию ресурса, копирование не производится. Метод возвращает кортеж вида ‘(filename, headers)’, где filename — имя локального файла с копией ресурса и headers None, если url ссылается на локальный файл, иначе — объект, возвращаемый методом info() объекта, реализующего чтение ресурса (см. выше).

Аргумент filename указывает имя локального файла, в который будет производиться копирование. По умолчанию имя файла генерируется с помощью функции tempfile.mktemp(). Задав аргумент reporthook Вы можете отслеживать процесс копирования. Функция (или другой объект, поддерживающий вызов) reporthook вызывается при установлении сетевого соединения и после загрузки каждого блока ресурса с тремя аргументами: число загруженных блоков, размер блока в байтах и размер файла (-1, если размер неизвестен). Аргумент data имеет такое же значение, как и для функции urlopen().

version

Этот атрибут класса является строкой с именем программы клиента, которое будет использовано при конструировании HTTP-запросов. По умолчанию используется строка ’Python-urllib/urllib_ver’, где urllib_ver — версия модуля

27.3. urlparse — операции над URL

367

urllib. Вы можете переопределить атрибут version в определении производного класса, чтобы изменить имя программы, посылаемое серверу.

Для совместимости с предыдущими версиями, если URL без идентификатора протокола (scheme identifier) не соответствует существующему локальному файлу, производится попытка использовать его для FTP протокола. Это может привести к сбивающим с толку сообщениям об ошибках.

При установлении сетевого соединения может произойти задержка на произвольное время. Таким образом, использование средств модуля urllib в однопоточных программах сильно затруднено.

Следующий пример использует метод GET для загрузки ресурса по протоколу HTTP:

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

Итот же самый ресурс, используя метод POST:

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

27.3 urlparse — операции над URL

Этот модуль определяет средства для разбиения URL (Uniform Resource Locator, единообразный указатель ресурса, RFC 1738) на компоненты, конструирования URL из компонент и преобразования относительных URL в абсолютные (RFC 1808).

urlparse(urlstring [, default_scheme [, allow_fragments]])

Разбивает URL на компоненты и возвращает кортеж из шести строк: идентификатор протокола (scheme identifier), положение в сети, путь, параметры, строка

368

Глава 27. Поддержка протоколов Internet

запроса и идентификатор фрагмента. То есть применение функции к строке общего вида

’scheme://netloc/path;parameters?query#fragment’

дает ‘(scheme, netloc, path, parameters, query, fragment)’. Если URL не содержит какого-либо компонента, соответствующий элемент возвращаемого кортежа будет равен пустой строке. Разделители компонент не включаются

врезультат, за исключением косой черты в начале пути:

>>>import urlparse

>>>urlparse.urlparse(

... ’http://www.cwi.nl:80/%7Eguido/Python.html’) (’http’, ’www.cwi.nl:80’, ’/%7Eguido/Python.html’, ’’, ’’, ’’)

Если задан аргумент default_scheme, он будет использован в качестве идентификатора протокола (scheme identifier) по умолчанию — в том случае, если указанный URL не содержит идентификатора протокола.

Если задан и равен нулю аргумент allow_fragments, использование идентификатора фрагмента в URL (последний компонент) считается недопустимым.

urlunparse(tuple)

Восстанавливает и возвращает URL из компонент, переданных в кортеже tuple. При последовательном применении функций urlparse() и urlunparse() Вы можете получить другой (например, если исходный URL содержит излишние разделители), но эквивалентный URL.

urljoin(base, rel_url [, allow_fragments])

Конструирует и возвращает полный URL, комбинируя базовый URL base и относительный URL rel_url. Например:

>>> urljoin(

... ’http://www.cwi.nl/%7Eguido/Python.html’,

... ’FAQ.html’) ’http://www.cwi.nl/%7Eguido/FAQ.html’

Если задан и равен нулю аргумент allow_fragments, использование идентификатора фрагмента в URL (последний компонент) считается недопустимым.

369

Глава 28

Поддержка форматов, используемых в Internet

В этой главе описаны модули, обеспечивающих поддержку форматов, обычно используемых для передачи данных через Internet. Модули, предназначенные для обработки структурной разметки, описаны отдельно — в главе 29.

rfc822 Обработка заголовков электронных писем (в стиле RFC 822). mimetools Обработка сообщений в формате MIME.

MimeWriter Средства для записи в формате MIME.

multifile Чтение сообщений, состоящих из нескольких частей (например, в формате MIME).

xdrlib Преобразование данных в формат XDR и обратно.

28.1rfc822 — обработка заголовков электронных писем

Модуль rfc822 определяет класс Message, представляющий набор заголовков электронного письма (см. описание стандарта RFC 822). Он может быть использован в различных ситуациях, обычно для чтения таких заголовков из файла. Этот модуль также определяет класс AddressList, предназначенный для обработки адресов в соответствии с RFC 822, и несколько вспомогательных функций.

Message(file [, seekable])

При создании экземпляров класса Message в качестве аргумента file должен быть указан файловый или подобный объект (достаточно, чтобы этот объект имел метод readline()). При инициализации считываются и сохраняются заголовки из file вплоть до разделительной пустой строки.

Наличие методов seek() и tell() у объекта file позволяет использовать метод rewindbody() экземпляров класса Message. Кроме того, при наличии этих методов или метода unread() некорректные строки будут возвращены в поток. Таким образом, этот класс может быть использован для чтения буферизованных потоков.

370

Глава 28. Поддержка форматов, используемых в Internet

Если аргумент seekable опущен или равен 1, наличие методов seek() и tell() определяется путем вызова tell(). Однако такой механизм не всегда хорошо работает. Поэтому, для обеспечения максимальной переносимости следует установить seekable равным нулю, если объект file не поддерживает установку указателя (например, если он представляет сетевое соединение).

Строки, считываемые из файла, могут заканчиваться комбинацией CR-LF или одним символом LF; перед сохранением комбинация CR-LF заменяется на LF.

AddressList(field)

При инициализации экземпляров этого класса используется единственный аргумент — строка, в которой, в соответствии с RFC 822, через запятую перечислены адреса. При использовании в качестве аргумента field значения None, созданный экземпляр будет представлять пустой список.

parsedate(date)

Пытается проанализировать строку с датой в соответствии с правилами, приведенными в RFC 822 (например, ’Mon, 20 Nov 1995 19:12:08 -0500’). В некоторых случаях эта функция срабатывает и для строк, в которых дата записана не в соответствии со стандартом. В случае удачного анализа возвращает кортеж из девяти элементов, пригодный для использования в качестве аргумента функции time.mktime() (назначение элементов кортежа смотрите в описании модуля time), иначе возвращает None. Заметим, что 6, 7 и 8 элементы возвращаемого кортежа не имеют полезных значений.

parsedate_tz(date)

Работает аналогично функции parsedate(), но возвращает либо None, либо кортеж из десяти элементов. Первые девять элементов такие же, десятый — сдвиг часового пояса в секундах относительно универсального времени. Заметим, что знак этого сдвига противоположен знаку time.timezone для того же часового пояса (time.timezone следует стандарту POSIX, в то время как данная функция — RFC 822). Если строка date не содержит информации о часовом поясе, последний элемент кортежа будет равен None. Заметим, что 6, 7 и 8 элементы возвращаемого кортежа не имеют полезных значений.

mktime_tz(tuple)

Преобразует кортеж из десяти элементов (например, возвращаемый функцией parsedate_tz()) в число секунд, пройденных с начала эпохи (UTC timestamp). Если последний элемент кортежа tuple равен None, считается, что время в tuple представлено для локального часового пояса. Эта функция может давать небольшую ошибку в точках перехода на летнее и зимнее время.

formatdate([tuple])

Возвращает строку с временем tuple (кортеж из девяти элементов — значение элементов смотри в описании модуля time), представленным в соответствии с RFC 822 и RFC 1123.

Экземпляры класса Message являются отображениями имен заголовков к их значениям (с доступом только на чтение) и поддерживают большинство характерных для