Цели проекта
Задача была не «написать много текстов», а проверить гипотезу: можно ли масштабировать органику через programmatic SEO в travel — и при этом не сломать индексацию и конверсию.
- Протестировать массовую генерацию контента. Проверить, как автоматизированное создание продуктовых страниц влияет на трафик и индексацию.
- Закрепить лидерство в органике. Усилить позиции по ключевым запросам, чтобы конкуренты остались за бортом.
- Оптимизировать конверсию. Превратить видимость в заявки.
- Снизить зависимость от платного трафика. Перенести фокус с контекста на долгосрочный SEO-эффект.
Сбор ядра: как мы нашли максимум трафика
Проанализировали всю выдачу тревел-рынка UK/EU. Посмотрели не только частотные запросы, но и редкие, локальные, сезонные. Разобрали, как пользователи ищут билеты, отели и туры.
Вскрыли конкурентов: Kayak, Skyscanner, Booking, Google Flights. Изучили, какие сценарии поиска у них работают, и добавили свои гипотезы. Собрали полную карту намерений.
Учли не только запросы вроде «Как дешевле?», но и те, которые никто не закрывает — «Когда лучше ехать?», «Что посмотреть?», «Как сэкономить?». Сайт перехватывает трафик на всех этапах принятия решения.
Пример группировки
Фрагмент семантической карты: запрос → тип намерения → контекст → пример → объём.
| Query | Intent Type | Context | Example Query | Volume |
|---|---|---|---|---|
| Рим — Барселона билеты | Transactional | Пользователь ищет конкретные билеты | Купить билет Рим Барселона | 50 000 |
| Дешевые билеты в Милан | Informational / Transactional | Пользователь ищет выгодную цену на билеты | Дешевые билеты Милан июнь | 40 000 |
| Лучшие пляжи в 50 км от Барселоны | Informational | Пользователь ищет отдых рядом с городом | Лучшие пляжи Барселона 2025 | 25 000 |
| Лучшее время для поездки в Париж | Informational | Пользователь планирует путешествие | Когда лучше лететь в Париж | 30 000 |
| Горящие туры в Лондон | Transactional | Пользователь ищет туры с выгодными ценами | Горящие туры Лондон март 2025 | 35 000 |
| Топ-10 мест в Париже за 3 дня | Informational | Пользователь планирует короткое путешествие | Что посмотреть в Париже за 3 дня | 45 000 |
| Как добраться из аэропорта в центр Милана | Informational | Пользователь ищет логистическую информацию | Как доехать из аэропорта Милана до центра | 20 000 |
| Отели 5 звезд в Дубае с бассейном | Transactional | Пользователь выбирает отель по характеристикам | Лучшие 5-звездочные отели Дубай с бассейном | 15 000 |
| Рейтинг отелей в Шарм-эль-Шейхе | Informational | Пользователь сравнивает варианты проживания | Лучшие отели Шарм-эль-Шейх отзывы | 10 000 |
| Туры на Мальдивы с питанием all-inclusive | Transactional | Пользователь ищет пакетные туры | Лучшие туры на Мальдивы all inclusive | 22 000 |
| Где поесть в Риме недорого | Informational | Пользователь ищет недорогие заведения | Лучшие недорогие рестораны Рим | 12 000 |
| Куда поехать на уикенд в Европе | Informational | Пользователь ищет идеи для короткого отдыха | Лучшие города для уикенда в Европе | 18 000 |
| Сколько стоит аренда авто в Барселоне | Transactional | Пользователь оценивает стоимость аренды авто | Прокат авто Барселона цена 2025 | 8 000 |
| Какие документы нужны для поездки в США | Informational | Пользователь уточняет визовые требования | Документы для поездки в США 2025 | 9 000 |
| Какой чемодан можно взять в ручную кладь Ryanair | Informational | Пользователь уточняет правила перевозки багажа | Ручная кладь Ryanair размер и вес | 7 500 |
Как мы создали 1 000 000 страниц в Excel через ChatGPT и выгрузили их в CMS
Собрали таблицу с 25 колонками для гибкой генерации контента. Каждая строка — готовая страница: URL, мета-теги, текст, данные о маршруте, FAQ, разметка и приоритет индексации. Тексты генерировали через GPT API, данные о ценах и отелях — из API авиакомпаний и Booking.
- URL
- Ссылка на страницу
- H1
- Заголовок первого уровня (динамически генерируется)
- Title
- SEO-заголовок до 60 символов
- Meta Description
- Мета-описание до 160 символов
- Body
- Основной текст страницы (GPT API)
- Departure City
- Город отправления
- Arrival City
- Город прибытия
- Country
- Страна назначения
- Region
- Регион / область в стране
- Best Travel Time
- Оптимальный период для поездки
- Price Range
- Диапазон цен на билеты (API авиакомпаний)
- Airlines
- Список авиакомпаний на маршруте
- Hotel Offers
- Цены на отели (Booking API)
- Attractions
- Топовые достопримечательности (LSI-фразы)
- FAQ
- Частые вопросы из People Also Ask
- Internal Links
- Связанные внутренние ссылки (автогенерация)
- Schema.org
- Product + AggregateRating
- Images
- Изображения с автоматическими именами файлов
- Reviews
- Количество отзывов (Trustpilot / Google Reviews)
- CTA
- Призыв к действию: «Купить билет», «Забронировать отель»
- Load Speed
- Скорость загрузки (Lighthouse)
- Indexing Priority
- Приоритет индексации: High, Medium, Low
- Canonical
- Канонический URL (динамическое заполнение)
- Structured Data Type
- Product, FAQ, BreadcrumbList
- Cache Control
- Политика кеширования: max-age=3600, no-cache
Масштаб упирается не в «нагенерить и забыть», а в шаблон с уникальными переменными, canonical на каждую страницу и приоритетная индексация. Так миллион URL не превращается в миллион дублей.
Генерация контента
Контент генерировали через OpenAI API. Для каждого элемента — отдельный промпт: H1, meta description, body, FAQ. Так проще контролировать длину, тон и уникальность, чем одним большим запросом на всю страницу.
import openai
import pandas as pd
def generate_text(prompt):
response = openai.ChatCompletion.create(
model="gpt-4",
messages=[{"role": "user", "content": prompt}],
temperature=0.7
)
return response["choices"][0]["message"]["content"]
df = pd.read_csv("pages.csv")
df["H1"] = df.apply(
lambda row: generate_text(
f"Создай H1 для билетов {row['Departure City']} – {row['Arrival City']}"
), axis=1
)
df["Meta Description"] = df.apply(
lambda row: generate_text(
f"Напиши meta description для страницы авиабилетов "
f"{row['Departure City']} – {row['Arrival City']}"
), axis=1
)
df.to_csv("updated_pages.csv", index=False)
Выгрузка в JSON для загрузки в CMS
После генерации — экспорт в JSON-массив: каждая запись = одна страница, готовая к импорту в CMS.
import pandas as pd
df = pd.read_csv("updated_pages.csv")
df.to_json("pages.json", orient="records", force_ascii=False)
Как мы автоматизировали индексацию через Indexing API
Сканировали новые URL из базы и отправляли в Google Indexing API пачками — не ждали, пока бот сам доберётся до миллиона страниц.
import json
import requests
with open("new_urls.json", "r") as f:
urls = json.load(f)
API_URL = "https://indexing.googleapis.com/v3/urlNotifications:publish"
HEADERS = {
"Content-Type": "application/json",
"Authorization": "Bearer TOKEN"
}
def index_url(url):
data = {"url": url, "type": "URL_UPDATED"}
response = requests.post(API_URL, headers=HEADERS, json=data)
return response.json()
for i in range(0, len(urls), 100):
batch = urls[i:i+100]
for url in batch:
result = index_url(url)
print(result)
Оптимизировали частоту запросов, чтобы Google не посчитал нас ботами:
- Между запросами — пауза random.uniform(1, 3) секунды.
- Индексацию прокидывали не всех страниц сразу, а с задержкой 3–4 дня — для естественного роста.
Верстаем продуктовую страницу: удобной и продающей
Главное — быстро дать всю нужную информацию. Вверху маршрут, даты и количество путешественников, которые можно менять. Заголовок, адрес, рейтинг — сразу видно, стоит ли бронировать. Фото крупные, листаются в один клик.
Рейтинг детализирован по категориям — локация, сервис, чистота, завтрак, номер. Удобства иконками, чек-ин и локация перед глазами. Кнопка «Забронировать» всегда на виду.
Авиабилеты и параметры поездки
После отеля логично показать, как до него добраться. Мы добавили авиабилеты в том же стиле, чтобы не выбивались из структуры страницы.
Рядом с заголовком — уточнение, что перелёт включён, чтобы снять лишние вопросы. Показываем конкретные рейсы: время вылета, длительность, авиакомпания. Если не подходят — можно сразу изменить.
Дальше — блок с параметрами поездки: маршрут, даты, пассажиры. Кнопка «Изменить» даёт возможность быстро поменять параметры, не выходя со страницы.
Перелинковка
Добавили перелинковку. Сначала — билеты. Человек уже выбрал отель, теперь важно, как он туда попадёт. Показываем рейсы, даём возможность поменять даты.
Дальше — достопримечательности. Если пользователь не уверен, что делать в городе, ведём его в раздел с экскурсиями.
Если отель не подошёл — показываем альтернативы. Не через блок «похожие варианты», а через аргумент: «Не понравился рейтинг? Вот другие 5-звёздочные отели».
Ссылки встроили органично, по логике пользователя. Это увеличивает глубину просмотров и снижает вероятность выхода. Google видит, что страницы связаны, передаёт им вес, поднимает в поиске.
Как мы сделали выбор номера полезным для SEO
Обычно страницы отелей устроены так: загружаются скриптом, фильтры работают на фронте, Google ничего не индексирует.
Каждый номер — отдельный блок с H2, уникальными характеристиками и ценой. Заголовки не шаблонные («Double Room»), а с уточнением: «Double 1 or 2 beds deluxe sea view». Это сразу закрывает поисковые запросы вида «Отель + вид из окна».
Разметка Schema.org/Product. В неё передаём:
- цены и доступность, чтобы Google понимал, что данные актуальны;
- условия отмены, которые важны для пользователей и увеличивают CTR;
- варианты питания, чтобы поисковик считал их разными предложениями, а не дублями.
Динамическая кнопка «Показать другие номера» открывает список через серверный рендеринг. Google видит все номера и индексирует их как отдельные ссылки, а не скрытые фильтры.
Итог: каждый вариант номера — точка входа в поиске. Страницы не конкурируют друг с другом, а расширяют охват. Больше контента → выше шанс занять выдачу.
Выбор маршрута
Пользователь может менять города, даты и добавлять направления — всё в одном окне.
Но главное — SEO. Каждый новый маршрут генерирует индексируемый URL, а не скрытый параметр.
Если меняют «Амстердам → любой город», сайт создаёт /flights-from-amsterdam/, что перехватывает низкочастотный трафик.
Кнопка «Добавить направление» усиливает внутреннюю перелинковку. Google видит связанные маршруты, пользователи — больше вариантов.
Популярные маршруты: SEO и перелинковка
Каждый маршрут — отдельная индексируемая страница. Вместо параметров в URL генерируем /flights/milano-londra/, чтобы Google видел их как полноценные посадочные.
Список обновляется автоматически: алгоритм учитывает частотность запросов, бронирования и клики пользователей. Популярные направления поднимаются выше, слабые уходят вниз.
Система раз в сутки пересчитывает рейтинг маршрутов на основе:
- Частотности запросов — API Serpstat, Google Trends, самописное решение коллег по куки;
- Бронирований — история продаж;
- Кликов пользователей — самописное решение коллег.
Формула ранжирования:
Score = (SearchVolume × 0.5) + (Bookings × 0.3) + (Clicks × 0.2)
df = df.sort_values(by="score", ascending=False)
df.to_csv("popular_routes.csv", index=False)
Ссылки формируются в формате /flights/milano-londra/, а изображения подставляются автоматически.
Маршруты всегда актуальны, Google их индексирует, пользователи видят только востребованные направления.
Результат
Запустили 1 000 000 страниц, развернули полную SEO-структуру.
Трафик: 7,74 млн кликов, 570 млн показов за 16 месяцев. Средняя позиция 9.9, CTR 1.4%.
Изображения дали дополнительный охват: 67,4K кликов, 15,5M показов. График показывает рост после добавления уникальных фото.
Индексация: 245K страниц в Google из 1,1 млн. Остальные подтягиваем через Sitemap, внутренние ссылки и загрузку контента.
Миллион URL — не разовая генерация, а работающая SEO-машина: индексация, перелинковка и контент продолжают наращивать органику.