JavaScript | Как получить все ссылки с фрагментами на HTML-странице?

JavaScript | Как получить все ссылки с фрагментами на HTML-странице?

Одной командой

Получаем массив из строк-адресов со знаками решётки из атрибутов href элементов <a>

Array.from(document.getElementsByTagName("a")).filter(i => i.hash != "").map(i => i.href)
Получение всех ссылок с фрагментами на HTML-странице при помощи JavaScript и консоли браузера
Получение всех ссылок с фрагментами на HTML-странице при помощи JavaScript и консоли браузера

 

С выводом на текущую страницу «замудрёным» способом 🙂

document.write((((Array.from(document.getElementsByTagName("a"))).map(i => {if (i.hash != "") {return i.href}})).filter(i => i != undefined)).join("<br>"))
Получение всех ссылок с фрагментами - замудрёный способ
Получение всех ссылок с фрагментами — замудрёный способ

Куда вводить эту команду? Открываете HTML-страницу, с которой хотите получить все ссылки. Включаете «Инструменты разработчика» в браузере (CTRL + SHIFT + i). Находите вкладку «Console«. Тыкаете курсор в белое поле справа от синей стрелочки. Вставляете команду. Жмёте ENTER.

Для тех кто не понял длинную строчку кода выше, предлагаю упрощённую для понимания версию. Пошаговая инструкция ниже.

 

Теория вопроса

Для начала у вас должна быть страница, на которой присутствуют фрагменты. О каких фрагментах идёт речь?

Стандарт RFC 3986 описывает URI — Унифицированный идентификатор ресурса. URI состоит из пяти синтаксических компонентов:

  • схема (scheme)
  • основание (authority)
  • путь (path)
  • запрос (query)
  • фрагмент (fragment)

