Маркетинг Dennis Loganov
5 103

Поисковая оптимизация сайтов, использующих SPA-приложения

Директор SEO-отдела агентства «Двигус» Денис Логанов и руководитель группы разработки проектов «Ситилинк» Константин Осипов — об инструментах, которые помогут индексировать в поисковых системах AJAX-сайты.

В закладки

При создании новых высоконагруженных веб-сервисов и сайтов разработчики стремятся использовать современные технологии. В силу этого всё большую популярность набирают различные JavaScript-фреймворки и библиотеки (Angular, React, Vue, Inferno и прочие), которые, безусловно, помогают создавать SPA (Single Page Application) приложения с лучшим на сегодня опытом взаимодействия, позволяют разрабатывать легко масштабируемые, удобные в поддержке веб-приложения.

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

Поисковые боты были изначально разработаны для обхода статичных HTML-страниц и не умели интерпретировать JavaScript-код. Это означает, что части страницы, загруженные через AJAX, оставались невидимы для поисковых роботов, так как передача данных осуществляется после загрузки станицы. AngularJS и вовсе полностью охватывает асинхронную модель, и именно это создаёт проблемы для поисковых ботов.

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

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

Как обстоят дела сейчас на рынке

Google

  • В 2009 году Google предложила решение с «_escaped_fragment_», AJAX-сайты должны были иметь статические версии страниц, а технология лишь помогала поисковому боту найти их.
  • В 2014 году Google заявила, что будет сама индексировать сайты с динамическим контентом, загружаемым с помощью JavaScript.
  • В 2015 году Google заявила, что уже очень хорошо научилась индексировать сайты с динамическим контентом, и анонсировала отказ от решения 2009 года с «_escaped_fragment_». И более того, она не рекомендует его использовать.
  • В декабре 2017 года Google сообщила, что с 2018 года перестанет поддерживать решение с «_escaped_fragment_», потому что научилась индексировать сайты с динамическим контентом.

Итого: сейчас всё хорошо.

«Яндекс»

  • По сей день официальная справка говорит, что для индексации SPA-сайтов следует использовать решение с «_escaped_fragment_».
  • В ноябре 2015 «Яндекс» начал использовать в тестовом режиме JavaScript и CSS для индексации, но только для ограниченного круга ресурсов.
  • Официальный ответ сотрудника от 24 апреля 2017 года – AJAX-сайты «Яндекс» так и не научился индексировать.

Итого: всё плохо, AJAX-сайты «Яндекс» так и не поддерживает.

В «Яндексе» и сейчас предлагают инструкцию по настройке AJAX-сайтов то есть говорят, что каждая индексируемая AJAX-страница должна иметь HTML-версию.

Так как поддержка ещё одной версии сайта (статической) — удовольствие не из дешёвых, то мы рассмотрим сервис, автоматизирующий этот процесс, — Prerender.

Что такое Prerender

Prerender — это Open Source решение, которое является прослойкой между поисковым ботом и вашим сайтом, помогая поисковому боту увидеть AJAX-сайт так, как видите его вы, когда открываете в браузере.

Prerender может быть установлен как на ваши сервера, что абсолютно бесплатно, так и использоваться без инсталляции благодаря облачному сервису Prerender.io, который за очень разумную плату будет делать всю работу на своём оборудовании.

Методы интеграции

Что касается установки данного сервиса для работы с сайтом, здесь имеется много готовых решений. На официальном сайте вы можете найти ссылки на четыре способа настройки Prerender.

Самым простым способом будет настройка Nginx или Apache, так как на ноябрь 2017 года этими веб-серверами пользуются более 60% сайтов в интернете, а их настройка для использования сервиса Prerender не составит труда вашему системному администратору или разработчику.

Если же в силу ограничений хостинга или каких-либо других у вас нет возможности сделать данные настройки на стороне сервера, то вы можете использовать один из готовых официальных модулей для интеграции с Prerender (ExpressJS или Rails) или воспользоваться модулями, разработанными сообществом сервиса.

После того как вы сделаете необходимые настройки, вам потребуется также установить специальный тег в блоке <HEAD> на всех страницах, которые должны будут обработаны сервисом Prerender: <meta name="fragment" content="!">.

На этом настройка интеграции сервиса будет закончена.

Как это работает

