При каждой публикации заново формируйте карту сайта по готовому набору публичных страниц, а затем загружайте оба результата вместе. В этом процессе для Mac небольшой скрипт на Python автоматически добавляет новые страницы и удаляет исчезнувшие, а также позволяет проверить результат на сайте.
Задача здесь — поддерживать карту сайта для небольшого статического сайта, экспортированного с Mac. В примере используются вымышленные страницы о цветах. Предполагается, что существующий процесс публикации умеет загружать папку экспорта и удалять устаревшие файлы с публичного сайта.
Выберите, где формировать карту сайта
Сначала проверьте, формирует ли ваша система публикации карту сайта автоматически. Google отмечает, что многие системы управления контентом предоставляют такую возможность. Если ваша система это умеет, проверьте карту сайта после добавления и удаления тестовой страницы, прежде чем подключать ещё один генератор. Подробнее о картах сайта.
Для статического экспорта используйте такую последовательность: завершите экспорт страниц, сформируйте карту сайта по экспортированным данным и опубликуйте получившуюся папку. Это предлагаемый шаблон реализации: благодаря ему карта сайта описывает тот же набор страниц, который получает система публикации.
Формирование карты во время публикации задаёт единое правило для добавления и удаления страниц. Страница, присутствующая в готовом экспорте, включается; отсутствующая — исключается. Не нужно помнить об обновлении отдельного списка.
Выберите способ интеграции, соответствующий вашей системе:
| Существующая система публикации | Где формировать карту сайта |
|---|---|
| CMS уже поддерживает карту сайта | Оставьте этот генератор и проверьте, как он реагирует на изменения страниц |
| Статический экспортёр поддерживает команду после экспорта | Запускайте генератор после экспорта, до загрузки файлов |
| Существующая команда публикует готовую папку | Запускайте её через необязательный аргумент генератора для публикации |
| Вы загружаете файлы через настольное приложение | Сначала сформируйте карту, затем загрузите всю папку; автоматическое обновление сайта без участия пользователя требует поддерживаемой интеграции с системой публикации |
Локальный скрипт сам по себе не может изменить удалённый сайт. Описанный ниже процесс автоматизирует формирование карты сайта и может запускать существующую команду публикации. Фактическую загрузку выполняет ваша настроенная система публикации.
Точно определите, какие страницы включать в карту сайта
Для обычных URL страниц Google принимает текстовую карту сайта, в которой на каждой строке указан полный URL. Для этой задачи XML не обязателен. Указывайте предпочтительный публичный URL каждой страницы, а не несколько вариантов URL одного и того же содержимого. Создание и отправка карты сайта.
Текстовый формат требует кодировки UTF-8 и содержит только URL — без заголовков и комментариев. Один файл может содержать не более 50 000 URL и занимать не более 52 428 800 байт. Разместите карту сайта из этого примера в корне сайта, чтобы она охватывала экспортированные страницы, расположенные ниже. Протокол Sitemaps: текстовые файлы и расположение.
Генератор использует намеренно простое соглашение об экспорте:
| Экспортированный файл | Пример публичного URL |
|---|---|
public/index.html |
https://example.com/ |
public/colors/blue.html |
https://example.com/colors/blue.html |
public/tiles/index.html |
https://example.com/tiles/ |
Используйте это соглашение, только если ваш хост обслуживает именно такие URL. Если система публикации преобразует blue.html в /colors/blue/ или размещает сайт по пути, например /collection/, перед публикацией используйте список маршрутов системы или измените сопоставление. По одним именам файлов определить пользовательские маршруты невозможно.
Оставляйте в папке экспорта только страницы, которые следует включить в публикацию. В этом примере пропускаются пути, начинающиеся с точки, и файлы с именем 404.html; метаданные страниц, канонические URL и правила перенаправления не проверяются. Если на вашем сайте есть такие условия, формируйте карту по списку подходящих страниц из системы публикации.
Также продолжайте поддерживать обычные навигационные ссылки. В стандарте WHATWG гиперссылки определяются элементами a с атрибутом href, а Google поясняет, что страницы с корректными ссылками обычно можно обнаружить через навигацию. При обновлении карты сайта обновляйте и ссылки, ведущие на добавленные или удалённые страницы. Стандарт WHATWG HTML: ссылки, Подробнее о картах сайта.
Создайте генератор на Mac
Вам понадобятся Python версии 3.8 или новее и обычный текстовый редактор. В Терминале выполните python3 --version, чтобы проверить доступную версию интерпретатора. Если Python ещё не установлен, воспользуйтесь инструкциями Python Software Foundation по установке для macOS. В документации также описан запуск скриптов командой python3 из Терминала. Использование Python в macOS.
Создайте на рабочем столе папку sitemap-demo. Сохраните в ней приведённую ниже программу целиком под именем regenerate_sitemap.py. Программа использует стандартную библиотеку Python и не требует установки дополнительных пакетов.
import argparse
from pathlib import Path, PurePosixPath
import subprocess
import tempfile
from urllib.parse import quote, urlsplit
def make_sitemap(paths, origin):
parsed = urlsplit(origin)
if (parsed.scheme not in ("http", "https") or not parsed.hostname
or parsed.netloc != parsed.hostname
or parsed.path not in ("", "/")
or parsed.query or parsed.fragment):
raise ValueError("Use a site origin, such as https://example.com")
base = origin.rstrip("/")
urls = set()
for relative in paths:
path = PurePosixPath(relative)
if path.name == "index.html":
parent = path.parent.as_posix()
route = "" if parent == "." else parent + "/"
else:
route = path.as_posix()
urls.add(base + "/" + quote(route, safe="/"))
if not urls:
raise ValueError("No eligible pages; sitemap was not replaced")
if len(urls) > 50000:
raise ValueError("Split the sitemap: more than 50,000 URLs")
data = ("\n".join(sorted(urls)) + "\n").encode("utf-8")
if len(data) > 50 * 1024 * 1024:
raise ValueError("Split the sitemap: larger than 50 MB")
return data
def main():
parser = argparse.ArgumentParser()
parser.add_argument("folder")
parser.add_argument("origin")
parser.add_argument("publish", nargs=argparse.REMAINDER)
args = parser.parse_args()
root = Path(args.folder).resolve()
if not root.is_dir():
parser.error("The export folder must already exist")
paths = []
for file in root.rglob("*.html"):
relative = file.relative_to(root)
if (file.is_file() and file.name != "404.html"
and not any(p.startswith(".") for p in relative.parts)):
paths.append(relative.as_posix())
data = make_sitemap(paths, args.origin)
target = root / "sitemap.txt"
temporary = None
try:
with tempfile.NamedTemporaryFile(dir=root, delete=False) as handle:
temporary = Path(handle.name)
handle.write(data)
temporary.replace(target)
finally:
if temporary is not None:
temporary.unlink(missing_ok=True)
print(f"Wrote {len(data.splitlines())} URLs to {target}", flush=True)
if args.publish:
subprocess.run(args.publish, check=True)
if __name__ == "__main__":
main()
При каждом запуске весь список URL формируется заново. Результат сортируется и очищается от повторов, специальные символы в путях, например пробелы, кодируются, а перед заменой sitemap.txt данные записываются во временный файл. Если при формировании карты возникает ошибка, программа останавливается и не запускает необязательную команду публикации.
Если экспорт пуст, программа намеренно выдаёт ошибку и оставляет прежнюю карту сайта без изменений. Это помогает обнаружить случайно выбранную или неполную папку. Намеренное удаление всех страниц требует отдельного решения о публикации; передавать пустой экспорт в этот процесс не следует.
Проверьте добавление и удаление страницы до подключения публикации
В Терминале перейдите в папку с примером:
cd "$HOME/Desktop/sitemap-demo"
Создайте две вымышленные страницы полной командой настройки ниже. Выполните её в новой папке для примера; она создаст два указанных файла.
python3 - <<'PY'
from pathlib import Path
root = Path("public")
(root / "colors").mkdir(parents=True, exist_ok=True)
pages = {
"index.html": "<!doctype html><title>Color collection</title><p>Color collection.</p>",
"colors/blue.html": "<!doctype html><title>Blue tile</title><p>A blue tile.</p>",
}
for name, content in pages.items():
(root / name).write_text(content, encoding="utf-8")
PY
Сформируйте и проверьте локальную карту сайта. Указанный источник — пример; эти команды ничего на нём не публикуют.
python3 regenerate_sitemap.py public https://example.com
cat public/sitemap.txt
Ожидается, что в файле будут ровно две строки:
https://example.com/
https://example.com/colors/blue.html
Теперь замените вымышленную страницу синего цвета страницей зелёного цвета:
python3 - <<'PY'
from pathlib import Path
root = Path("public")
(root / "colors/blue.html").unlink()
(root / "colors/green.html").write_text(
"<!doctype html><title>Green tile</title><p>A green tile.</p>",
encoding="utf-8",
)
PY
python3 regenerate_sitemap.py public https://example.com
cat public/sitemap.txt
Ожидаемый результат — URL главной страницы, а за ним https://example.com/colors/green.html. URL синей страницы исчезнет, поскольку её экспортированного файла больше нет. Так вы проверите оба вида изменений, не дожидаясь, пока поисковая система заметит их.
Добавьте формирование карты в каждую публикацию
Для реального сайта замените папку и источник из примера на фактическую папку готового экспорта и публичный адрес сайта. Запускайте генератор только после завершения экспорта и не изменяйте папку, пока публикация не закончится. Публикуйте релизы последовательно.
Если в папке проекта уже есть рабочий скрипт публикации с именем deploy-site.sh, следующая команда интеграции сформирует карту сайта, а затем запустит этот скрипт. В примере предполагается, что скрипт уже существует; генератор его не создаёт и не предоставляет настройки хостинга.
python3 regenerate_sitemap.py public https://example.com sh ./deploy-site.sh
Скрипт публикации должен загрузить ту же папку public, включая sitemap.txt, и удалить общедоступные файлы, исчезнувшие из экспорта. После формирования карты сайта он не должен повторно собирать страницы. Если ваша система публикации также собирает сайт, размещайте формирование карты между этапами сборки и загрузки.
Если формирование карты завершится ошибкой, команда публикации не запустится. Если ошибка возникнет при публикации, Python сообщит о ней, но удалённый сайт уже может быть изменён частично. Перед повторной попыткой проверьте результат на сайте. Если хост поддерживает одновременную публикацию целого релиза, используйте документированный способ.
При загрузке через настольное приложение сначала сформируйте карту сайта, затем выберите папку экспорта для загрузки. Проверьте, что приложение заменяет существующую карту сайта и обрабатывает удалённые страницы. Для этого всё равно нужно вручную запустить загрузку: одна лишь автоматическая генерация на локальном компьютере не обеспечивает публикацию без участия пользователя.
Проверьте публичную карту сайта и удалённую страницу отдельно
После успешной публикации откройте в браузере фактический публичный URL sitemap.txt. Проверьте, что добавленная страница присутствует, а удалённая отсутствует. Затем откройте напрямую каждую затронутую страницу. Так можно убедиться, что корректны и локальный экспорт, и опубликованный сайт.
Удаление записи из карты сайта не определяет HTTP-ответ по старому адресу страницы. Если у удалённой страницы нет замены, проверьте, что хост возвращает подходящий ответ о том, что страница не найдена. В RFC 9110 код 404 определяется для ресурса, у которого нет актуального представления, а код 410 — для случая, когда известно, что отсутствие ресурса, вероятно, носит постоянный характер. RFC 9110: семантика HTTP.
Страница, на которой отображается сообщение об отсутствии, но возвращается код 200, может считаться ложной ошибкой 404. Google также документирует, что ранее проиндексированные URL, возвращающие соответствующие ответы 4xx, со временем удаляются из индекса. Поэтому удаление URL из карты сайта — только часть процесса удаления страницы. Как коды состояния HTTP влияют на роботов Google.
Если что-то выглядит неправильно, выполните эту последовательность проверок:
| Наблюдение | Что проверить дальше |
|---|---|
| В локальной карте сайта по-прежнему указана удалённая страница | Найдите оставшийся файл экспорта или проверьте, выбрана ли правильная папка экспорта |
| Локальная карта верна, но публичная копия отличается | Проверьте загруженную папку, место назначения и кэширование |
| Публичная карта верна, но удалённая страница всё ещё открывается | Проверьте, удалила ли публикация старый файл на сервере |
| Сгенерированный URL открывает не ту страницу | Сопоставьте маршруты хоста с соглашением об именах файлов |
| Новый URL доступен, но отсутствует в поиске | Считайте обнаружение и индексирование отдельным процессом |
Причиной того, что публичная карта сайта выглядит неизменной, может быть кэширование. В RFC 9111 описано, как кэшированные ответы остаются актуальными и проходят повторную проверку. Если хост позволяет настраивать заголовки ответа, Cache-Control: no-cache требует успешной проверки перед повторным использованием сохранённого ответа; изменение локального файла само по себе не настраивает этот заголовок. RFC 9111: кэширование HTTP.
Сохраняйте один постоянный адрес карты сайта
Сделайте публичную карту сайта доступной для обнаружения: отправьте её постоянный URL через отчёт Sitemaps в Search Console или укажите его в существующем файле robots.txt сайта. Google описывает оба способа и отмечает, что отправка является лишь подсказкой. Создание и отправка карты сайта.
Для сайта из примера строка для обнаружения будет выглядеть так:
Sitemap: https://example.com/sitemap.txt
Сохраняйте адрес карты сайта постоянным, заменяя её содержимое при публикации. Практическая проверка завершённости: публичная карта соответствует готовому экспорту, добавленная страница открывается по указанному в ней адресу, а удалённая страница возвращает предусмотренный ответ. Поисковые системы обрабатывают эти изменения по собственному расписанию; наличие страницы в карте сайта не гарантирует её сканирование или индексирование. Подробнее о картах сайта.
Источники
- Создание и отправка карты сайта — Google Search Central.
- Подробнее о картах сайта — Google Search Central.
- Формат XML Sitemap — Sitemaps.org.
- Стандарт HTML: ссылки — WHATWG.
- Использование Python в macOS — Python Software Foundation.
- RFC 9110: семантика HTTP — RFC Editor / IETF.
- RFC 9111: кэширование HTTP — RFC Editor / IETF.
- Как коды состояния HTTP влияют на роботов Google — инфраструктура сканирования Google.