Знакомство с веб-технологиями

Как работают сайты в интернете?

Кратко: когда вы вбиваете адрес сервера в ваш браузер, браузер соединяется с этим сервером и отправляет ему запрос по протоколы HTTP (https://ru.wikipedia.org/wiki/HTTP). Это текстовый прикладной протокол поверх TCP/IP. В ответ, сервер присылает вашему браузеру HTML код страницы.

HTML - это язык разметки, который используется для оформления страниц в интернете. Например, он позволяет выделять в тексте заголовки, делать шрифт жирным или курсивным, вставлять абзацы и таблицы и многое другое. Идея HTML в помещение текста внутрь тэгов, которые определяют, каким будет этот текст.

Краткое знакомство:

Если HTML код на сервере лежит в виде файла, то такая страница называется статической, а если она генерируется кодом на python или PHP (или любом другом) прямо во время запроса - такая страница называется динамической.

Помимо HTML, на странице могут быть CSS стили и скрипты на JavaScript. CSS стили задают дизайн страницы (например, цвета и отступы), а JS позволяет сделать страницы интерактивными (всплывающие окна, вкладки, фоновое обновление страниц и тд.)

Некоторые определения

Веб-сервер

  • устройство vs. программа
  • задача — получать запросы от других компьютеров или программ (клиентов, clients) и отправлять запрошенные данные
  • основная функция — размещение сайтов (website hosting)

Термины

  • Запрос (request) — сообщение от агента, желающего получить или разместить информацию
  • Ответ (response) — ответное сообщение сервера с кодом состояния и информацией (HTML, изображения, загружаемые файлы и т. п.)
  • Протокол (protocol) — набор правил, по которым составляются запросы и ответы
  • Сессия (session) — установка соединения между агентом и сервером и последующая серия запросов и ответов
  • Гипертекст — множество текстов, организованных в виде графа при помощи гиперссылок
  • Протокол HTTP (HyperText Transfer Protocol) — протокол для передачи гипертекстовых данных (обычно в виде HTML)
  • URL (Uniform Resource Locator), веб-адрес ресурса — строка, представляющая собой уникальное имя, по которому можно найти в сети этот ресурс

Адресация

IP

  • IP-адрес — (пока что) набор из 4 байт, присваиваемый каждому подключённому к сети устройству
  • Некоторые IP-адреса уникальны, некоторые — нет (внутренние адреса в локальных сетях)
  • Практически любой ресурс (например, сайт) можно получить по его IP-адресу (например, через браузер)
  • Существуют зарезервированные адреса и диапазоны адресов, например, 127.0.0.1 — адрес данного устройства

Порт

  • Каждый запрос обращается не просто к какому-то IP-адресу, а к некоторому порту на этом адресе
  • Веб-сервер имеет 65 535 портов, пронумерованных начиная с 1
  • Веб-сервер может прослушивать некоторые порты (listen to ports) и по-разному обрабатывать сообщения, поступившие на разные порты
  • Если порт не прослушивается, сообщения на этот порт останутся без ответа

URL

http://www.example.com:1234/directory1/file1.html

протокол://доменное имя или IP-адрес:порт/адрес файла на сервере

  • Порт указывать не обязательно: используются стандартные порты (HTTP — 80, FTP — 20 и т. п.)
  • DNS (Domain Name Servers) — специальные сервера в сети, на которых хранятся таблицы соответствия между доменными именами и IP-адресами их серверов

HTML и скрипты

  • страницы, содержимое (HTML-код) которых не изменяется, называются статическими (static)
  • страницы, содержимое которых может быть разным в зависимости от введённых пользователем данных, времени, IP-адреса и т. п., называются динамическими (dynamic)
  • динамические страницы создаются с помощью скриптов на стороне сервера (server side scripts), написанных, например, на PHP или Python
  • скрипт порождает HTML и посылает его пользователю
  • пользователь не видит кода скрипта, выполняющегося на сервере
  • скрипт на стороне клиента (client side script) — вставка в HTML на каком-то языке программирования (например, JavaScript), позволяющая странице вести себя интерактивно
  • код клиентских скриптов посылается клиенту сервером вместе с HTML и не выполняется на сервере

Питон и сайты

Написать сайт на питоне значит написать такую программу, которая может работать веб-сервером или использоваться веб-сервером для порождения HTML-кода веб-страниц. Для этого существует несколько модулей, например, Django и Flask

Веб-сервер на чистых сокетах

Для получения HTML кода страниц от сервера в интернете используется протокол HTTP. Это текстовый протокол, в котором после подключения к серверу клиент (браузер) должен отправить запрос с описанием того, что он хочет, а сервер в ответ посылает HTML код.

Давайте попробуем сделать совсем простой веб-сервер, используя только стандартные сокеты.

import socket

host = ''
port = 80
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind((host, port))
sock.listen(1)

while True:
    conn, caddr = sock.accept()
    print ("Connection from: ", caddr)
    req = conn.recv(1024).decode('utf-8')
    print (req)
    conn.sendall("""HTTP/1.0 200 OK
Content-Type: text/html

<html>
<head>
<title>Success</title>
</head>
<body>
Boo!
</body>
</html>
""".encode('utf-8'))
    conn.close()

Попробуйте запустить его и в вашем любимой браузере перейти по адресу http://127.0.0.1. Если все работает правильно вы увидите HTML страницу со словом Boo!.

Код выше печатает в консоли код запроса, который пришел от клиента:

GET / HTTP/1.1
Host: 127.0.0.1:80
Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate, br
Accept-Language: ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7

Как видите, это текстовое сообщения, в котором в первой строке указано, что посылается HTTP запрос GET / HTTP/1.1, а далее указываются некоторые его параметры.

В ответе мы посылаем клиенту строки HTTP/1.0 200 OK и Content-Type: text/html, в которых указано, что страница найдена и ответ - это HTML код, а дальше (спустя одну пустую строку) отдаем ответ в виде HTML кода.

Flask - небольшой фреймворк для разработки веб-сервисов

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

Чтобы упростить эту задачу, программисты часто используются фрейворки - это библиотеки, которые упрощают разработку кода и задают некоторый удобный шаблон, как должна выглядеть программа. Например, для разработки веб-сервисов на питоне удобно использовать Flask - https://flask.palletsprojects.com/en/3.0.x/.

pip install flask

Например, код сервера, который мы писали выше на сокетах, на Flask будет выглядеть так:

from flask import Flask

app = Flask(__name__)

@app.route('/')
def index():
    return '<html><body>Boo!</body></html>'

app.run(debug=True, port=8080)

Чтобы увидеть результат, нужно в браузере зайти на адрес http://127.0.0.1:8080.

PS: Я выбрал порт 8080, тк для выбора порта 80 программу нужно запускать от имени администратора (sudo python3 my_server.py).

Подобно коду телеграм ботов, код на flask состоит из функций, каждая из которых отвечает на конкретный запрос пользователя. В декораторе @app.route('/') указывается путь к странице, которую запросил пользователь, а вернуть функция должна html код, который нужно отправить пользователю.

Напримен, если помимо главной страницы (http://127.0.0.1:8080/) нам понадобися страница http://127.0.0.1:8080/about, код будет выглядеть следующим образом:

from flask import Flask

app = Flask(__name__)

@app.route('/')
def index():
    return '<html><body>Boo!</body></html>'

@app.route('/about')
def about():
    return """
<html>
    <body>
        Это страница о сервисе!
    </body>
</html>
"""

app.run(debug=True, port=8080)

PS1: В режиме отладки (debug=True) переапускать программу после каждого изменения не трбуется.

PS2: Выше использован многострочный текст, в питоне для его обозначения вместо одинарных используются тройные кавычки.

Синтаксис HTML

Для описания внешнего вида страницы ипользуются HTML теги. Почти всегда теги идут в паре - открывающий и закрывающий (такая пара называется HTML элемент). Если открывающий тег <p>, то закрывающий будет </p>. Элементы можно вкладывать друг в друга или располагать рядом. В этом случае внешний элемент называется родителем (parent), а вложенный ребенком (child).

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

В любом HTML документе должны присутствовать теги <html>, <head> и <body>.

В онлайн редакторах <html> и <head> писать не нужно.

<html>
    <head>
        ...
    </head>
    <body>
        ...
    </body>
</html>

Рассмотрим приведенный выше пример HTML файла:

  • <html> является главным тегом, внутри него находятся абсолютно все элементы на странице
  • внутри <head> располагается вспомогательная информация для браузера (например, заголовок страницы)
  • внутри <body> располагаются все блоки, которые будут видны на странице (например, текст)

Чтобы создать свою страницу сохраните файл с расширением .html и откройте его в браузере. Для этого нажмите на файл правой кнопкой мыши и выберите Открыть с помощью...

Теги HTML можно писать в любом регистре. Здесь и далее будет использоваться строчный вариант.

Для улучшения читаемости принято добавлять дополнительный отступ вложенным элементам.

Основные теги

Рассмотрим основные теги, с помощью которых совсем скоро вы сможете написать свой первый сайт.

Текст, заголовки, ссылки

До сих пор главным способом представления информации в интернете является текст, поэтому рассмотрим теги для создания заголовков, абзацев, ссылок и их позиционирования.

Тег Описание
<p> </p> Абзац (от слова paragraph)
<b> </b> Текст жирно выделенный (от слова bold)
<s> </s> Зачеркнутый текст (от слова strikethrough)
<i> </i> Текст выделенный курсивом (от слова italic)
<h1> </h1> Заголовок (существуют 6 типов заголовков: <h1> самый большой, <h6> самый маленький)
<br> Перевод строки (не требует закрывающего тега)
<hr> Горизонтальная черта (не требует закрывающего тега)
<a href="..."> </a> Ссылка, ведущая по адресу, указанному в кавычках

Как говорилось ранее, теги можно вкладывать друг в друга, тем самым комбинируя эффекты, например, сделать абзац с жирной курсивной ссылкой.

<p>
    <b><i><a href="http://ya.ru">Яндекс</a></i></b>
</p>

Атрибуты

Некоторые элементы обладают атрибутами - специальными свойствами, указываемыми в открывающем теге.

<a href="http://ya.ru" title="Перейти на Яндекс">Яндекс</a>

Атрибуты перечисляются через пробел, а их значения (в двойных кавычках) присваиваются через знак равно.

Картинки

Как бы не был хорошо написан текст, без картинок обойтись трудно. Для вставки изображений используется тег <img> (сокращение от image). Закрывающий тег не требуется. Основными атрибутами для картинки являются:

  • src задает путь к картинке (сокращение от source)
  • width задает ширину в пикселях (или процентах, если приписать знак процента)
  • height задает высоту аналогично ширине
  • alt задает текст, отображаемый на месте картинки в случае невозможности загрузить картинку
<img src="http://mysite.com/img/example.jpg" height="640" width="480">

Если поместить картинку в тег <a>, то при нажатии на нее будет происходить переход, как по ссылке.

Списки

Для структурирования информации удобно использовать списки. Существуют нумерованный (упорядоченный) список <ol> (сокращение от ordered list) и неупорядоченный список <ul> (сокращение от unordered list). Каждый пункт списка помещается в тег <li> (сокращение от list item).

<ol>
    <li>Пункт под номером 1</li>
    <li>Пункт под номером 2</li>
    <li>Пункт под номером 3</li>
    <li>Пункт под номером 4</li>
</ol>

<ul>
    <li>Просто пункт</li>
    <li>Просто пункт</li>
    <li>Просто пункт</li>
    <li>Просто пункт</li>
</ul>

Как и другие элементы, списки можно вкладывать друг в друга, тем самым создавая подпункты пункта.

Таблицы

Еще эффективнее для структурирования информации можно использовать таблицы. Каждая таблица состоит тега таблицы <table>, строк таблицы <tr> (сокращение от table row), ячеек таблицы <td> (сокращение от table data) или ячеек-заголовков <th> (сокращение от table header). Строки вложены в таблицу, а ячейки вложены в строки.

<table border="1" cellspacing="0">
    <tr>
        <th>Столбец 1</th>
        <th>Столбец 2</th>
        <th>Столбец 3</th>
    </tr>
    <tr>
        <td>1-1</td>
        <td>1-2</td>
        <td>1-3</td>
    </tr>
    <tr>
        <td>2-1</td>
        <td>2-2</td>
        <td>2-3</td>
    </tr>
    <tr>
        <td>3-1</td>
        <td>3-2</td>
        <td>3-3</td>
    </tr>
</table>

В этом примере атрибут border задает толщину границы между ячейками (по-умолчанию ее нет), а атрибут cellspacing задает расстояние между ячейками (значение 0 заставялет слипнуться границы ячеек, тем самым избавиться от двойных границ).

Для растягивания ячейки <td> направо используется атрибут colspan, а для растягивания вниз rowspan.

<table border="1" cellspacing="0">
    <tr>
        <th>Столбец 1</th>
        <th>Столбец 2</th>
        <th>Столбец 3</th>
    </tr>
    <tr>
        <td>1-1</td>
        <td>1-2</td>
        <td rowspan="2">1-3 && 2-3</td>
    </tr>
    <tr>
        <td colspan="2">2-1 && 2-2</td>
    </tr>
    <tr>
        <td colspan="3">3-1 && 3-2 && 3-3</td>
    </tr>
</table>

Тег <head>

Внутри тега head помещают некоторые технические теги. Например, теги с информацией о языке странице, ее кодировке, теги, в которых мы загружаем стили.

На данный момент нам интересны только два тега.

  • <title>Title</title> задает заголовок страницы, отображаемый в названии вкладки
  • <meta charset="utf-8"> сообщает браузеру, что HTML файл имеет кодировку utf-8. Таким образом сохранив файл в такой же кодировке (современные редакторы используют ее по умолчанию) удастся избежать "крокозябр".

Статические файлы и Flask

Если вам нужно разместить на вашем сайте обычный файл, например, картинку, то вам нужно содать папку static в папке с вашим проекто и разместить его там.

Например, если мы положим картинку image.jpg в папку static рядом с my-server.py, то вставить ее можно так:

<img src="/static/image.jpg" />