Prerender делает за «Яндекс» его работу.

  • Когда поступает запрос от поискового бота «Яндекса», он перенаправляется на сервис Prerender.

  • Prerender запускает на сервере браузер Chrome и открывает запрошенную «Яндексом» страницу и ждёт, когда она полностью загрузится и отрисуется.

  • Prerender сохраняет уже отрисованную с помощью JavaScript страницу и отдает её «Яндексу» как статическую.

Таким образом, посетители сайта всё так же могут пользоваться динамическим быстрым интерфейсом SPA-приложения, а боты поисковых систем получают подготовленные для индексации статические HTML файлы.

Проверка

После того как все необходимые страницы сайта будут обработаны сервисом, вы можете проверить результат симулятором или в Fetch and Render из Search Console (Посмотреть как Googlebot), при этом на конце URL-адресов страниц необходимо добавлять "?_escaped_fragment_=". Данный параметр соответствует запросу поискового робота, когда он встречает тег fragment в блоке <HEAD> страницы вашего сайта. Например, если страница вашего сайта имеет URL: https://site.ru/catalog/.

То в сервисе «Посмотреть как Googlebot», нужно ввести URL:https://site.ru/catalog/?_escaped_fragment_=.

В «Яндекс.Вебмастере» доступен инструмент «Переобход страниц», вы можете воспользоваться им для того, чтобы ускорить обновление данных о страницах в базе индексирующего робота. В инструмент необходимо добавлять страницы именно по адресу HTML-копии, то есть с
?_escaped_fragment_=.

Что получим

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

Скриншот до

В декабре 2017 года внедрили сервис на сайт.

Скриншот после

Динамика по увеличению количества проиндексированных страниц в Google после внедрения сервиса.

Динамика по увеличению количества проиндексированных страниц в «Яндексе» после внедрения сервиса.

Как мы видим, есть значительный рост по количеству проиндексированных страниц, что в свою очередь положительно влияет и на поисковую оптимизацию ресурса.

Кейс интеграции от citilink.ru

В «Ситилинке» в 2016 году появилась мобильная версия построенная на фреймворке AngularJS. Особенность данного сайта в том, что он на 100% рендерится в браузере с помощью JavaScript. Вот так выглядит сайт при отключённом JS.

Да-да, это белый лист. Нет даже тега title

Поэтому мы сразу задумались над тем, какое решение выбрать, чтобы помочь поисковым ботам проиндексировать сайт.

Было установлено несколько серверов с Prerender и Memcache для кеширования результатов Prerender.

Особенность настройки была в том, что мы не стали использовать схему интеграции с «_escaped_fragment_», а отправляли запросы на Prerender по UserAgent, это позволило нам не заворачивать ботов Google на Prerender, так как он сам неплохо справлялся, а перенаправлять только тех ботов, которые нам были интересны (например, «Яндекс»).

Как бонус мы получили возможность переадресовывать на Prerender даже тех ботов, которые не поддерживают «_escaped_fragment_», это оказалось полезным для того, чтобы в популярных мессенджерах и соцсетях формировались правильные превью для нашего сайта.

Страницы в поиске после внедрения Prerender.

В процессе интеграции мы столкнулись с некоторыми трудностями, которые потребовали внесения правок в наше AngularJS приложение.

Большинство вопросов исчезает после прочтения «Лучших практик».

Рассмотрим некоторые из них.

  • Несуществующие страницы отдавали HTTP код 200 ОК, вместо 404 Not Found.

    Для решения этой проблемы достаточно, чтобы ваше приложение добавляло meta-тег «<meta name="prerender-status-code" content="404">», который даст понять Prerender, каким HTTP-кодом ответить.

  • Не работал 301 редирект.

    Опять же понадобились правки, добавляющие meta-теги:

    «<meta name="prerender-status-code" content="301">»

    «<meta name="prerender-header" content="Location: http://www.example.com">».

  • Prepender либо не дожидался, когда страница отрисована, либо ждал гораздо дольше, чем это нужно.

    Решение: нужно изначально добавить в HTML код:

    <script> window.prerenderReady = false; </script>

    И когда ваше приложение считает, что оно закончило загрузку заменить значение переменной:

    window.prerenderReady = true.

Заключение

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

Также возможны различные непредсказуемые баги. Мы рекомендуем не использовать клиентский рендеринг в тех случаях, где можно от него отказаться. Особенно в конкурентных нишах, где крайне важна SEO.

#маркетинг

Материал опубликован пользователем. Нажмите кнопку «Написать», чтобы поделиться мнением или рассказать о своём проекте.

