Web Progr Python
Web Progr Python
ORG -
В. В. ЯНЦЕВ
WEBПРОГРАММИРОВАНИЕ
НА PYTHON
Учебное пособие
•САНКТПЕТЕРБУРГ•МОСКВА•КРАСНОДАР•
2022
ISBN 9785811494606
УДК 004
ББК 32.973.4я723
Обложка
П. И. ПОЛЯКОВА
def opfi(adr):
fo = open(adr, encoding='utf-8')
ti = fo.read()
fo.close()
return ti
1.4. Браузеры
1.5. Zip-архив
10
Включите компьютер, дождитесь полной загрузки операционной системы.
Щелкните на кнопке «Пуск», а затем на кнопке «Параметры» (рис. 2.1.1). В от-
крывшемся окне выберите пункт меню «Система». Откроется следующая
вкладка, в которой необходимо кликнуть на строке «О системе» (или «О про-
грамме»). После этого на вкладке «Характеристики устройства» посмотрите
строку «Тип системы» (рис. 2.1.2).
12
Рис. 2.2.2. Начало установки пакета
13
2.3. Установка сервера Apache 2.4
14
Рис. 2.3.3. Запуск командной строки
Теперь надо инсталлировать, а затем запустить сервер. Для этого в окне ко-
мандной строки сразу после
C:\WINDOWS\System32>
наберите
C:\Apache24\bin\httpd.exe -k install
Должно получиться
C:\WINDOWS\System32>C:\Apache24\bin\httpd.exe -k install
C:\WINDOWS\System32>
15
ВНИМАНИЕ! Может открыться окно брандмауэра с запросом на раз-
решение работы Apache. Разрешите доступ во всех сетях.
Нам надо убедиться, что сервер заработал. Для этого откройте ваш браузер
и введите в строке адреса http://localhost/. Если появилось сообщение «It
works!», значит все в порядке — сервер функционирует как положено
(рис. 2.3.5).
16
Рис. 2.3.6. Находим приложение «Службы»
18
Рис. 2.3.10. Идет процесс остановки Apache
19
Рис. 2.3.12. Идет процесс запуска сервера
20
Дождитесь окончания процесса (рис. 2.4.5). Нажмите кнопку «Close»
(рис. 2.4.6).
21
Рис. 2.4.3. Здесь просто жмем «Next»
Рис. 2.4.4. Ставим «галочку» напротив пункта «Install for all users», меняем имя
папки, в которую будет установлен интерпретатор, и начинаем инсталляцию
22
Рис. 2.4.5. Процесс установки файлов интерпретатора Python
DirectoryIndex index.html
23
и добавьте к ней
index.py
Должно получиться
ExecCGI
Должно получиться
.py
24
Должно получиться
#! C:/Python/python
print('Content-type: text/html\n\n')
print('PYTHON !')
Сохраните этот файл под именем test.py. Откройте ваш браузер и введите в
строке адреса http://localhost/test.py. Если появилось сообщение «PYTHON !»,
значит, все в порядке (рис. 2.4.8).
Вы также можете упростить себе задачу, использовав готовый файл test.py
из папки «Глава 2» zip-архива. Для этого файл необходимо скопировать и пере-
нести в папку C:\Apache24\htdocs.
Осталось добавить, что файлы ваших проектов необходимо помещать в
папку htdocs по адресу C:\Apache24\htdocs, а просматривать готовые страницы
сайтов в браузере по адресу http://localhost/ (для файла index.py) или
http://localhost/имя_страницы.py, например http://localhost/primer.py или
http://localhost/test/primer.py.
25
Рис. 2.5.1. Сайт с файлами редактора Notepad++
26
Рис. 2.5.4. Соглашаемся с условиями лицензии
28
Notepad++ позволяет:
– выполнять поиск по файлу в разных направлениях;
– производить замену по шаблону;
– устанавливать кодировки, в том числе необходимую для нашего проекта
UTF-8;
– менять страницы, форматируя их по стандартам разных операционных си-
стем — Windows, Unix или macOS;
– подсвечивать код, выделяя разные по назначению фрагменты, операторы,
функции, переменные, комментарии и т. д.;
– выбирать синтаксис документа (благодаря чему меняются варианты под-
светки кода, например Python, HTML, CSS или JavaScript);
– сохранять файлы с разным расширением;
– менять стили оформления окна программы — вариантов достаточно,
найдется любой по желанию;
– выполнять еще многие и многие операции.
29
Рис. 2.5.8. Ждем окончания процесса
30
Рис. 2.5.10. Редактор Notepad++ с открытым в нем файлом Python
31
Рис. 2.6.1. Редактор IDLE с открытым в нем файлом Python
32
Рис. 2.7.1. Валидатор кода Python
33
3. Теория
В этой главе будет много примеров кода. Напомню, что все они собраны в
папке «Глава 3» zip-архива. Чтобы запускать эти примеры в браузере, выполни-
те следующие действия:
– удалите из папки C:\Apache24\htdocs тестовый файл test.py;
– скопируйте все содержимое папки «Глава 3» zip-архива;
– поместите скопированные папки и файлы в папку C:\Apache24\htdocs;
– чтобы запустить файл в браузере, в строке адреса введите
http://localhost/file_name.py, где file_name.py — имя файла.
Python обладает большими функциональными возможностями. В этой главе
мы рассмотрим далеко не все из них, а только те, что соответствуют двум ос-
новным требованиям.
1. Материал должен быть простым и легким в восприятии. Автор не ставил
своей целью рассказать обо всех синтаксических особенностях этого языка. Ес-
ли вы хотите узнать о Python больше, прочтите какую-нибудь более объемную
и обстоятельную книгу.
2. Материал должен иметь первостепенную важность именно для web-
программирования на Python. При этом уже в который раз констатируем, что
все примеры кода (за одним исключением), иллюстрирующие наши рассужде-
ния, мы будем тестировать в браузере. Писать в оболочке Python и запускать
файлы из командной строки нам не придется.
#! C:/Python/python
print('Content-type: text/html\n\n')
print('PYTHON !')
#! C:/Python/python
34
Любой файл Python будет у нас всегда начинаться с этой строки. Подчеркну
важность данного факта: инструкция с указанием пути к интерпретатору долж-
на быть первой, какова бы ни была ваша программа!
Специальные символы #! указывают серверу, что данная строка содержит
путь к исполняемому файлу.
Многие программисты утверждают, что первую строку с указанием пути
к интерпретатору необходимо писать без пробела. На самом деле, это не бо-
лее чем дань традиции. И на локальном хостинге, и на реальном (там путь к
интерпретатору будет выглядеть по-другому) наличие или отсутствие про-
бела не играет никакой роли. Даже валидаторы кода Python не видят в про-
беле никакого нарушения стандартов. Вы можете писать так, как вам боль-
ше нравится:
#! C:/Python/python
или
#!C:/Python/python
print('Content-type: text/html\n\n')
print('PYTHON !')
#! C:/Python/python
print('Content-type: text/html\n\n')
print('Изучаем язык программирования Python !')
35
Рис. 3.1.1. Запускаем в браузере русскоязычный файл
#! C:/Python/python
print('Content-type: text/html; charset=utf-8\n\n')
print('Изучаем язык программирования Python !')
#! C:/Python/python
36
print('Content-type: text/html; charset=utf-8\n\n')
'Python'
True, False
None
[0, 1, 2, 3]
(0, 1, 2, 3)
{0, 1, 2, 3}
range(1, 5)
function — функции:
def a(): 1 + 1
module — модули:
import cgi
38
input. В этом случае Python ожидает от нас ввода данных и не закрывает окно,
позволяя нам увидеть результаты работы программы. Естественно, что на са-
мом деле ничего больше вводить не надо, а просто изучите полученные резуль-
таты. Разобрать их очень просто: сначала идут данные, а строкой ниже — ука-
зание их типа. Пустая строка — и новые данные.
print("'Python'")
print(type('Python'))
print("")
print("5")
print(type(5))
print("")
print("5.5")
print(type(5.5))
print("")
print("True")
print(type(True))
print("")
print("[0, 1, 2, 3]")
print(type([0, 1, 2, 3]))
print("")
39
print("(0, 1, 2, 3)")
print(type((0, 1, 2, 3)))
print("")
print("{0, 1, 2, 3}")
print(type({0, 1, 2, 3}))
print("")
print("range(1, 5)")
print(type(range(1, 5)))
print("")
import cgi
print("import cgi")
print(type(cgi))
input()
Нужно также отметить, что данные в Python делятся еще на две группы:
– последовательности — к ним относятся строки, списки, кортежи и диа-
пазоны;
– отображения — к ним относятся словари.
3.3. Переменные
False
None
True
__peg_parser__
and
as
assert
async
await
40
break
class
continue
def
del
elif
else
except
finally
for
from
global
if
import
in
is
lambda
nonlocal
not
or
pass
raise
return
try
while
with
yield
a
adr
t2
n3b
varName
d_var
x = 5
y = 5.5
z = 'Python'
41
или
x, y, z = 1, 2, 3
#! C:/Python/python
print(a)
42
имена глобальной и локальной переменных совпадают, то функция оперирует
локальной переменной, не изменяя значения глобальной. И снова автор совету-
ет присваивать всем переменным уникальные имена, чтобы не запутаться в них.
Важное место в работе с переменными занимает изменение типа данных.
Для этого существуют несколько функций. Мы упомянем пять из них.
a = 1
int — преобразует объект в целое число. Здесь можно привести обратный при-
мер:
a = '1'
print(1 + a)
Ошибку вызовет тот факт, что в выражении одно слагаемое — число, а вто-
рое — строка. Необходимо привести строку '1' к числовому значению:
print(1 + int(a))
float(1)
даст результат
1.0
list('Python')
43
['P', 'y', 't', 'h', 'o', 'n']
bool(0)
bool('')
bool(1)
bool('Python')
3.4. Кавычки
44
Мы с вами в этой книге будем придерживаться следующего правила: двой-
ные кавычки — для HTML-разметки, одинарные — для ограничения строки в
коде Python.
3.5. Комментарии
# Это комментарий
Например:
'''Это пояснения
к программе.
Они состоят
из нескольких строк'''
Например:
def isImageType(t):
'''
Проверяем, является ли объект изображением.
Параметр t - проверяемый объект
Возвращает True, если объект является изображением
'''
return hasattr(t, 'im')
45
1. Не загромождайте код комментариями к тем частям, назначение которых
понятно без лишних слов. Пример:
46
# Вводим переменные:
rs = 1 # для сохранения результатов
i = 0 # счетчик
while i < sum - 1: # Запускаем цикл
3.6. Операторы
47
Продолжение табл. 3.6.2
Оператор Действие Пример Примечание
in Проверка на 'Стр' in 'Строка' True, в случае вхождения
вхождение элемента в последователь-
ность
not in Проверка на 'Стр' not in True, если элемент отсут-
невхождение 'Строка' ствует в последовательно-
сти
48
Продолжение табл. 3.6.4
Оператор Сравнение Пример
is Проверяет, содержат ли две переменные x is y
ссылки на один и тот же объект
is not Проверяет, содержат ли две переменные x is not y
ссылки на разные объекты
3.7. Числа
round(3.5)
Результат:
abs — возвращает абсолютное значение числа (иначе говоря, если число с от-
рицательным знаком, то вернется с положительным).
abs(-5)
pow(5, 3)
125
max(0, 1, 2, 3)
min(0, 1, 2, 3)
49
sum — возвращает сумму значений элементов последовательности.
sum([0, 1, 2, 3])
(3.5).is_integer()
False
math.pi
3.141592653589793
math.e
2.718281828459045
math.sqrt(49)
7.0
math.floor(5.9)
math.factorial(7)
50
5040
random.random()
0.45109179654967557
random.uniform(2, 7)
3.942466835198392
random.randint(2, 7)
6
random.choice[1, 2, 3, 4, 5, 6, 7]
gr = [1, 2, 3, 4, 5, 6, 7]
random.shuffle(gr)
print(gr)
[1, 4, 6, 2, 3, 7, 5]
random.sample([1, 2, 3, 4, 5, 6, 7], 3)
[3, 6, 7]
3.8. Строки
s = 'Текст'
len(s)
Результат:
\n — перевод строки;
\' — апостроф;
\\ — обратный слеш.
Иногда надо вывести текст строго в том виде, как он написан (программи-
сты часто называют такую строку «сырой»). В Python для подобных случаев
предусмотрен модификатор r. Зачем он нужен? Допустим, вы хотите показать
на странице фрагмент какого-то кода, в котором есть спецсимвол \n. Если не
поставить перед строкой с таким символом модификатор, то браузер посчитает,
что это команда на перевод строки, и символ не напечатает. Если поставить мо-
дификатор перед строкой, то символ \n будет отображен на странице. Запустите
программу 3_8_1.py:
#! C:/Python/python
print('Content-type: text/html; charset=utf-8\n\n')
print('1 \n 2')
print('<br><br>')
print(r'1\n2')
52
Рис. 3.8.1. Вывод обработанной и «сырой» строки
s = 'Текст'
s[3]
Результат:
s = 'Текст'
s[-3]
где start_index — индекс начала среза, end_index — индекс конца среза (в ре-
зультат не входит), step — шаг, с которым получают номер следующего индек-
са. Если значение шага не указано, то по умолчанию оно равно 1. Если не ука-
зан индекс начала, то его значение будет 0, если не указан индекс конца, то срез
будет выполнен до конца строки. Если вообще не указать никакие параметры,
то вернется строка в исходном виде (что вряд ли имеет какое-то практическое
значение).
Срез хорошо иллюстрирует следующая программа (файл 3_8_2.py):
#! C:/Python/python
53
s = 'Текст строка'
print(s[2 : 8 : 2])
print('<br><br>')
print(s[2 : 8])
print('<br><br>')
print(s[:])
s = 'Текст'
s.strip('т')
Результат:
Текс
Как видите, метод чувствителен к регистру символов. Так же, как и три следу-
ющих:
s = 'Текст'
s.lstrip('Т')
Текст
54
rstrip — удаляет указанные символы или пробелы и знаки перевода строки \n
в конце строки.
s = 'Текст'
s.rstrip('ст')
Тек
s = 'Текст'
s.split('к')
['Те', 'ст']
s = 'Текст\nстрока'
s.splitlines()
['Текст', 'строка']
s = 'Текст\nстрока'
s.partition('\n')
('Текст', '\n', 'строка')
s = 'Текст текст'
s.find('кс')
Результат:
2
55
rfind — ищет заданную подстроку в строке и возвращает номер позиции по-
следнего вхождения. Если подстрока не найдена, возвращается –1.
s = 'Текст текст'
s.rfind('кс')
s = 'Текст текст'
s.count('кс')
2
s = 'Текст текст'
s.startswith('кс')
False
s = 'Текст текст'
s.endswith('ст')
True
s = 'Текст текст'
s.replace('кс', 'н')
Тент тент
3.9. Условия
if условие:
инструкции
a = 1
if a == 1:
print('Yes')
56
Результат:
Yes
if условие:
инструкции 1
else:
инструкции 2
a = 1
if a == 2:
print('Yes')
else:
print('No')
No
if условие 1:
инструкции 1
elif условие 2:
инструкции 2
...
elif условие n:
инструкции n
else:
инструкции на случай ложности всех условий
Простой пример:
a = 4
if a == 1:
print('Один')
elif a == 2:
print('Два')
elif a == 3:
print('Три')
else:
print('Сопоставление не найдено')
Сопоставление не найдено
if a == 1:
инструкции 1
if a == 2:
инструкции 2
if a == 3:
инструкции 3
Вот пример:
a = 4
if a == 1:
print('Один')
if a == 2:
print('Два')
if a == 3:
print('Три')
if a == 1:
инструкции 1
elif a == 2:
инструкции 2
elif a == 3:
инструкции 3
a = 2
if a == 1:
print('Один')
elif a == 2:
print('Два')
elif a == 3:
print('Три')
Два
#! C:/Python/python
def func(pr):
return pr*2
a = 4
58
b = 2
if a == func(b):
print('Равно')
if a == func(b):
3.10. Циклы
#! C:/Python/python
59
print(i**2)
print('<br>')
#! C:/Python/python
while условие:
инструкции
60
Пример записи цикла в реальной программе (файл 3_10_3.py):
#! C:/Python/python
i = 0
while i <= 5:
print(i*2)
print('<br>')
i += 1
#! C:/Python/python
print('Content-type: text/html; charset=utf-8\n\n')
def func(pr):
if pr < 6:
pr += 1
return pr
i = 0
while i < func(i):
print(i)
print('<br>')
i += 1
61
В функции задано ограничение — она работает, пока переданное значение
меньше 6:
def func(pr):
if pr < 6:
pr += 1
return pr
if pr < 6:
Рис. 3.10.4. Выводим числа в цикле while, условие для которого получаем
из функции
62
Второй полезный оператор — break. Он необходим для полной остановки
цикла в случае выполнения определенных условий. Следующая программа
i = 1
while i < 6:
if i == 4:
break
print(i)
i += 1
1 2 3
#! C:/Python/python
import re
it = re.compile('[a-z]+')
ar = ['Python', '12345']
res = it.search(ar[i])
программа обнаруживает, что поиск букв был успешен, и выводит об этом со-
общение:
if res:
print(ar[i], ' - это текст<br>')
else:
print(ar[i], ' - это не текст<br>')
64
Если выполняется проверка строки, которая полностью должна совпадать с
регулярным выражением, то используется привязка регулярного выражения к
началу и концу строки. Делается это с помощью таких метасимволов:
\b — привязка к началу слова (началом слова считается пробел или любой сим-
вол, кроме буквы, цифры и знака подчеркивания).
[^0-9]
65
Продолжение табл. 3.11.2
Класс Комментарий
\w Любая латинская буква, цифра или символ подчерки-
вания
\W Не латинская буква, цифра или символ подчеркивания
\s Пробельный символ
\S Не пробельный символ
Если необходимо искать в строке точку, то это можно сделать двумя спосо-
бами:
– заключив ее в квадратные скобки (например, вместе с другими символами)
– [.];
– поставив перед ней слеш — \.
Если необходимо искать в строке дефис, то отменить его специальное зна-
чение можно также двумя способами:
– заключив его в квадратные скобки (например, вместе с другими символа-
ми) и расположив последним в перечислении — [-];
– поставив перед ним слеш — \-.
Квантификаторы задают количество вхождений символа или группы сим-
волов в строку. Они перечислены в таблице 3.11.3.
шаблон.sub(заменяющая_строка, заменяемая_строка)
66
Пример:
it = re.compile('\d')
it.sub('A', '123456789')
Результат:
AAAAAAAAA
3.12. Списки
a = [0, 1, 2, 3, 4, 5]
a = list('Python')
Результат:
Результат:
67
a = [0, 1, 2, 3, 4, 5]
a[2] = 'два'
Результат:
[0, 1, 'два', 3, 4, 5]
a = [0, 1, 2, 3, 4, 5]
len(a)
6
a = []
a.append('Py')
a.append('thon')
a.append('3')
68
Получим
Операция конкатенации:
a = [0, 1, 2]
b = [9, 8, 7]
c = a + b
[0, 1, 2, 9, 8, 7]
a = [0, 1, 2]
a.extend('Python')
[0, 1, 2, 'P', 'y', 't', 'h', 'o', 'n']
a.insert(индекс, элемент)
Пример:
a = [0, 1, 2]
a.insert(1, 'Python')
[0, 'Python', 1, 2]
a = [0, 'Python', 1, 2]
a.pop(1)
[0, 1, 2]
a = [0, 'Python', 1, 2]
a.pop()
[0, 'Python', 1]
a = [0, 1, 0, 2, 1]
a.clear()
[]
a = [3, 1, 9, 5, 7, 2]
a.sort()
Результат:
[1, 2, 3, 5, 7, 9]
a = [3, 1, 9, 5, 7, 2]
a.sort(reverse = True)
[9, 7, 5, 3, 2, 1]
3.13. Кортежи
70
1. Перечислив все элементы через запятую внутри круглых скобок:
a = (3, 1, 9, 5, 7, 2)
a = [3, 1, 9, 5, 7, 2]
tuple(a)
Результат:
(3, 1, 9, 5, 7, 2)
Если у вас в кортеже всего один элемент, после него обязательно должна
стоять запятая:
a = (3,)
a = (3, 1, 9, 5, 7, 2)
a[2]
9
a = (3, 1, 9, 5, 7, 2, 9)
a.count(9)
2
a = [0, 1, 2, 3, 4, 5]
len(a)
6
a = (3, 1, 9, 5, 7, 2)
a += (8, 0, 4, 6)
print(a)
(3, 1, 9, 5, 7, 2, 8, 0, 4, 6)
71
3.14. Множества
Результат:
#! C:/Python/python
Результат:
72
a | b или a.union(b) — объединение двух или более множеств:
a = set([0, 1, 2])
b = set([3, 4, 5])
c = set([6, 7, 8, 9])
a | b | c
Результат:
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
Другой случай:
a = set([0, 1, 2])
b = set([3, 4, 5])
a.union(b)
Результат:
{0, 1, 2, 3, 4, 5}
a = set([0, 1, 2])
b = set([3, 4, 5])
a |= b
или
a = set([0, 1, 2])
b = set([3, 4, 5])
a.update(b)
Результат:
{0, 1, 2, 3, 4, 5}
a = set([0, 1, 2, 3, 4])
b = set([3, 4, 5, 6, 7])
a & b
или
a = set([0, 1, 2, 3, 4])
b = set([3, 4, 5, 6, 7])
a.intersection(b)
73
Результат:
{3, 4}
a = set([0, 1, 2, 3, 4])
b = set([3, 4, 5, 6, 7])
a == b
False
a = set([0, 1, 2, 3, 4])
b = set([3, 4, 5, 6, 7])
a != b
True
a = set([0, 1, 2, 3, 4])
b = set([3, 4, 5, 6, 7])
a > b
False
a = set([3, 4])
b = set([3, 4, 5, 6, 7])
a < b
True
a = set([0, 1, 2])
b = set([3, 4, 5, 6, 7])
a.isdisjoint(b)
True
74
Чтобы удалить элемент из множества, примените метод remove:
{'Python', '3'}
#! C:/Python/python
print('Content-type: text/html; charset=utf-8\n\n')
st = set(['Python', 'версия', '3'])
a = list(st)
print(a)
print('<br><br>')
print(a[1])
3.15. Диапазоны
75
Чтобы создать диапазон, необходимо применить функцию range. Ее формат:
#! C:/Python/python
print('Content-type: text/html; charset=utf-8\n\n')
3.16. Словари
76
#! C:/Python/python
Результат:
версия
True
77
items — возвращает объект в виде списка, состоящего из кортежей, в которые
входят ключи и значения:
Из данных объекта легко получить текущее время. Напишем для этого специ-
альную программу (файл 3_17_1.py):
#! C:/Python/python
import time
dw = ['понедельник', 'вторник', 'среда', 'четверг',
'пятница', 'суббота', 'воскресенье']
tm = time.localtime()
print('Content-type: text/html; charset=utf-8\n\n')
print(tm)
print('<br><br>Сегодня: ')
print(dw[tm[6]], str(tm[2]), str(tm[1]),
str(tm[0]), 'г.')
print('<br>Время: ')
print(str(tm[3]), ':', str(tm[4]), ':', str(tm[5]))
3.18. Файлы
79
Начнем с того, что для открытия файлов применяется функция open следу-
ющего формата:
open('img.jpg', 'wb')
После чтения или записи файл необходимо закрыть с помощью метода close:
#! C:/Python/python
fo = open('test/text.txt', encoding='utf-8')
tx = fo.read()
fo.close()
80
В результате текст из файла окажется в окне браузера (рис. 3.18.1).
fo = open('test/text.txt', encoding='utf-8')
tx = fo. readlines()
fo.close()
#! C:/Python/python
#! C:/Python/python
81
fo = open('test/text.txt', 'w', encoding='utf-8')
fo.write('\nНовый текст')
fo.close()
fo = open('test/text.txt', encoding='utf-8')
tx = fo.read()
fo.close()
print('Content-type: text/html; charset=utf-8\n\n')
print(tx)
#! C:/Python/python
print(tx)
82
Теперь рассмотрим несколько функций для манипулирования файлами.
Для начала возьмем две полезные функции из модуля os.
os.rename('test/text.txt', 'test/1.txt')
os.remove('test/1.txt')
shutil.copy('test/test.txt', 'exper/new.txt')
shutil.move('exper/new.txt', 'test')
Этот раздел касается всего одного пункта — указания кодировки при от-
крытии файла.
Например, в PHP или Perl для корректного чтения и записи в текстовый
файл достаточно того, что сама программа и текстовый файл были созданы в
кодировке utf-8. В Python дело обстоит иначе.
Если вы помните, устанавливая интерпретатор, мы открывали файл
httpd.conf из папки сервера C:\Apache24\conf и добавляли в самый конец стро-
ку
83
#! C:/Python/python
fo = open('content/text.txt')
tx = fo.read()
fo.close()
Рис. 3.19.1. Попытка открыть текстовый файл без указания его кодировки
print('Content-type: text/html\n\n')
print('<!DOCTYPE html>')
...
print('<meta charset="utf-8">')
...
open(adr, encoding='utf-8')
84
3.20. Каталоги
#! C:/Python/python
import os
opdir = os.listdir('content')
print('Content-type: text/html; charset=utf-8\n\n')
print(opdir)
#! C:/Python/python
import os
os.mkdir('empty')
print('Content-type: text/html; charset=utf-8\n\n')
print('Каталог создан!')
rmdir — удаляет пустой каталог. Если в нем есть вложенные папки и файлы,
сначала необходимо удалить их. В следующем примере мы удалим созданный
на предыдущем шаге пустой каталог empty (файл 3_20_3.py).
#! C:/Python/python
85
import os
os.rmdir('empty')
print('Content-type: text/html; charset=utf-8\n\n')
print('Каталог удален!')
#! C:/Python/python
import shutil
shutil.rmtree('test')
3.21. Функции
86
return Возвращаемое_значение
# Определение функции
def func():
...
инструкции
...
# Вызов функции
func()
#! C:/Python/python
b = 'Язык программирования '
def func():
d = b + 'Python'
print(d)
#! C:/Python/python
87
Она вычисляет сумму двух исходных чисел. Какой результат мы получили,
видно на рисунке 3.21.2.
#! C:/Python/python
print(func(5, 10))
print('<br><br>')
func(5, 1)
не печатается.
При втором вызове функции ее блок, содержащий инструкцию return,
пропускается, а значит, последняя строка теперь появляется на экране ком-
пьютера.
Результат двух разных вызовов функции func показан на рисунке 3.21.3.
88
Рис. 3.21.3. Результат работы функции с инструкцией return в середине
#! C:/Python/python
def func(a, b):
d = a + b
return d
s = func
print('Content-type: text/html; charset=utf-8\n\n')
print(s(5, 10))
#! C:/Python/python
s1 = lambda: 1 + 2
s2 = lambda a, b: a + b
89
print(s1())
print('<br><br>')
print(s2(5, 10))
3.22. Модули
import cgi
90
import cgi, os — это неправильно!
import cgi
import os
def func(i):
return i ** 2
91
Теперь напишем основную программу. Она будет передавать в модуль чис-
ло 7 и печатать возвращенный результат. Назовем этот файл 3_22_1.py.
В начале программы указываем путь к интерпретатору:
#! C:/Python/python
import mymod
и предварительный текст:
mymod.func(7)
и печатаем результат:
print(mymod.func(7))
Его вы можете посмотреть на рисунке 3.22.1. Как видите, наш модуль пре-
красно работает.
Теперь еще один важный момент. Вы, наверное, обратили внимание, что
после первого запуска нашего модуля в рабочем каталоге C:\Apache24\htdocs
появилась новая папка __pycache__ с файлом внутри. Это произошло вот по
какой причине. При запуске модуль сначала компилируется и преобразуется в
особый байт-код. Для откомпилированных модулей Python создает в каталоге с
модулем специальную папку __pycache__ и размещает в ней откомпилирован-
92
ный файл с именем module.cpython-XX.pyc, где module — имя модуля,
cpython- — стандартная часть, присутствующая в именах всех откомпилиро-
ванных файлов, XX — первые две цифры номера версии Python, а .pyc — рас-
ширение файла. До тех пор, пока в коде основного модуля не произойдут изме-
нения, при каждом его вызове Python будет запускать именно откомпилирован-
ный файл. Делается это для ускорения работы программ.
93
4. Практика
#! C:/Python/python
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _
| |
| Код Python |
|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _|
print('Content-type: text/html\n\n')
print('<!DOCTYPE html>')
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
| |
| HTML-код |
|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _
| |
| Код Python |
|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _|
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
| |
| HTML-код |
|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _
| |
94
| Код Python |
|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _|
print('</body></html>')
print('Content-type: text/html\n\n')
print('<!DOCTYPE html>')
print('<html lang="ru">')
print('<head>')
print('<meta charset="utf-8">')
print('<title>Заголовок</title>')
print('</head>')
print('<body>')
print('<div>')
...
...
...
'''Этот
текст
не
выводится
в
браузере'''
print('Content-type: text/html\n\n')
print('''<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
95
<title>Заголовок</title>
</head>
<body>
<div>
...
...
...''')
#! C:/Python/python
# Начинаем печатать страницу.
print('Content-type: text/html\n\n')
print('''<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Абстракции</title>
<style>
body {margin: 0;}
div {position: relative; width: 1000px; margin: auto;
text-align: center;}
p {text-align: center; font-family: Tahoma;
96
font-size: 24px;}
img {width: 300px; border: 1px solid #000000;}
</style>
</head>
<body>
<div>
<p>Абстракции</p>
<img src="abs/1.jpg" alt="Абстракция">
<img src="abs/2.jpg" alt="Абстракция">
<img src="abs/3.jpg" alt="Абстракция">
<br>
...
<img src="abs/31.jpg" alt="Абстракция">
<img src="abs/32.jpg" alt="Абстракция">
<img src="abs/33.jpg" alt="Абстракция">
</div>
</body>
</html>''')
Завершая этот раздел, хочу обратить внимание читателей на еще один важ-
ный момент. Если раньше мы писали тип загружаемого документа так:
print('Content-type: text/html\n\n')
<meta charset="utf-8">
97
Ниже — текст «Вас зовут» без продолжения, так как мы еще ничего не вводили
и не отправляли форму.
Заполним поля. Например, введем имя Иван, а фамилию Иванов. Нажмем
кнопку «Отправить». Программа получит данные из формы и выведет их рядом
с текстом «Вас зовут» (рис. 4.2.2.).
Начинаем писать программу.
Первым делом указываем путь к интерпретатору:
#! C:/Python/python
import cgi
nam = ''
98
sur = ''
form = cgi.FieldStorage()
if form.getfirst('nam'):
nam = form.getfirst('nam')
if form.getfirst('sur'):
sur = form.getfirst('sur')
print('Content-type: text/html\n\n')
print('''<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Данные из формы</title>
<style>
span {font-weight: bold; font-size: 24px;}
</style>
</head>
<body>
<p> </p>
<form method="POST" action="4_2_1.py">
<p>Введите имя: <input name="nam"></p>
<p>Введите фамилию: <input name="sur"></p>
<p><input type="submit" value="Отправить"></p>
</form>
<p>Вас зовут: <span>''' + nam + '</span> <span>' +
sur + '''</span></p>
99
</body>
</html>''')
100
Рис. 4.3.1. Форма
Рис. 4.3.2. Предупреждение, если в полях формы введено всего по одному знаку
101
Рис. 4.3.3. Предупреждение, если количество знаков в полях формы превышает
допустимые значения
#! C:/Python/python
import cgi
form = cgi.FieldStorage()
nam = form.getfirst('nam')
sur = form.getfirst('sur')
print('Content-type: text/html\n\n')
print('''<!DOCTYPE html>
102
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Проверка данных из формы</title>
<style>
span {font-weight: bold; font-size: 24px;}
</style>
</head>
<body>
<p> </p>
<form method="POST" action="4_3_1.py">
<p>Введите имя: <input name="nam"></p>
<p>Введите фамилию: <input name="sur"></p>
<p><input type="submit" value="Отправить"></p>
</form>''')
Начинаем проверку.
Первым делом определяем, содержатся ли какие-то данные в переменных
nam и sur. Если форма отправлена пустой, то выводим соответствующее пре-
дупреждение:
else:
print('<p>Вас зовут: <span>' + nam +
'</span> <span>' + sur + '</span></p>')
print('''</body>
</html>''')
103
Для иллюстрации проверки на соответствие данных установленному фор-
мату мы рассмотрим программу 4_3_2.py. Она проверяет корректность введен-
ного адреса электронной почты (рис. 4.3.5).
В примере выше мы определяли количество знаков в полях формы. Однако для
выяснения корректности e-mail этих параметров недостаточно. Мы не проверили:
– наличие в адресе электронной почты знака @;
– наличие обязательной точки, разделяющей доменные имена первого и
второго уровней;
– наличие в адресе запрещенных символов.
Решить данную проблему нам поможет регулярное выражение. Попробуем
написать его для проверки адреса почты.
Вообще, корректный e-mail может содержать самые разнообразные симво-
лы. Но мы будем ориентироваться на требования, которые предъявляют к адре-
сам российские почтовые сервисы. А они заметно снижают перечень таких
символов. Например, в Яндекс.Почте установлены следующие требования:
– разрешены буквы латинского алфавита, цифры, точки, дефисы;
– адрес не должен начинаться с цифры, дефиса или точки;
– адрес не может заканчиваться точкой или дефисом.
Есть правила и для доменных имен второго уровня:
– они могут содержать латинские буквы, цифры и дефис;
– имя может начинаться с цифры или буквы;
– имя не может завершаться дефисом.
Введите в поле формы электронный адрес, нарушающий эти правила и
нажмите клавишу «Enter» на компьютере. Ниже поля появится короткое сообще-
ние «Ошибка!» (рис. 4.3.6). Теперь введите корректный адрес и снова нажмите
«Enter». Вы увидите подтверждение, что «E-mail правильный» (рис. 4.3.7).
Прежде чем разбирать код такой программы, выясним, что должно представ-
лять собой регулярное выражение, созданное по правилам, описанным выше.
Адрес не должен начинаться с цифры, дефиса или точки. Этому требованию
удовлетворяет вот такой фрагмент выражения:
104
Рис. 4.3.6. Сообщение о некорректном e-mail
[a-z]
То есть, первый символ — только буква. Затем идет некоторое количество про-
извольных символов из тех, что разрешены — буквы, цифры, точка, дефис:
[a-z\d.-]+
Знак «+» означает, что символов может быть более одного. Наконец, заверша-
ющий символ — буква или цифра:
[a-z\d]
[a-z\d]
105
Следом могут идти буквы, цифры и дефис:
[a-z\d-]+
[a-z\d]
Имя домена второго уровня отделяется точкой от имени домена первого уровня:
\.
[a-z]{2,13}
r'^...$'
r'^[a-z][a-z\d.-]+[a-z\d]@[a-z\d][a-z\d-]+[a-z\d]\.
[a-z]{2,13}$'
#! C:/Python/python
import cgi
import re
form = cgi.FieldStorage()
em = form.getfirst('em')
print('Content-type: text/html\n\n')
print('''<!DOCTYPE html>
<html lang="ru">
106
<head>
<meta charset="utf-8">
<title>Проверка e-mail</title>
<style>
b {font-size: 24px;}
</style>
</head>
<body>
<p> </p>
<form method="POST" action="4_3_2.py">
<p>Введите e-mail:</p>
<p><input name="em"></p>
</form>''')
108
Рис. 4.4.3. Файл загружен и показан на странице
Как видите, процесс выглядит точно так же, как на других ресурсах.
Программа в обязательном порядке начинается с указания пути к интерпре-
татору. Это действие настолько уже привычно и стандартно, что мы в дальней-
шем не будем упоминать о нем. А вот загружаемые модули перечислим, так как
для разных скриптов они могут быть разными. В данном случае необходимы
два модуля:
import cgi
import os
form = cgi.FieldStorage()
и получаем данные:
imfo = form.getfirst('pict')
Вторая операция нужна только для того, чтобы создать элемент для проверки,
была ли выполнена загрузка. Реальное получение файла произойдет позже и
другим способом.
Печатаем основную часть страницы:
109
print('Content-type: text/html\n\n')
print('''<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Загрузка изображения</title>
</head>
<body>
<p> </p>
<form method="POST" action="4_4_1.py"
enctype="multipart/form-data">
<p><input type="file" name="pict"></p>
<p><input type="submit"></p>
</form>''')
if imfo:
else:
print('Выберите файл !')
print('''</body>
</html>''')
up = form['pict']
ima = os.path.basename(up.filename)
Второе действие необходимо, чтобы сохранить загруженный файл под его ис-
ходным именем.
Следующий шаг — создаем в папке pict новый файл и помещаем данные
этого объекта в переменную fim:
110
Четвертый шаг — запись данных исходного файла в тот, что был создан на
предыдущем этапе:
fim.write(up.file.read())
up.file.read()
а потом запись:
fim.write(...)
import cgi
town = 'Москва'
form = cgi.FieldStorage()
if form:
town = form.getfirst('t')
Печатаем страницу:
112
print('Content-type: text/html\n\n')
print('''<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Безусловный вывод данных</title>
<style>
span {font-weight: bold; font-size: 24px;}
</style>
</head>
<body>
<p> </p>
<p>Город, в котором вы живете: <span>''' + town +
'''</span></p>
</body>
</html>''')
113
Рис. 4.5.4. Вводим название города
print('Content-type: text/html\n\n')
print('''<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Условный вывод данных</title>
<style>
span {font-weight: bold; font-size: 24px;}
</style>
</head>
<body>
<p> </p>
<p>Город, в котором вы живете:''')
form = cgi.FieldStorage()
if form:
town = form.getfirst('t')
114
выводим название города на страницу:
print('''</p>
</body>
</html>''')
115
Теперь в строке запроса измените цифру 1 на 2: http://localhost/
4_6_1.py?a=2. Появится другая страница под названием «Абстракционизм»
(рис. 4.6.2). Она извлечена из файла 2.txt папки content. (Обе статьи цитируют
сайт КУЛЬТУРА.РФ.)
Как видите, указание в строке запроса одного и того же параметра с разными
значениями позволяет одному и тому же файлу Python загружать в браузер разные
страницы. Мы уже говорили об этом, но автор посчитал нелишним напомнить:
в подавляющем большинстве случаев разработчик не пишет для каждой страницы
отдельный файл Python, а создает одну программу, которая на основе данных из
запроса формирует ту или иную страницу с тем или иным содержанием.
Перейдем к разбору программы. Нам понадобится всего один модуль:
import cgi
print('Content-type: text/html\n\n')
print('''<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Контент по запросу</title>
<style>
b {font-size: 24px;}
</style>
</head>
<body>''')
116
Получаем данные из формы:
form = cgi.FieldStorage()
if form:
abs = form.getfirst('a')
print('''</body>
</html>''')
Завершая этот раздел, будет не лишним еще раз напомнить читателям про
безопасность сайта и проверку данных из запросов. В нашей программе цифра
из параметра a соответствовала номеру файла из папки content. Это нормаль-
ная практика при условии, что в программе Python предусмотрена проверка на
существование файла с введенным именем и разрешено открытие файлов толь-
ко из директории content.
117
«Больше 21 года» и снова нажмите кнопку. Теперь программа сообщит вам, что в
этом случае вы можете избираться в законодательные органы власти (рис. 4.7.3).
print('Content-type: text/html\n\n')
print('''<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Передача параметра в условное выражение</title>
<style>
b {font-size: 24px;}
</style>
118
</head>
<body>
<form method="POST" action="4_7_1.py">
Ваш возраст: <select name="a">
<option selected value="1">Меньше 21 года</option>
<option value="2">Больше 21 года</option>
</select>
<input type="submit" value="Комментировать">
</form>''')
Здесь мы прерываем вывод, так как пришло время напечатать ответ посети-
телю. Для этого сначала получаем данные из формы:
form = cgi.FieldStorage()
if form:
age = int(form.getfirst('a'))
if age == 1:
print ('<br><b>Увы. Ваш возраст не позволяет
вам стать депутатом.</b>')
else:
print ('<br><b>Ваш возраст позволяет вам
стать депутатом.</b>')
119
Рис. 4.7.5. Результат вычислений
print('Content-type: text/html\n\n')
print('''<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Передача параметра в цикл</title>
<style>
b {font-size: 24px;}
</style>
</head>
<body>
<form method="POST" action="4_7_2.py">
Вычислить сумму чисел от 1 до: <select name="s">
<option selected value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
<option value="6">6</option>
<option value="7">7</option>
<option value="8">8</option>
<option value="9">9</option>
<option value="10">10</option>
</select>
<input type="submit" value="Вычислить">
</form>''')
if form:
sum = int(form.getfirst('s'))
120
rs = 1
i = 0
rs += sum - i
i += 1
Посмотрим этот порядок на примере значения 3 (то есть будет два прохода
цикла). На первом проходе к исходному значению результатов вычисления
прибавляется число, представляющее верхнюю границу диапазона минус
начальное значение счетчика:
121
и закрывающие теги страницы:
print('''</body>
</html>''')
str(rs)
import cgi
и печатаем страницу:
print('Content-type: text/html\n\n')
print('''<!DOCTYPE html>
<html lang="ru">
122
<head>
<meta charset="utf-8">
<title>Передача параметра в функцию</title>
<style>
b {font-size: 24px;}
</style>
</head>
<body>
<form method="POST" action="4_7_3.py">
Вычислить квадрат числа: <select name="s">
<option selected value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
<option value="6">6</option>
<option value="7">7</option>
<option value="8">8</option>
<option value="9">9</option>
<option value="10">10</option>
</select>
<input type="submit" value="Вычислить">
</form>''')
form = cgi.FieldStorage()
if form:
sum = int(form.getfirst('s'))
def func(i):
t = i ** 2
return '<br><b>' + str(t) + '</b>'
print(func(sum) +
'''</body>
</html>''')
Cookie — это текстовые файлы, которые тот или иной сайт создает на ва-
шем компьютере. Cookie устанавливаются для конкретного ресурса и через
конкретный браузер (то есть если на вашем компьютере несколько web-
обозревателей, то cookie будут создаваться отдельно для каждого из них, в за-
висимости от того, через какой браузер вы станете посещать тот или иной ре-
сурс). В таких файлах может храниться самая разнообразная информация:
– о прохождении регистрации или аутентификации пользователем;
123
– о его интересах и предпочтениях;
– об избранных страницах;
– о времени предыдущих посещений ресурса;
– о сделанных заказах в Интернет-магазинах;
– множество иных данных.
В Python имеется довольно простой «механизм» установки и чтения cookie.
Рассмотрим его на конкретном примере. Для этого необходимо запустить файл
4_8_1.py. Вы увидите страницу с выпадающим списком, в котором вам предла-
гается сделать выбор из двух операций: «Установить» и «Посмотреть» cookie
(рис. 4.8.1). Если сразу выбрать пункт «Посмотреть», то на странице появится
текст «Вы еще не установили cookie» (рис. 4.8.2).
import cgi
import os
sc = ''
form = cgi.FieldStorage()
if form:
co = int(form.getfirst('c'))
if co == 1:
print('Set-cookie: testcook=12345')
sc = 'Установлено'
и проверяем, содержит ли переменная htc какие-либо данные или нет. Если пе-
ременная не пустая, значит, cookie уже установлено, и можно показать его имя
и значение:
if htc:
sc = '<br><b>Cookie: ' + htc + '</b>'
126
4.9. Бесконечная лента
127
Поэкспериментируем. Прокрутите страницу вниз до упора. Ползунок не-
ожиданно укоротится и немного сместится вверх, а на странице появится не-
сколько новых рисунков. Попробуйте опять прокрутить страницу вниз до упо-
ра. Эффект повторится: ползунок еще укоротится и вновь сместится вверх, а
на странице появится очередная порция картинок (рис. 4.9.2). Так будет про-
исходить до тех пор, пока вы не решите, что экспериментов достаточно. Это и
есть наша версия бесконечной ленты новостей.
Тут необходимо сделать одну оговорку. Естественно, что автор не стал со-
бирать несколько сотен изображений для максимально натуральной демон-
страции эффекта бесконечной ленты. В папке abs, из которой «черпаются» эти
изображения, всего 33 файла. Поэтому снимки довольно быстро закончатся.
Но, согласитесь, этого вполне достаточно для наглядного примера. Тем более
что непрерывно уменьшающийся размер ползунка подтверждает — картинки
загружаются именно в процессе прокрутки страницы.
Кстати, на этом работа бесконечной ленты не прекратится. Вместо фото-
графий на странице начнут появляться иконки, замещающие отсутствующие
изображения. То есть процесс действительно будет бесконечным.
128
Сценарий, который отправляет запросы серверной программе, мы не станем
разбирать. При желании вы можете посмотреть JavaScript-код позже, открыв
страницу 4_9_1.html в текстовом редакторе Notepad++. Там все очень просто.
А вот программу отправки изображений с сервера — 4_9_1.py — посмот-
рим сейчас. Она очень короткая и состоит всего из шести строк.
Начинаем традиционно:
#! C:/Python/python
import cgi
form = cgi.FieldStorage()
st = form.getfirst('st')
print('Content-type: text/html\n\n')
import cgi
import os
После их импортирования начинаем печатать страницу:
130
<body>
<form method="POST" action="4_10_1.py">
<p>Введите слово: <input name="wo">
<input type="submit" value="Искать"></p>
</form>''')
len(opdir) + 1
str(x)
ti = fo.readlines()
Закрываем файл:
fo.close()
131
Здесь в диапазоне начальная точка отсчета 0, а конечная (напоминаю, не вхо-
дящая в диапазон) равна количеству строк в списке:
len(ti)
if ti[i].find(wo) != -1:
print('''</body>
</html>''')
132
ними словами и выглядеть так: «В тексте есть вот та-
каяhttps://mysite.ruссылка». Подобное нередко случается при наборе текста
со смартфона. Как в таком случае отделить ссылку?
Автор предлагает вам рассмотреть небольшую программу, рассчитанную на
выявление ссылок вида https://mysite.ru, как бы они ни были замаскированы в
тексте. Обращаю ваше внимание: программа корректно работает только с про-
стыми ссылками! Вот такую строку https://mysite.ru/content/cont.py?arg=
no®=yes&time=1 она уже не распознает. Для ее подсвечивания нужны бо-
лее сложные программы.
Итак, у нас есть программа, которая находит ссылки, начинающиеся с
https:// и заканчивающиеся доменным именем первого уровня .ru. Она содер-
жится в файле 4_11_1.py. Запустим его. Мы увидим поле с текстом, в который
без пробелов встроена ссылка на поисковый сервис Yandex (рис. 4.11.1). Ниже
поля — кнопка «Проверить». Нажмем ее. Результат показан на рисунке 4.11.2.
Как видите, программа распознала ссылку. Если навести на нее указатель мы-
ши, в нижней левой части браузера мы увидим ее адрес — он правильный.
А если кликнуть на ссылке, то мы попадем на главную страницу ресурса
yandex.ru. Кстати, в порядке эксперимента вы можете самостоятельно доба-
вить еще текст и ссылки для проверки скрипта.
133
Рис. 4.11.2. Подсвеченная ссылка
print('Content-type: text/html\n\n')
print('''<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Поиск ссылок</title>
<style>
textarea {width: 500px; height: 200px;
font-size: 24px;}
p {font-size: 24px;}
</style>
</head>
<body>
<form method="POST" action="4_11_1.py">
<p><textarea name="ta">В этом тексте есть вот
такаяhttps://yandex.ruссылка.
Проверьте, как она будет подсвечена.</textarea><br>
<input type="submit" value="Проверить"></p>
</form>''')
form = cgi.FieldStorage()
if form:
ta = form.getfirst('ta')
134
С помощью метода split разделяем полученный текст на отдельные слова
(разделителем при отсутствии символов в скобках служит пробел):
wo=ta.split()
Если они нашлись, разбиваем это слово на два фрагмента, используя в качестве
разделителя символы протокола:
spwo=wo[zz].split('https://')
Если оно есть, в свою очередь делим второй фрагмент на два по разделите-
лю .ru:
newspwo = spwo[1].split('.ru')
наберите
C:\WINDOWS\System32>
import cgi
import os
from PIL import Image
print('Content-type: text/html\n\n')
print('''<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Размер изображения</title>
<style>
b {font-size: 24px;}
</style>
</head>
<body>
<form method="POST" action="4_12_1.py">
Выбрать изображение: <select name="im">''')
opdir = os.listdir('abs')
и запустим цикл печати тегов option. Для этого введем счетчик проходов:
i = 0
if i == 0:
else:
print('<option value="' + opdir[i] + '">' +
opdir[i] + '</option>')
139
В конце каждого прохода увеличиваем счетчик на 1:
i += 1
print('''</select>
<input type="submit" value="Узнать размер">
</form>''')
form = cgi.FieldStorage()
if form:
adr = form.getfirst('im')
wi, he = ima.size
print('''</body>
</html>''')
140
только кнопка — на ней надпись «Изменить размер» (рис. 4.12.6). Выберите из
списка какой-то рисунок и нажмите кнопку. Страница перезагрузится, и на ней
появится уменьшенная в четыре раза картинка с указанием ее нового размера в
пикселях (рис. 4.12.7). Вы также можете убедиться, что новое изображение ока-
залось в папке pict, открыв данный каталог.
Для этой программы снова нужны три модуля:
import cgi
import os
from PIL import Image
print('''</select>
<input type="submit" value="Узнать размер">
</form>''')
141
Получаем данные с именем запрошенного изображения:
form = cgi.FieldStorage()
if form:
adr = form.getfirst('im')
newwi = int(wi/2)
newhe = int(he/2)
newima.save('pict/' + adr)
print('''</body>
</html>''')
142
5. Пишем сайт
143
Также необходимо напомнить, что тема ресурса — реклама студии звукоза-
писи (не существующей в реальности).
Всего сделано 6 страниц. Пять из них посвящены музыкальным инструмен-
там, которыми оснащена студия. Шестая содержит форму для отправки заявок
на услуги звукозаписи. Страница «Синтезаторы» является одновременно глав-
ной.
Компоновка страницы сайта показана на рисунке 5.1.1.
Главную страницу сайта можно видеть на рисунке 5.1.2.
144
Нескольких комментариев к рисунку 5.1.2.
1. Все картинки и фотографии, использованные в качестве элементов ди-
зайна, а также в качестве контента, взяты с сайта бесплатных изображений.
Данный сайт разрешает использовать эти изображения без указания автор-
ства — в любых целях, в том числе коммерческих.
2. Текст страниц написан автором на основе данных из нескольких источ-
ников и носит произвольный характер. Все марки производителей музыкаль-
ных инструментов — выдуманные.
3. Блок новостей носит чисто изобразительную нагрузку. Страницы анонси-
рованных событий, как и ссылки на них, не существуют.
На каждой странице, кроме «Контакты», в области контента есть по два
изображения. Посетитель может увеличить любое из них, щелкнув мышью по
картинке. При этом страница будет закрыта белым полупрозрачным слоем с
увеличенным изображением. Если теперь кликнуть на нем или прокрутить
страницу, увеличенная картинка и полупрозрачный слой исчезнут. Управляет
данным процессом сценарий, написанный на JavaScript. Его мы разберем поз-
же, в главе 6.
5.2. Компоненты
145
Исходя из этого, выходит, что сайт должен иметь страницы, представляю-
щие техническое оборудование студии, и страницу, где клиент может оформить
и отправить заявку. В свою очередь, наличие второго пункта подразумевает,
что администратор должен иметь возможность получать и фиксировать заявки.
Автор выбрал систему сбора заявок, основанную не на отправке их по элек-
тронной почте, а на записи в файл, который можно легко прочитать через брау-
зер и перенести данные из файла на свой компьютер. Так у читателя появляется
больше возможностей наблюдать за работой Python. К тому же это вполне рав-
ноценная замена. Судите сами. В обоих случаях необходим запуск на компью-
тере соответствующей программы — почтового клиента или web-обозревателя,
а также копирование данных из письма или со страницы с заявками. Вариант с
файлом даже удобнее: не надо по очереди открывать каждое письмо. Открыл
файл и сразу перенес на свой ПК все данные. Раз у нас будет файл, значит, ад-
министратор должен иметь возможность удалять из него уже скопированные
заявки.
Чтобы реализовать все запланированные цели, нам потребуется следующий
набор файлов Python:
– шаблон сайта, в который будут загружаться данные из разных страниц;
– программа записи заявок;
– страница просмотра заявок, доступная только администратору;
– программа удаления заявок, запустить которую может только админи-
стратор.
Кроме того, понадобится еще целый ряд компонентов, которые будут со-
держать все остальные элементы, необходимые для функционирования сайта.
Посмотрим, что есть в zip-архиве для решения поставленных задач:
– файл index.py — шаблон сайта;
– файл rec.py — программа записи заявок;
– файл admin.py — страница просмотра заявок;
– файл del.py — программа удаления заявок
– 4 папки — img, studio, content и set.
Папка img содержит два файла:
– muz.jpg — заставка сайта;
– net.jpg — его назначение выяснится в разделе 6.1.
В папке studio собраны фотографии, использованные в оформлении стра-
ниц.
В папке content 6 текстовых файлов. Пять из них содержат контент основ-
ных страниц, а в файле contact.txt записан HTML-код формы для заявок.
При создании проекта не использовалась база данных. Как видите, вся ин-
формация, размещенная на сайте, хранится в простых текстовых файлах. Сде-
лано это по двум причинам:
– сайту нечего скрывать, так как никакой секретной информации он не со-
держит;
– так проект получается проще и доступнее для повторения.
Естественно, при желании вы можете переписать соответствующие фраг-
менты кода для взаимодействия с базами данных.
146
В папке set находятся:
– index.css — таблица стилей сайта;
– admin.css — таблица стилей страницы просмотра заявок;
– index.js — программа для просмотра на страницах сайта увеличенных фото;
– cont.js — программа проверки данных из формы и передачи на запись;
– del.js — программа передачи команды на удаление заявок;
– title.txt — файл с названием сайта, выводящимся в закладке страницы;
– nav.txt — HTML-код меню;
– news.txt — HTML-код блока новостей;
– cont.py — роль этого файла разъяснится в разделе 5.4.
Итак, часть файлов из архива образуют структуру сайта, а другая часть —
страницу администратора. Сначала выясним, как взаимодействуют файлы, не-
обходимые для работы сайта.
«Скелет» любой страницы — HTML-код с разметкой (рис. 5.2.1). Непосред-
ственно в теле документа прописаны все его элементы, кроме:
– основного содержания;
– названия сайта, которое выводится на вкладке страницы браузера;
– меню;
– блока новостей;
– таблицы стилей;
– сценариев на JavaScript.
Созданием разметки на странице управляет «оболочка», написанная на Py-
thon.
Таблица стилей и сценарий просмотра фото добавляются в HTML-код в
процессе загрузки документа, минуя «посредников». Название, меню, новост-
ной блок и основное содержание вставляется с помощью Python-оболочки из
соответствующих txt-файлов. В Python-коде предусмотрен механизм определе-
ния, какой именно контент должен быть загружен для той или иной страницы.
147
У оболочки есть еще одна функция: проверять, соответствует ли адрес в
строке запроса адресу реально существующей страницы. Если искомая страни-
ца отсутствует, то никаких предупреждений не выводится, а просто загружает-
ся главная страница.
Если загружена страница «Контакты», то к ней подключается файл cont.js.
После отправки формы данные проверяются этим скриптом и отправляются на
запись файлу rec.py. По ее завершении сценарию cont.js возвращается соответ-
ствующий сигнал, который преобразуется в текст подтверждения успешной за-
писи, выводящийся на странице.
Схема взаимодействия файлов страницы заявок показана на рисунке 5.2.2.
Таблица стилей вставляется в HTML-код в процессе загрузки документа.
Текст в тег title и заявки добавляются с помощью Python-оболочки из соответ-
ствующих файлов.
Если администратор запустил процесс удаления заявок, данные отправля-
ются сценарию del.js, а затем программе del.py. Заявки удаляются, сценарий
получает сигнал об этом и выводит на страницу необходимое сообщение.
#! C:/Python/python
148
Следующий шаг — подключение модулей. Нам понадобятся модуль cgi —
для получения параметра с адресом затребованной страницы и os — для запус-
ка функции чтения каталога со страницами:
import cgi
import os
a = 'index'
form = cgi.FieldStorage()
b = form.getfirst('a')
if b:
opdir = os.listdir('content')
i = 0
while i < len(opdir):
if b + '.txt' == opdir[i]:
a = b
break
i += 1
149
if b:
opdir = os.listdir('content')
затем создаем счетчик:
i = 0
if b + ".txt" == opdir[i]:
a = b
break
a = 'index'
def opfi(adr):
fo = open(adr, encoding='utf-8')
150
ti = fo.read()
fo.close()
return ti
fo = open(adr, encoding='utf-8')
считывает его:
ti = fo.read()
закрывает:
fo.close()
return ti
print('Content-type: text/html\n\n')
print('''<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>''' + opfi('set/title.txt') + '''</title>
<link rel="stylesheet" href="set/index.css">
<script src="set/index.js"></script>''')
...
<title>''' + opfi('set/title.txt') + '''</title>
...
<script src="set/index.js"></script>
151
Если запрошена страница «Контакты», то в головную часть документа еще
добавляется JavaScript-файл проверки данных:
if a == 'contact':
print('<script src="set/cont.js"></script>')
print('''</head>
<body>
<div id="bas"></div>
<div id="view">
<img id="pict" src="img/net.jpg" alt="Photo">
</div>
<div id="basis">
<table id="tab">
<tr><td id="menu" colspan="2">
<nav id="sect">''' + opfi('set/nav.txt') + '''</nav>
</td></tr>
<tr><td id="main">
<div id="cont">''' + opfi('content/'+a+'.txt') +
'''</div></td>
<td id="rec">''' + opfi('set/news.txt') +
'''</td></tr>
</table>
</div>
</body>
</html>''')
Блок
<body>
<div id="bas"></div>
<div id="view">
<img id="pict" src="img/net.jpg" alt="Photo">
</div>
<table id="tab">
<tr><td id="menu" colspan="2">
<nav id="sect">
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
| |
| Меню |
|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|
</nav>
</td></tr>
152
<tr><td id="main">
<div id="cont">
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
| |
| Основное содержание |
|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|
</div></td>
<td id="rec">
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
| |
| Новости |
|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|
</td></tr>
</table>
<div id="cont">
...
</div>
'content/'+a+'.txt'
153
5.4. Страница «Контакты»
Эта страница отличается только тем, что в нее загружается не текст с фото-
графиями, а форма для отправки заявок. И еще файл cont.js, о чем мы упомина-
ли в предыдущем разделе.
Наполнение страницы «Контакты» представлено на рисунке 5.4.1. Форма
имеет три поля — «Ваше имя», «Телефон или e-mail» и «Сообщение», а также
кнопку «Отправить». Если какое-то поле оставить незаполненным, то появляет-
ся соответствующее предупреждение. Причем выводится оно креативным спо-
собом — прямо на кнопку «Отправить», заменяя ее изначальный текст
(рис. 5.4.2).
Отправка заявки выполняется с помощью технологии Ajax. То есть в брау-
зере остается та же страница. В это время сценарий из файла cont.js сначала
проверяет данные, а потом отправляет запрос программе rec.py. Там данные
проверяются еще раз, после чего происходит их запись в файл cont.py (объяс-
нения этому факту — в разделе 5.5). На следующем этапе программа rec.py
возвращает файлу cont.js отчет об успешной записи. На последнем шаге сцена-
рий из cont.js выводит на страницу подтверждение о получении заявки (и опять
на кнопку отправки данных — рис. 5.4.3).
154
Рис. 5.4.2. Предупреждение, если заполнены не все поля
155
5.5. Файл rec.py
#! C:/Python/python
import cgi
form = cgi.FieldStorage()
nam = form.getfirst('nam')
con = form.getfirst('con')
tex = form.getfirst('tex')
print('Content-type: text/html\n\n')
print(2)
156
и прерываем выполнение программы:
exit()
157
формация загружается в ту или иную страницу и видна любому посетителю. Но
есть одно исключение — файл для хранения заявок. К нему доступ может быть
только у администратора. Значит, текстовый файл не подойдет, ведь посторон-
ний человек может открыть его в браузере, введя соответствующий путь в
строке адреса (выяснить его не составляет труда). Что же делать? Выход очень
простой — писать заявки в файл с расширением .py. Так как в таком файле не
будет обязательной строки с путем к интерпретатору, при попытке его загру-
зить сервер выдаст сообщение об ошибке. А значит «снаружи» прочитать этот
файл не удастся. Что нам и требуется.
#! C:/Python/python
import cgi
pas = 'admin'
form = cgi.FieldStorage()
b = form.getfirst('pr')
158
Пишем функцию, которая будет нужна для открытия файла с названием
сайта и файла заявок:
def opfi(adr):
fo = open(adr, encoding='utf-8')
ti = fo.read()
fo.close()
return ti
print('Content-type: text/html\n\n')
print('''<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>''' + opfi('set/title.txt') + '''</title>
<link rel="stylesheet" href="set/admin.css">''')
...
<title>''' + opfi('set/title.txt') + '''</title>
...
if b != pas:
print('''</head>
<body>
<p> </p>
<form method="POST" action="admin.py">
<p><input type="password" name="pr" maxlength="20">
</p>''')
if b != pas:
159
ложно, это означает, что пароль введен и он правильный. Тогда мы печатаем
страницу с заявками (рис. 5.6.2):
print('''<script src="set/del.js"></script>
</head>
<body>
<p><textarea id="tex">''' + opfi('set/cont.py') +
'''</textarea></p>
<form name="dat"><input type="hidden" value="''' +
pas + '''" name="hid">
<p><input type="button" value="Удалить" id="but">
</p>''')
...
<textarea id="tex">''' + opfi('set/cont.py') +
'''</textarea>
...
print('''</form>
</body>
</html>''')
160
5.7. Файл del.py
#! C:/Python/python
import cgi
form = cgi.FieldStorage()
hid = form.getfirst('hid')
print('Content-type: text/html\n\n')
Данная строка нужна независимо от того, был ли отправлен верный пароль или
нет. Сейчас вы убедитесь в этом.
Если пароль в запросе отсутствует или он неверный,
print('''<!DOCTYPE html>
<html lang="ru">
<head><meta charset="utf-8">
<title>Некорректный запрос !</title>
<link rel="stylesheet" href="set/admin.css">
</head>
<body>
<p> </p><p>Некорректный запрос !</p>
</body>
</html>''')
161
и прерываем выполнение программы:
exit()
print(1)
Система просмотра заявок устроена так, что при каждом входе нужно вво-
дить пароль. Если вы считаете, что это неудобно, можно предусмотреть какой-
то механизм запоминания администратора после первого входа. Например, ис-
пользовать cookie.
162
Завершая разговор про демонстрационный сайт музыкальной студии, необ-
ходимо подчеркнуть: хотя наш ресурс полностью работоспособен, это всего
лишь наглядная иллюстрация к рассказу о том, как можно использовать Python
в web-программировании. Понятно, что настоящие, полноценные сайты устро-
ены сложнее, имеют более обширный функционал и работают с базами данных,
а не с текстовыми файлами.
165
Рис. 5.8.4. Загружаем файлы проекта в папку вашего сайта
166
Рис. 5.8.5. Выбор пункта «Свойства» из контекстного меню
167
Рис. 5.8.7. Установка прав доступа в панели настроек хостинга
168
Рис. 5.8.8. Страница с перечнем ваших доменов
169
6. Приложения — сценарии на JavaScript
<div id="bas"></div>
<div id="view">
<img id="pict" src="img/net.jpg" alt="Фото">
</div>
<div id="bas"></div>
<div id="view">
...
</div>
170
В исходном состоянии на данный слой загружено изображение net.jpg белого
цвета размером 1х1 пиксель. Сделано это, чтобы угодить требованиям стандар-
тов Консорциума Всемирной паутины, которые не допускают в разметке изоб-
ражений с пустым атрибутом src (ведь в исходном состоянии никакое фото со
страницы в контейнер div id="view" не загружено).
При загрузке увеличенного рисунка белый фон занимает все пространство
окна браузера, а картинка располагается строго по середине (рис. 6.1.1).
Для вставки данного фрагмента кода автор выбрал место сразу после от-
крывающего тега body:
...
<body>
<div id="bas"></div>
<div id="view">
<img id="pict" src="img/net.jpg" alt="Фото">
</div>
<div id="basis">
...
171
<script src="set/index.js"></script>
addEventListener("load", function()
{
...
});
let view=document.getElementById("view");
let bas=document.getElementById("bas").style;
let pict=document.getElementById("pict");
document.getElementById("cont").
addEventListener("click", function(ev)
{
...
});
if(ev.target.tagName=="IMG")
{
...
}
let sc=window.pageYOffset;
pict.src=ev.target.src;
view.style.visibility="visible";
bas.visibility="visible";
view.addEventListener("click", del);
addEventListener("scroll", del);
function del()
{
view.style.visibility="hidden";
bas.visibility="hidden";
pict.src="img/net.jpg";
}
if a == 'contact':
print('<script src="set/cont.js"></script>')
addEventListener("load", function()
{
document.getElementById("but").
addEventListener("click", cont);
});
if(document.getElementById("nam").value.length<2)
{
document.getElementById("but").value=
"ВЫ НЕ ВВЕЛИ ИМЯ !";
return false;
}
document.getElementById("but").value=
"ВЫ НЕ ВВЕЛИ ИМЯ !";
Самые короткие имена состоят из двух букв, например: Ян, Ия. Поэтому в про-
верочном условии
if(document.getElementById("nam").value.length<2)
else
{
if(document.getElementById("con").value.length<8)
{
document.getElementById("but").value=
174
"ВЫ НЕ ВВЕЛИ ТЕЛЕФОН ИЛИ E-MAIL !";
return false;
}
...
}
else
{
if(document.getElementById("tex").value.length<10)
{
document.getElementById("but").value=
"ВЫ НЕ ВВЕЛИ СООБЩЕНИЕ !";
return false;
}
...
}
175
Отправлять заявки мы будем, используя технологию Ajax. Для этого созда-
дим новый объект с данными из формы:
re.send(dt);
re.addEventListener("load", show);
function show()
{
let re=document.getElementById("but");
let ans=this.responseText;
if(ans==1)
re.value="СООБЩЕНИЕ ОТПРАВЛЕНО !";
if(ans==2)
re.value="ЗАПОЛНЕНЫ НЕ ВСЕ ПОЛЯ !";
if(ans==3)
re.value="НЕКОРРЕКТНЫЕ ДАННЫЕ !";
setTimeout(sto, 3000);
}
function sto()
{
document.getElementById("but").value="Отправить";
}
176
6.3. Сценарий запроса на удаление заявок
<script src="set/del.js"></script>
addEventListener("load", function()
{
document.getElementById("but").
addEventListener("click", cont);
});
function cont()
{
let dt=new FormData(document.forms.dat);
let re=new XMLHttpRequest();
re.open("POST", "del.py", true);
re.send(dt);
re.addEventListener("load", show);
}
function show()
{
let ans=this.responseText;
if(ans==1)
document.getElementById("tex").value=
"ЗАЯВКИ УДАЛЕНЫ !";
}
177
7. Заключение
178
Валерий Викторович ЯНЦЕВ
WEBПРОГРАММИРОВАНИЕ НА PYTHON
Учебное пособие
ЛР № 065466 от 21.10.97
Гигиенический сертификат 78.01.10.953.П.1028
от 14.04.2016 г., выдан ЦГСЭН в СПб
Издательство «ЛАНЬ»
[email protected]; www.lanbook.com
196105, СанктПетербург, пр. Юрия Гагарина, д.1, лит. А.
Тел.: (812) 3362509, 4129272.
Бесплатный звонок по России: 88007004071