автор: Jes Scholz
Хотя параметры любимы разработчиками и поклонниками аналитики, они часто являются кошмаром для SEO. Бесчисленные комбинации параметров могут создать тысячи вариантов URL из одного и того же контента.
Проблема в том, что мы не можем просто пожелать, чтобы параметры исчезли. Они играют важную роль в пользовательском опыте на сайте. Поэтому нам нужно понимать, как обрабатывать их дружественным для SEO способом.
Чтобы сделать это, мы исследуем:
- Основы URL-параметров
- Проблемы SEO, вызванные параметрами
- Оценка степени вашей проблемы с параметрами
- Решения SEO для обуздания параметров
- Лучшая практика обработки URL-параметров
Что такое URL-параметры?
Также известные под псевдонимами query strings или переменные URL, параметры — это часть URL, следующая за знаком вопроса. Они состоят из пары ключ-значение, разделенной знаком равенства. Несколько параметров можно добавить на одну страницу, используя амперсанд.
Наиболее распространенными случаями использования параметров являются:
- Отслеживание — Например, ?utm_medium=социальный, ?sessionid=123 или ?affiliateid=abc
- Перестановка — Например, ?sort=низкая цена, ?порядок=самый высокий или ?со=новинка
- Фильтрация — Например, ?тип=виджет, цвет=синий или ?диапазон цен=20-50
- Идентификация — Например, ?продукт=маленький синий виджет, идентификатор категории=124 или идентификатор элемента=24AU
- Разделение на страницы — Например, ?страница=2, ?p=2 или viewItems=10-30
- Поиск — Например, ?запрос=пользователи-запрос, ?q=пользователи-запрос или ?поиск=вариант выпадающего списка
- Перевод — Например, ?lang=fr, ?язык=de или
Конечно, вот перевод текста:
SEO-проблемы с URL-параметрами
1. Параметры создают дублирующий контент
Часто URL-параметры не вносят существенных изменений в контент страницы. Отсортированная версия страницы часто отличается от оригинала лишь незначительно. URL страницы с метками отслеживания или идентификатором сессии идентичен оригиналу.
Например, следующие URL будут возвращать коллекцию виджетов.
- Статический URL: https://www.example.com/widgets
- URL с метками отслеживания: https://www.example.com/widgets?sessionID=32764
- URL с параметром сортировки: https://www.example.com/widgets?sort=последний
- URL с параметром идентификации: https://www.example.com?category=виджеты
- URL с параметром поиска: https://www.example.com/products?search=виджет
Это несколько URL для контента, который по сути является одним и тем же, — теперь представьте это для каждой категории на вашем сайте. Это может действительно накапливаться.
Проблема в том, что поисковые системы рассматривают каждый URL с параметрами как новую страницу. Таким образом, они видят несколько вариантов одной и той же страницы. Все они обслуживают дублирующий контент и нацелены на одну и ту же ключевую фразу или семантическую тему.
Хотя такое дублирование вряд ли приведет к тому, что ваш сайт будет полностью исключен из результатов поиска, оно приводит к каннибализации ключевых слов и может снизить восприятие Google общего качества сайта, поскольку эти дополнительные URL не добавляют никакой реальной ценности.
2. Параметры расходуют бюджет на краулинг
Краулинг ненужных страниц с параметрами затрачивает бюджет на краулинг, снижая способность сайта индексировать релевантные для SEO страницы и увеличивая нагрузку на сервер.
Google подводит итог этой точки зрения:
«Слишком сложные URL, особенно содержащие несколько параметров, могут создать проблемы для краулеров, создавая ненужно большое количество URL, указывающих на идентичный или похожий контент на вашем сайте. В результате Googlebot может потреблять гораздо больше пропускной способности, чем необходимо, или может быть не в состоянии полностью проиндексировать весь контент на вашем сайте».
3. Параметры разбавляют сигналы ранжирования страницы
Если у вас есть несколько вариантов одного и того же контента страницы, ссылки и публикации в социальных сетях могут поступать на разные версии.
Это разбавляет ваши сигналы ранжирования. Когда вы запутываете краулера, он становится неуверенным, какую из конкурирующих страниц следует индексировать для поискового запроса.
4. Параметры делают URL менее кликабельными
Давайте посмотрим правде в глаза. URL-параметры не очень привлекательны. Их трудно читать. Они не кажутся надежными. Поэтому они с меньшей вероятностью будут нажаты.
Это повлияет на производительность страницы. Не только потому, что CTR может влиять на рейтинги, но и потому, что на них менее нажимается в социальных сетях, в электронной почте, при копировании и вставке в форумы или где-либо еще, где отображается полный URL.
Хотя это может оказать лишь незначительное влияние на эффективность одной страницы, каждый твит, лайк, репост, электронное письмо, ссылка и упоминание имеют значение для домена.
Плохая читаемость URL может способствовать снижению вовлеченности бренда.
Оцените степень вашей проблемы с параметрами
Важно знать все параметры, используемые на вашем сайте. Но, скорее всего, ваши разработчики не ведут актуального списка.
Так как же найти все параметры, которые необходимо обработать? Или понять, как поисковые системы крадут и индексируют такие страницы? Понимая ценность, которую они приносят пользователям?
Следуйте этим пяти шагам:
- Запустите краулер: С помощью инструмента, такого как Screaming Frog, вы можете искать “?” в URL.
- Посмотрите в инструменте URL-параметров Google Search Console: Google автоматически добавляет найденные им запросы.
- Просмотрите свои журналы: Проверьте, крабит ли Googlebot URL-параметры.
- Поиск с использованием продвинутых операторов: Узнайте, как Google индексирует параметры, которые вы нашли, введя ключевое слово в комбинации site:example.com inurl:.
- Посмотрите в отчете Google Analytics All Pages: Ищите “?”, чтобы увидеть, как каждый из параметров, которые вы нашли, используются пользователями. Обязательно проверьте, что параметры URL-запросов не были исключены в настройках представления.
С этими данными вы можете теперь решить, как лучше всего обрабатывать каждый параметр вашего сайта.
SEO-решения для обуздания URL-параметров
У вас в арсенале шесть инструментов для решения проблем с URL-параметрами на стратегическом уровне.
Ограничьте использование URL-параметров
Простой обзор того, как и почему генерируются параметры, может дать быстрый SEO-выигрыш. Вы часто обнаружите способы сокращения количества URL-параметров и, таким образом, минимизации негативного влияния SEO. Существуют четыре распространенные проблемы, с которых можно начать ваш обзор.
1. Устраните ненужные параметры
Спросите у разработчика список каждого веб-параметра и его функции. Вероятно, вы обнаружите параметры, которые больше не выполняют полезной функции.
Например, пользователи могут быть лучше идентифицированы с помощью файлов cookie, чем с помощью идентификаторов сессии. Однако параметр сессии может все еще присутствовать на вашем сайте, поскольку он использовался исторически.
Или вы можете обнаружить, что фильтр в вашей фасетной навигации редко используется пользователями.
Любые параметры, вызванные техническим долгом, должны быть немедленно устранены.
2. Предотвратите наличие пустых значений
URL-параметры должны добавляться в URL только тогда, когда они имеют функцию. Не допускайте добавления параметрных ключей, если значение пустое.
В приведенном выше примере ключ2 и ключ3 не имеют значения ни буквально, ни фигурально.
3. Используйте ключи только один раз
Избегайте применения нескольких параметров с одним и тем же параметром имени и разным значением.
Для вариантов выбора нескольких значений лучше объединить значения вместе после одного ключа.
4. Упорядочите URL-параметры
Если один и тот же URL-параметр переставляется, страницы воспринимаются поисковыми системами как одинаковые.
Таким образом, порядок параметров не имеет значения с точки зрения дублирующего контента. Однако каждое из этих сочетаний расходует бюджет на краулинг и разделяет сигналы ранжирования страницы.
Избегайте этих проблем, попросив разработчика написать скрипт, который всегда располагает параметры в одинаковом порядке, независимо от того, как пользователь их выбирает.
На мой взгляд, вы должны начать с переводящихся параметров, затем с идентифицирующих, затем с параметрами сортировки, а затем с параметрами слоя, фильтрации, перестановки или поиска, и, наконец, с отслеживающими параметрами.
Преимущества:
- Позволяет более эффективное использование бюджета на краулинг.
- Снижает проблемы с дублирующим контентом.
- Консолидирует сигналы ранжирования на меньшее количество страниц.
- Подходит для всех типов параметров.
Недостатки:
- Требует умеренного времени на техническую реализацию.
Атрибут ссылок rel=”canonical”
Атрибут ссылок rel=”canonical” указывает на то, что страница имеет идентичный или похожий контент на другую. Это побуждает поисковые системы объединять сигналы ранжирования на URL, указанный как канонический.
Вы можете использовать атрибут rel=”canonical” для ваших URL с параметрами, чтобы отслеживать, идентифицировать или переставлять параметры. Но эта тактика не подходит, когда контент на странице с параметрами недостаточно близок к каноническому, например, при пагинации, поиске, переводе или некоторых параметрах фильтрации.
Преимущества:
- Относительно простая техническая реализация.
- Вероятно, предотвратит проблемы с дублирующим контентом.
- Консолидирует сигналы ранжирования на канонический URL.
Недостатки:
- Расходует бюджет на краулинг страниц с параметрами.
- Не подходит для всех типов параметров.
- Интерпретируется поисковыми системами как сильный намек, а не директива.
Мета-тег robots "noindex"
Установите директиву "noindex" для любой страницы, основанной на параметрах, которая не имеет ценности с точки зрения SEO. Этот тег предотвратит индексацию страницы поисковыми системами.
URL-адреса с тегом "noindex" также, вероятно, будут сканироваться реже, и если он присутствует в течение длительного времени, в конечном итоге приведет к тому, что Google применит атрибут "nofollow" к ссылкам на странице.
Преимущества:
- Относительно простая техническая реализация.
- Вероятно, предотвратит проблемы с дублирующим контентом.
- Подходит для всех типов параметров, которые вы не хотите индексировать.
- Удаляет существующие URL-адреса с параметрами из индекса.
Недостатки:
- Не предотвращает поисковые системы от сканирования URL-адресов, но побуждает их делать это реже.
- Не консолидирует сигналы ранжирования.
- Интерпретируется поисковыми системами как сильный намек, а не директива.
Robots.txt Disallow
Файл robots.txt — это то, что поисковые системы просматривают в первую очередь перед краулингом вашего сайта. Если они видят, что что-то запрещено, они даже не пойдут туда.
Вы можете использовать этот файл для блокировки доступа краулера к каждому URL, основанному на параметрах (с помощью Disallow: )) { document.addEventListener("mousemove", resizeIframe, false); } }, false); document.addEventListener("mouseup", function(){ if (isIframeActive()) { document.removeEventListener("mousemove", resizeIframe, false); } }, false); barEl.onclick = function (e) { var target = e.target, block = findAncestor(target, blockClass); if (block && !block.classList.contains(titleClass) && !block.classList.contains(ignoreClickClass) && e.which !== 2 && !e.ctrlKey ) { while (target !== this) { if (target.href) { removeActiveBlocksCls(); block.classList.add(blockActiveClass); showIframe(target.href); } target = target.parentNode; } e.preventDefault(); } }; toggleEl.onclick = togglePosition; } function findAncestor(el, cls) { while ((el = el.parentElement) && !el.classList.contains(cls)) ; return el; } function renderAjaxRequests() { var requestCounter = document.getElementsByClassName('yii-debug-toolbar__ajax_counter'); if (!requestCounter.length) { return; } var ajaxToolbarPanel = document.querySelector('.yii-debug-toolbar__ajax'); var tbodies = document.getElementsByClassName('yii-debug-toolbar__ajax_requests'); var state = 'ok'; if (tbodies.length) { var tbody = tbodies[0]; var rows = document.createDocumentFragment(); if (requestStack.length) { var firstItem = requestStack.length > 20 ? requestStack.length - 20 : 0; for (var i = firstItem; i < requestStack.length; i++) { var request = requestStack[i]; var row = document.createElement('tr'); rows.appendChild(row); var methodCell = document.createElement('td'); methodCell.innerHTML = request.method; row.appendChild(methodCell); var statusCodeCell = document.createElement('td'); var statusCode = document.createElement('span'); if (request.statusCode < 300) { statusCode.setAttribute('class', 'yii-debug-toolbar__ajax_request_status yii-debug-toolbar__label_success'); } else if (request.statusCode < 400) { statusCode.setAttribute('class', 'yii-debug-toolbar__ajax_request_status yii-debug-toolbar__label_warning'); } else { statusCode.setAttribute('class', 'yii-debug-toolbar__ajax_request_status yii-debug-toolbar__label_error'); } statusCode.textContent = request.statusCode || '-'; statusCodeCell.appendChild(statusCode); row.appendChild(statusCodeCell); var pathCell = document.createElement('td'); pathCell.className = 'yii-debug-toolbar__ajax_request_url'; pathCell.innerHTML = request.url; pathCell.setAttribute('title', request.url); row.appendChild(pathCell); var durationCell = document.createElement('td'); durationCell.className = 'yii-debug-toolbar__ajax_request_duration'; if (request.duration) { durationCell.innerText = request.duration + " ms"; } else { durationCell.innerText = '-'; } row.appendChild(durationCell); row.appendChild(document.createTextNode(' ')); var profilerCell = document.createElement('td'); if (request.profilerUrl) { var profilerLink = document.createElement('a'); profilerLink.setAttribute('href', request.profilerUrl); profilerLink.innerText = request.profile; profilerCell.appendChild(profilerLink); } else { profilerCell.innerText = 'n/a'; } row.appendChild(profilerCell); if (request.error) { if (state !== "loading" && i > requestStack.length - 4) { state = 'error'; } } else if (request.loading) { state = 'loading' } row.className = 'yii-debug-toolbar__ajax_request'; } while (tbody.firstChild) { tbody.removeChild(tbody.firstChild); } tbody.appendChild(rows); } ajaxToolbarPanel.style.display = 'block'; } requestCounter[0].innerText = requestStack.length; var className = 'yii-debug-toolbar__label yii-debug-toolbar__ajax_counter'; if (state === 'ok') { className += ' yii-debug-toolbar__label_success'; } else if (state === 'error') { className += ' yii-debug-toolbar__label_error'; } requestCounter[0].className = className; } function shouldTrackRequest(requestUrl) { if (!toolbarEl) { return false; } var a = document.createElement('a'); a.href = requestUrl; var skipAjaxRequestUrls = JSON.parse(toolbarEl.getAttribute('data-skip-urls')); if (Array.isArray(skipAjaxRequestUrls) && skipAjaxRequestUrls.length && skipAjaxRequestUrls.includes(requestUrl)) { return false; } return a.host === location.host; } var proxied = XMLHttpRequest.prototype.open; XMLHttpRequest.prototype.open = function (method, url, async, user, pass) { var self = this; if (shouldTrackRequest(url)) { var stackElement = { loading: true, error: false, url: url, method: method, start: new Date() }; requestStack.push(stackElement); this.addEventListener('readystatechange', function () { if (self.readyState === 4) { stackElement.duration = self.getResponseHeader('X-Debug-Duration') || new Date() - stackElement.start; stackElement.loading = false; stackElement.statusCode = self.status; stackElement.error = self.status < 200 || self.status >= 400; stackElement.profile = self.getResponseHeader('X-Debug-Tag'); stackElement.profilerUrl = self.getResponseHeader('X-Debug-Link'); renderAjaxRequests(); } }, false); renderAjaxRequests(); } proxied.apply(this, Array.prototype.slice.call(arguments)); }; if (window.fetch) { var originalFetch = window.fetch; window.fetch = function (input, init) { var method; var url; if (typeof input === 'string') { method = (init && init.method) || 'GET'; url = input; } else if (window.URL && input instanceof URL) { method = (init && init.method) || 'GET'; url = input.href; } else if (window.Request && input instanceof Request) { method = input.method; url = input.url; } var promise = originalFetch(input, init); if (shouldTrackRequest(url)) { var stackElement = { loading: true, error: false, url: url, method: method, start: new Date() }; requestStack.push(stackElement); promise.then(function (response) { stackElement.duration = response.headers.get('X-Debug-Duration') || new Date() - stackElement.start; stackElement.loading = false; stackElement.statusCode = response.status; stackElement.error = response.status < 200 || response.status >= 400; stackElement.profile = response.headers.get('X-Debug-Tag'); stackElement.profilerUrl = response.headers.get('X-Debug-Link'); renderAjaxRequests(); return response; }).catch(function (error) { stackElement.loading = false; stackElement.error = true; renderAjaxRequests(); throw error; }); renderAjaxRequests(); } return promise; }; } })();