Написать
{ "author_name": "Dennis Loganov", "author_type": "self", "tags": ["\u043c\u0430\u0440\u043a\u0435\u0442\u0438\u043d\u0433"], "comments": 15, "likes": 25, "favorites": 1, "is_advertisement": false, "subsite_label": "marketing", "id": 36449, "is_wide": false }
00
дни
00
часы
00
мин
00
сек
(function(){ var banner = document.querySelector('.teaserSberbank'); var isAdsDisabled = document.querySelector('noad'); if (!isAdsDisabled){ var countdownTimer = null; var timerItem = document.querySelectorAll('[data-sber-timer]'); var seconds = parseInt('15388' + '59599') - now(); function now(){ return Math.round(new Date().getTime()/1000.0); } function timer() { var days = Math.floor(seconds / 24 / 60 / 60); var hoursLeft = Math.floor((seconds) - (days * 86400)); var hours = Math.floor(hoursLeft / 3600); var minutesLeft = Math.floor((hoursLeft) - (hours * 3600)); var minutes = Math.floor(minutesLeft / 60); var remainingSeconds = seconds % 60; if (days < 10) days = '0' + days; if (hours < 10) hours = '0' + hours; if (minutes < 10) minutes = '0' + minutes; if (remainingSeconds < 10) remainingSeconds = '0' + remainingSeconds; if (seconds <= 0) { clearInterval(countdownTimer); } else { timerItem[0].textContent = days; timerItem[1].textContent = hours; timerItem[2].textContent = minutes; timerItem[3].textContent = remainingSeconds; seconds -= 1; } } timer(); countdownTimer = setInterval(timer, 1000); } else { banner.style.display = 'none'; } })();
{ "id": 36449, "author_id": 163839, "diff_limit": 1000, "urls": {"diff":"\/comments\/36449\/get","add":"\/comments\/36449\/add","edit":"\/comments\/edit","remove":"\/admin\/comments\/remove","pin":"\/admin\/comments\/pin","get4edit":"\/comments\/get4edit","complain":"\/comments\/complain","load_more":"\/comments\/loading\/36449"}, "attach_limit": 2, "max_comment_text_length": 5000, "subsite_id": 199113 }

15 комментариев 15 комм.

Популярные

По порядку

Написать комментарий...
6

За конструкцию "SEO оптимизация" сразу вон из профессии.

Ответить
0

А за CD-диск?))

Ответить
0

Бить "DVD дисками" =)

Ответить
4

Яндекс, пожалуйста сделай уже нормальную индексацию SPA. Испанский стыд же.

Ответить
0

Зачем? Органической выдачи уже почти не осталось.

Ответить
4

SSR наше всё

Ответить
2

Пререндер - всегда плохое решение, если речь идёт не о сайте-визитке с 5 страницами. Везде, где подразумевается какой-либо каталог, ты зачастую не можешь и не должен обходить все 5к+ страниц и все возможные естественные роуты, и обновлять их время от времени вручную. Есть SSR, есть гидратация, есть кеш, чтобы это работало и быстро и автоматически, и для любого поисковика

Ответить
1

Кто еще не видел эту статью https://www.elephate.com/blog/ultimate-guide-javascript-seo/ — must read. Про Chrome 41 действительно правда, сам недавно пофиксил один из проектов, который без SSR.

Ответить
1

SEO в SPA это сложный, но решаемый момент.
Но если говорить о SPA как технологии для E-Commerce это путь в никуда.
В России нет ни одного проекта на SPA, который быстро грузится из-за наличия тяжелой библиотеки. Которая еще и рендерится на клиенте. Пример на скрине citilink и wildberries. При абсолютно одинаковых условиях. Причем можно для сравнения взять любые другие сайты с той же технологией и результат будет такой же.

Ответить
0

Хотелось бы услышать мнение других SEO)

Ответить
0

Гугл же, вроде, умеет и контент, отдаваемый через ajax по клику, прогружать.

Ответить
0

писали бы на пыхе и в ус не дули

Ответить
0

У текущего angular вполне приличный ssr рендеринг на базе universal
Вопросы и ссылки в https://t.me/angular_universal_ru

Ответить
0

Статья ни о чем.
Общеизвестные факты, ничего нового.
Разве только то, что Ситилинк потерял свой in-house SEO-отдел.

Ответить

Комментарий удален

0

SPA -- для приложений, а не магазинов, каталогов, блогов, новостных порталов. Гнать поганой метлой хипстеров с напомаженными бородками, которые всюду суют свои моднявые JS-фреймворки!

Ответить
0

