Чтобы покопаться в реализации серверных классов нашего веб-сервера, обращайтесь к файлам с исходными текстами в стандартной библиотеке Python (C:\Python31\Lib для версии Python 3.1). Одно из основных преимуществ открытых систем, таких как Python, состоит в том, что мы всегда можем заглянуть «под капот». В главе 15 мы расширим пример 1.32 возможностью указывать имя каталога и номер порта из командной строки.
Использование строки запроса и модуля urllib
В простом CGI-сценарии, представленном выше, мы запускали сценарий на языке Python, заполняя и отправляя форму, содержащую имя сценария. На практике серверные CGI-сценарии могут вызываться разными способами - либо за счет отправки формы, как было показано выше, либо за счет отправки серверу строки URL (интернет-адреса), содержащей входные данные в конце. Такую строку URL можно отправить не только с помощью броузера, то есть минуя традиционный путь, лежащий через форму ввода.
Например, на рис. 1.12 изображена страница, сгенерированная в ответ на ввод адреса URL в адресной строке броузера (символ + здесь означает пробел):
http://localhost/cgi-bin/cgi101.py?user=Sue+Smith
Рис. 1.12. Ответ сценария cgi101.py на запрос GET с параметрами
Входные данные здесь, известные как параметры, запроса, находятся в конце строки URL, после символа ?. Они не были введены в поля формы. Строку URL с дополнительными входными данными иногда называют GET-запросом. Наша оригинальная форма отправляет запрос методом POST, в котором входные данные отправляются отдельно. К счастью, в CGI-сценариях на языке Python не требуется различать эти два вида запросов - парсер входных данных в модуле cgi автоматически обрабатывает все различия между методами отправки данных.
Вполне возможно и часто даже полезно иметь возможность отправлять входные данные в строке URL в виде параметров запроса вообще без помощи веб-броузера. Пакет urllib из стандартной библиотеки Python, например, позволяет читать ответ, сгенерированный сервером для любого допустимого адреса URL. Фактически он позволяет посещать вебстраницы или вызывать CGI-сценарии из другого сценария - ваш программный код на языке Python будет играть роль веб-клиента. Ниже демонстрируется пример использования пакета в интерактивной оболочке:
>>> from urllib.request import urlopen
>>> conn = urlopen('http://localhost/cgi-bin/cgi101.py?user=Sue+Smith')
>>> reply = conn.read()
>>> reply
b’<title>Reply Page</title>\n<h1>Hello <i>Sue Smith</i>!</h1>\n'
>>> urlopen('http://localhost/cgi-bin/cgi101.py').read()
b’<title>Reply Page</title>\n<h1>Who are you?</h1>\n’
>>> urlopen('http://localhost/cgi-bin/cgi101.py?user=Bob').read()
b’<title>Reply Page</title>\n<h1>Hello <i>Bob</i>!</h1>\n’
Пакет urllib реализует интерфейс получения ответов от сервера для заданной строки URL, напоминающий интерфейс файлов. Обратите внимание, что ответ, который мы получаем от сервера, представляет собой простую разметку HTML (обычно отображается броузером). Мы можем обрабатывать этот текст с помощью любых инструментов обработки текста, входящих в состав Python, включая:
• Строковые методы поиска и разбиения
• Модуль re, позволяющий выполнять сопоставление с регулярными выражениями
• Развитую поддержку парсинга разметки HTML и XML в стандартной библиотеке, включая модуль html.parser, а также SAX-, DOM-и ElementTree-подобные инструменты парсинга разметки XML.
В сочетании с такими инструментами пакет urllib естественным образом подходит для применения в интерактивном тестировании вебсайтов, в собственных клиентских графических интерфейсах, в программах, извлекающих содержимое веб-страниц, и в автоматизированных регрессионных тестах для тестирования удаленных CGI-сценариев.
Форматирование текста ответа
Еще одно, последнее примечание: так как для взаимодействия с клиентами CGI-сценарии используют текст, они должны форматировать его, следуя определенному набору правил. Например, обратите внимание, что в примере 1.31 между заголовком ответа и разметкой HTML присутствует пустая строка в виде явного символа перевода строки (\n), в дополнение к символу перевода строки, который автоматически выводится функцией print, - это обязательный разделитель.
Кроме того, обратите внимание, что текст, добавляемый в разметку HTML ответа, передается через вызов функции cgi.escape (она же html. escape в Python 3.2 - смотрите примечание в разделе «Инструменты экранирования HTML и URL в языке Python», в главе 15), на тот случай, если он содержит символы, имеющие специальное значение в HTML. Например, на рис. 1.13 изображена страница ответа, полученная в результате ввода имени пользователя Bob </i> Smith, - последовательность символов </i> в середине преобразуется этой функцией в последовательность </i>, благодаря чему исключается влияние этой последовательности на фактическую разметку HTML (воспользуйтесь возможностью просмотра исходного кода страницы, имеющейся в броузерах, чтобы убедиться в этом). Без вызова этой функции остаток имени был бы выведен обычным, некурсивным шрифтом.