Фрагмент URI позволяет косвенно идентифицировать вторичный ресурс посредством ссылки на первичный ресурс и дополнительной идентифицирующей информации. Идентифицированный вторичный ресурс может быть некоторой частью или подмножеством первичного ресурса, некоторым представлением представлений первичного ресурса или некоторым другим ресурсом, определенным или описанным этими представлениями. Компонент идентификатора фрагмента указывается присутствием символа знака решётки («#») и заканчивается концом URI. Семантика идентификатора фрагмента не зависит от схемы URI и, следовательно, не может быть переопределена спецификациями схемы.

 

Как это работает в браузере?

Пользователь в браузере «кликает» на ссылку с фрагментом (нажимает ЛКМ на элемент <a> с атрибутом href, у которого в значении есть решётка «#»). Далее он попадает на начало страницы, а затем страница пролистывается баузером до той части документа у которой первый элемент с атрибутом id равен значению, после решётки «#» в URI.

По сути решётка — это нацеливание на элемент HTML.

ВАЖНО! В URI может быть передан только один фрагмент, а вот на странице может быть несколько элементов с одинаковыми идентификаторами «id». Это неправильно, это проблемы разработчиков. В идеале по одному адресу должен быть уникальный набор элементов с единственным id (не повторяющимся). Но нас пока интересуют только ссылки.

 

Практика решения задачи «Замудрёным» способом

С теорией разобрались, теперь практика. Открываем страницу товаров интернет-магазина. Пусть это будут телевизоры:

https://www.ozon.ru/category/televizory-15528/

Нужный нам элемент ссылки (<a>) с фрагментом в разметке страницы:

Элемент ссылки с фрагментом в разметке
Элемент ссылки с фрагментом в разметке

Мы видим ссылку (элемент):

<a data-v-414055a2="" class="a1b" href="/product/televizor-polarline-32pl13tc-sm-32-chernyy-186789154/#comments--offset-80">11 отзывов</a>

Видим значение атрибута href:

/product/televizor-polarline-32pl13tc-sm-32-chernyy-186789154/#comments--offset-80

Видим фрагмент URI:

#comments--offset-80

Если пользователь кликнет на эту ссылку, то сначала он перейдёт на страницу с товаром

Страница с товаром - телевизор ЖК
Страница с товаром — телевизор ЖК

…а потом страница промотается до фрагмента с отзывами/комментариями пользователей

Фрагмент страницы с отзывами на телевизор
Фрагмент страницы с отзывами на телевизор

Хитрая реализация сайта Ozon быстро распознаёт фрагмент в новой открывшейся странице, быстро проматывает в нужное место документа и тут же заменяет URI по которому осуществился переход. Это редкий случай, но к нему нужно быть готовым.

 
Этот адрес

https://www.ozon.ru/product/televizor-polarline-32pl13tc-sm-32-chernyy-186789154/#comments--offset-80

Быстро меняется на

https://www.ozon.ru/product/televizor-polarline-32pl13tc-sm-32-chernyy-186789154/

Это частный случай перехода подходящий под систему формирования и управления контентом. Не все сайты (проекты) будут такими. Это вам для кругозора. Но мы вернёмся к странице с фрагментами в ссылках.

 

Получаем все ссылки на странице

var a = document.getElementsByTagName("a")

Нам вернулась HTML-коллекция из 276 узлов <a>

HTML колекция из 276 элементов a - JavaScript
HTML колекция из 276 элементов a — JavaScript

 

Преобразуем HTML-коллекцию в массив

var b = Array.from(a)

Вывод в консоль браузера:

Массив из 276 элементов a - JavaScript
Массив из 276 элементов a — JavaScript

 

Определим ключ фильтрации ссылок

В JavaScript ключом фрагмента URI у объекта ссылки является hash. При проходе по массиву мы будем извлекать значения href с ключами hash.

Ключ hash у ссылки - JavaScript
Ключ hash у ссылки — JavaScript

Если ключ hash будет пустым, то мы увидим пустую строку:

Пустой ключ hash - ссылка без фрагмента URI - JavaScript
Пустой ключ hash — ссылка без фрагмента URI — JavaScript

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

 

Преобразование массива

Ключевым условием отбора будет условие (i.hash != «»). Если не равно пустоте.

var c = b.map(i => {if (i.hash != "") {return i.href}})

Большинство ссылок не будут иметь фрагментов URI, поэтому мы получим undefined.

undefined в этом массиве - это ссылки без фрагментов URI
undefined в этом массиве — это ссылки без фрагментов URI

 

Очистим массив от undefined

Будем использовать метод прототипов Arrayfilter(). В него нужно передать условие фильтрации, при котором будут возвращены нужные элементы. В нашем случае мы проверяем каждый элемент на undefined. Если проверяемый элемент НЕ равен undefined, тогда возвращаем этот элемент в новый массив.

var d = c.filter(i => i != undefined)

Теперь из 276 ссылок мы получили 18 ссылок с фрагментами:

Массив из 18 ссылок с фрагментами URI - JavaScript
Массив из 18 ссылок с фрагментами URI — JavaScript

 

Подготовим строку для вывода информации в текущий документ

Массив перегоняем в строку и добавляем разделитель между элементами:

var e = d.join("<br>")

Результат соединения элементов массива:

Строка со всеми ссылками с фрагментами
Строка со всеми ссылками с фрагментами

 

Выводим строку на страницу текущего документа

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

document.write(e)

Результат вывода:

Вывод ссылок с фрагментами URI в текущий документ
Вывод ссылок с фрагментами URI в текущий документ

В данном примере мы получили одинаковые по смыслу фрагменты. Они все ведут на отзывы каких-либо телевизоров. Так захотели разработчики — их право.

Ещё примечательно то, что все ссылки с фрагментами являются внутренними ссылками (ведут на этот же домен).
 

Информационные ссылки

JavaScript | Как получить все ссылки на HTML-странице?

JavaScript | Как узнать количество ссылок на HTML-странице?

JavaScript | Как получить все внутренние ссылки на HTML-странице?

JavaScript | Как получить все внешние ссылки на HTML-странице?

JavaScript | Как получить все ссылки с запросами на HTML-странице?

DOM стандарт — https://efim360.ru/dom/

Читайте перевод полной версии стандарта «объектной модели документа», чтобы ознакомиться со всеми концепциями и интерфейсами.

DOMLiving Standardhttps://dom.spec.whatwg.org

Читайте официальную документацию живого стандарта «объектной модели документа», чтобы быть в курсе последних изменений.

https://dom.spec.whatwg.org/#dom-document-getelementsbytagname

JavaScriptМассивыhttps://efim360.ru/javascript-massivy-array/

ECMAScriptLiving Standardhttps://tc39.es/ecma262/#sec-array.prototype.map