На некоторых серверах функция print может буферизовать вывод. Если ваш сценарий CGI выполняется продолжительное время, чтобы не заставлять пользователя ждать начала появления результатов, можно вручную выталкивать буферы (вызывая метод sys.stdout. flush()) или запустить сценарии Python в небуферизованном режиме. Напомню, что в главе 5 рассказывалось о возможности перевода потока вывода в небуферизованный режим за счет использования флага -u командной строки интерпретатора или установки переменной окружения PYTHONUNBUFFERED в любое непустое значение.
Чтобы передать интерпретатору флаг -u в мире CGI, попробуйте указать его в первой строке сценария на Unix-подобных платформах, например: #!/usr/bin/python -u. Однако обычно буферизация не оказывает существенного влияния. Тем не менее, для некоторых серверов и клиентов отключение ее может помочь решить проблему получения пустой страницы ответа или преждевременной отправки заголовка ошибки завершения сценария — на стороне клиента может истечь предельное время ожидания до того, как сервер отправит буферизованный поток вывода (хотя обычно подобные проблемы являются отражением действительных программных ошибок в сценариях).
На первый взгляд, этот процесс установки может показаться несколько сложным, но во многом он зависит от особенностей сервера, и когда вы разберетесь с ним самостоятельно, все окажется не так страшно. Установка занимает некоторое время и обычно до некоторой степени может быть автоматизирована с помощью сценариев Python, выполняемых на сервере. Подведем итоги. Большинство сценариев CGI на языке Python являются текстовыми файлами, содержащими программный код Python, которые:
• Именуются согласно соглашениям веб-сервера (например, file.cgi).
• Хранятся в каталоге, распознаваемом веб-сервером (например, cgi- bin/).
• Имеют права доступа исполняемых файлов, если это необходимо (например, chmod 755 file.py).
• На некоторых серверах могут потребовать добавить в начало особую строку #!pythonpath.
• Настраивают sys.path, только если это необходимо, чтобы увидеть модули в других каталогах.
• Используют соглашения Unix по концу строки, только если сервер не принимает формат DOS.
• При необходимости выталкивают выходные буферы или отправляют ответ порциями.
Поиск Python на удаленном сервере
Последняя подсказка по установке: в контексте веб-приложения на стороне сервера не требуется установка Python у клиентов, но он должен присутствовать на компьютере сервера, где должны выполняться сценарии CGI. Если вы пользуетесь своим собственным веб-сервером — сценарием webserver.py, представленным выше, или другим свободно распространяемым сервером, таким как Apache, то это не представляет проблемы.
Но если вы пользуетесь сервером, который настраивали не вы сами, необходимо убедиться в наличии интерпретатора Python на этом компьютере. Более того, необходимо узнать каталог его установки, чтобы указать путь к нему в строке #! в начале своего сценария. Если вы не уверены, установлен ли интерпретатор Python на сервере и где он находится, вам помогут несколько советов:
• Особенно в системах Unix следует сначала предположить, что Python находится в стандартном месте (например, /usr/local/bin/py thon): введите команду python (или which python) в окне командной оболочки и проверьте его работоспособность. Весьма вероятно, что Python уже установлен в системе. Если у вас есть доступ к серверу посредством Telnet или SSH, можно воспользоваться командой Unix find, выполнив с ее помощью поиск, начиная с каталога /usr.
• Если ваш сервер работает под управлением Linux, то, вероятно, все готово к работе. В настоящее время интерпретатор Python является стандартной частью дистрибутивов Linux, а под управлением операционной системы Linux работают многие веб-сайты и серверы провайдеров услуг Интернета. На таких сайтах Python обычно устанавливается в каталог /usr/bin/python.
• В других средах, где нет возможности самостоятельно контролировать компьютер сервера, получить доступ к уже установленному интерпретатору Python может оказаться труднее. В этих случаях можно переместить свой сайт на сервер, где Python точно установлен, или убедить провайдера установить Python на сервере, который вы хотите использовать, или установить Python на сервере самому.
Если ваш провайдер без понимания относится к вашей потребности в Python и вы хотите перенести свой сайт на сервер провайдера, который предоставляет возможность его использования, поищите в Интернете списки провайдеров, дружественно относящихся к Python. А если вы предпочтете установить Python на сервере самостоятельно, обязательно рассмотрите возможность применения инструментов создания ском пи- лиро ван ных файлов программ на языке Python — с их помощью можно создать единственный файл выполняемой программы, который целиком содержит интерпретатор Python вместе со всеми стандартными библиотечными модулями. Такой скомпилированный интерпретатор можно по FTP за один шаг выгрузить в каталог вашей учетной записи на сервере, при этом не потребуется полной инсталляции Python на сервере. Создать двоичный скомпилированный файл с программой на языке можно с помощью свободно распространяемых программ PyInstaller и Py2Exe.
Наконец, обратите внимание, что для опробования примеров из этой книги необходима версия Python 3.X, а не Python 2.X. Как уже упоминалось выше, на момент, когда я работал над четвертым изданием, многие коммерческие провайдеры Интернета поддерживали версию 2.X, а не 3.X, но такое положение вещей, как ожидается, должно измениться с течением времени. Если вам удалось найти провайдера, обеспечивающего поддержку Python 3.X, выгрузите свои файлы по FTP и используйте для работы SSH или Telnet. Вы можете также запустить на удаленном сервере сценарий webserver.py из этой главы, хотя при этом вам, возможно, придется отказаться от идеи использовать стандартный порт 80 — все зависит от того, какой уровень управления будет предоставлен вашей учетной записи.
Добавление картинок и создание таблиц
Вернемся к написанию серверных сценариев. Каждому, когда-либо бродившему по Сети, известно, что веб-страницы обычно содержат не только обычный текст. В примере 15.4 представлен CGI-сценарий на языке Python, который выводит разметку HTML, содержащую тег <IMG> для включения графического изображения в страницу, отображаемую броузером клиента. Чего-либо особенно характерного для Python в этом примере нет, но обратите внимание, что как и простые файлы HTML, графический файл (ppsmall.gif) также располагается на сервере и загружается с него в процессе интерпретации броузером вывода этого сценария.
Пример 15.4. PP4E\Internet\Web\cgi-bin\tutor1.py
#!/usr/bin/python
text = """Content-type: text/html
<TITLE>CGI 101</TITLE>
<H1>A Second CGI Script</H1>
<HR>
<P>Hello, CGI World!</P>
<IMG src="../ppsmall.gif" BORDER=1 ALT=[image]>
<HR>
print(text)
Обратите внимание на использование блока строк в тройных кавычках — вся строка с разметкой HTML посылается броузеру в один прием с помощью находящегося в конце вызова функции print. Обязательно убедитесь в том, что пустая строка между заголовком «Content-type» и первой строкой разметки HTML действительно является пустой (некоторые броузеры могут допускать ошибки при интерпретации, если в этой строке будут присутствовать пробелы или символы табуляции). Если и клиент, и сервер функционируют нормально, при обращении к этому сценарию будет сгенерирована страница, изображенная на рис. 15.4.
Рис. 15.4. Страница с изображением, созданная сценарием tutor1.py
До сих пор наши сценарии CGI выводили готовую разметку HTML, которую с таким же успехом можно было бы хранить в файле HTML. Но поскольку CGI-сценарии являются выполняемыми программами, они также способны воспроизводить разметку HTML динамически — даже, например, в ответ на определенный набор данных, введенных пользователем и переданных сценарию. В конце концов, в этом и состоит назначение сценариев CGI. Давайте начнем использовать это качество в своих целях и напишем сценарий Python, который программно конструирует разметку HTML, как показано в примере 15.5.
Пример 15.5. PP4E\Internet\Web\cgi-bin\tutor2.py
#!/usr/bin/python
print("""Content-type: text/html
<TITLE>CGI 101</TITLE>
<H1>A Third CGI Script</H1>
<HR>
<P>Hello, CGI World!</P>
<table border=1>
""")
for i in range(5):
print(‘<tr>’)
for j in range(4):
print(‘<td>%d.%d</td>’ % (i, j)) print(‘</tr>’)
print("""
</table>
<HR>
""")
Несмотря на все теги, это действительно программный код на языке Python — сценарий tutor2.py также встраивает блоки HTML с помощью строк в тройных кавычках. Но на этот раз вложенные циклы for динамически генерируют часть разметки HTML, посылаемой броузеру. В частности, сценарий создает разметку HTML двумерной таблицы, размещающейся в середине страницы, как показано на рис. 15.5.
Рис. 15.5. Страница с таблицей, генерируемая tutor2.py
В каждой строке таблицы выводятся пары чисел «номер_строки.но- мер_колонки», полученные в процессе выполнения сценария Python. Если вам интересно узнать, как выглядит сгенерированная разметка HTML, откройте страницу в броузере и выберите пункт меню View Source (Исходный код страницы или Просмотр HTML-кода). Это единая страница HTML, сгенерированная первым вызовом функции print сценария, последующими циклами for и, наконец, последним вызовом print. Иными словами, объединение вывода этого сценария представляет собой HTML-документ с заголовками.
Теги таблиц
Сценарий в примере 15.5 генерирует теги таблиц HTML. Опять-таки, мы не собираемся здесь изучать язык HTML, но представим его в объеме, достаточном для понимания примеров, приводимых в этой книге. Таблицы HTML объявляются как текст между тегами <table> и </table>. Текст таблицы, в свою очередь, обычно состоит из строк, объявляемых с помощью тегов <tr> и </tr>, и колонок в каждой из строк, заключенных в теги <td> и </td>. Циклы в нашем сценарии конструируют разметку HTML, объявляющую пять строк по четыре колонки в каждой, путем вывода соответствующих тегов, при этом значениями ячеек являются номера текущих строки и колонки.
Например, ниже приводится часть вывода сценария, определяющая первые две строки (чтобы увидеть полный вывод, запустите этот сценарий как обычную программу из командной строки или воспользуйтесь пунктом меню View Source (Исходный код страницы или Просмотр HTML-кода) в вашем броузере):
<table border=1>
<tr>
<td>0.0</td>
<td>0.1</td>
<td>0.2</td>
<td>0.3</td>
</tr>
<tr>
<td>1.0</td>
<td>1.1</td>
<td>1.2</td>
<td>1.3</td>
</tr>
</table>
Другие теги и параметры таблиц позволяют определять заголовки строк (<th>), тип границ и так далее. В одном из следующих разделов мы приведем расширенный синтаксис таблиц для придания организованной структуры формам.
Добавление взаимодействия с пользователем
Сценарии CGI прекрасно умеют генерировать разметку HTML на лету, как было показано выше, но их также часто используют для реализации взаимодействий с пользователями, вводящими данные в веб-броузере. Как отмечалось ранее в этой главе, веб-взаимодействия обычно представляют собой двухэтапный процесс и реализуются с использованием двух разных веб-страниц: вы заполняете форму ввода на странице и нажимаете кнопку Submit Query (Отправить запрос), а в ответ возвращается новая страница. В промежутке данные формы обрабатывает сценарий CGI.
Использованная литература:
Марк Лутц — Программирование на Python, 4-е издание, II том, 2011