Прямой эфир

[ { "id": 1, "label": "100%×150_Branding_desktop", "provider": "adfox", "adaptive": [ "desktop" ], "adfox_method": "createAdaptive", "auto_reload": true, "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "bugf", "p2": "ezfl" } } }, { "id": 2, "label": "1200х400", "provider": "adfox", "adaptive": [ "phone" ], "auto_reload": true, "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "bugf", "p2": "ezfn" } } }, { "id": 3, "label": "240х200 _ТГБ_desktop", "provider": "adfox", "adaptive": [ "desktop" ], "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "bugf", "p2": "fizc" } } }, { "id": 4, "label": "240х200_mobile", "provider": "adfox", "adaptive": [ "phone" ], "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "bugf", "p2": "flbq" } } }, { "id": 5, "label": "300x500_desktop", "provider": "adfox", "adaptive": [ "desktop" ], "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "bugf", "p2": "ezfk" } } }, { "id": 6, "label": "1180х250_Interpool_баннер над комментариями_Desktop", "provider": "adfox", "adaptive": [ "desktop" ], "adfox": { "ownerId": 228129, "params": { "pp": "h", "ps": "bugf", "p2": "ffyh" } } }, { "id": 7, "label": "Article Footer 100%_desktop_mobile", "provider": "adfox", "adaptive": [ "desktop", "tablet", "phone" ], "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "bugf", "p2": "fjxb" } } }, { "id": 8, "label": "Fullscreen Desktop", "provider": "adfox", "adaptive": [ "desktop", "tablet" ], "auto_reload": true, "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "bugf", "p2": "fjoh" } } }, { "id": 9, "label": "Fullscreen Mobile", "provider": "adfox", "adaptive": [ "phone" ], "auto_reload": true, "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "bugf", "p2": "fjog" } } }, { "id": 10, "disable": true, "label": "Native Partner Desktop", "provider": "adfox", "adaptive": [ "desktop", "tablet" ], "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "clmf", "p2": "fmyb" } } }, { "id": 11, "disable": true, "label": "Native Partner Mobile", "provider": "adfox", "adaptive": [ "phone" ], "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "clmf", "p2": "fmyc" } } }, { "id": 12, "label": "Кнопка в шапке", "provider": "adfox", "adaptive": [ "desktop" ], "adfox": { "ownerId": 228129, "params": { "p1": "bscsh", "p2": "fdhx" } } }, { "id": 13, "label": "DM InPage Video PartnerCode", "provider": "adfox", "adaptive": [ "desktop", "tablet", "phone" ], "adfox_method": "createAdaptive", "adfox": { "ownerId": 228129, "params": { "pp": "h", "ps": "bugf", "p2": "flvn" } } }, { "id": 14, "label": "Yandex context video banner", "provider": "yandex", "yandex": { "block_id": "VI-223676-0", "render_to": "inpage_VI-223676-0-1104503429", "adfox_url": "//ads.adfox.ru/228129/getCode?pp=h&ps=bugf&p2=fpjw&puid1=&puid2=&puid3=&puid4=&puid8=&puid9=&puid10=&puid21=&puid22=&puid31=&puid32=&puid33=&fmt=1&dl={REFERER}&pr=" } }, { "id": 15, "label": "Плашка на главной", "provider": "adfox", "adaptive": [ "desktop", "tablet", "phone" ], "adfox": { "ownerId": 228129, "params": { "p1": "byudx", "p2": "ftjf" } } }, { "id": 16, "label": "Кнопка в шапке мобайл", "provider": "adfox", "adaptive": [ "tablet", "phone" ], "adfox": { "ownerId": 228129, "params": { "p1": "byzqf", "p2": "ftwx" } } }, { "id": 17, "label": "Stratum Desktop", "provider": "adfox", "adaptive": [ "desktop" ], "auto_reload": true, "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "bugf", "p2": "fzvb" } } }, { "id": 18, "label": "Stratum Mobile", "provider": "adfox", "adaptive": [ "tablet", "phone" ], "auto_reload": true, "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "bugf", "p2": "fzvc" } } }, { "id": 19, "label": "Тизер на главной", "provider": "adfox", "adaptive": [ "desktop", "tablet", "phone" ], "auto_reload": true, "adfox": { "ownerId": 228129, "params": { "p1": "cbltd", "p2": "gazs" } } } ]
Нейронная сеть научилась читать стихи
голосом Пастернака и смотреть в окно на осень
Подписаться на push-уведомления