#javascript #html #google-chrome #dom
#javascript #HTML #google-chrome #dom
Вопрос:
Я пытаюсь создать расширение Chrome, которое находит «спонсируемые» сообщения на Facebook и удаляет их.
Делая это, я заметил это довольно странное поведение Google Chrome на Facebook.com , где определенные типы запросов для существующих элементов (в моем случае document.querySelector('a[href*="/ads/about"]');
) будут возвращать null
. Но если вы нажмете на них «проверить» (с помощью инструмента проверки или CTRL SHIFT C), они отобразятся в DevTools, а затем снова запустите запрос в консоли, чтобы показать элемент. Без какой-либо прокрутки, перемещения, изменения размера или каких-либо действий со страницей.
Это можно легко воспроизвести, используя приведенные выше инструкции, но для наглядности я сделал следующее видео, которое точно показывает странное поведение:
Это какая-то проблема с кэшированием dom-запросов? Вы когда-нибудь сталкивались с чем-то подобным? Спасибо
РЕДАКТИРОВАТЬ: проблема теперь сводится к возврату запроса null
до тех пор, пока элемент не будет завис, и это больше не проблема, связанная с DevTools.
Комментарии:
1. » и затем повторный запуск запроса в консоли покажет элемент. » похоже, что при первом запуске кода элемент просто отсутствует, и вам нужно дождаться его добавления в DOM.
2. После просмотра видео: вы уверены , что ссылка не отображается при нажатии или более длительном наведении курсора мыши или что-то еще?
3. Возможно, div, который вы пытаетесь получить, создан с использованием порталов React и помещен в другое дерево DOM.
4. @VLAZ Я запускаю запрос примерно через 3-4 секунды после фактического времени, когда я вижу его на странице… итак, как он мог «еще не быть добавлен в DOM»?
5.
Sponsored
Этоrole="button"
с tabindex 0, который перезагружает содержимое при нажатии и наведении курсора мыши. Вы также можете увидеть это наnetwork
вкладке.a
Просто не существует до этого. Не имеет значения, наведете ли вы на него курсор с помощью DevTools open или нет.
Ответ №1:
Как уже было замечено, рекламные ссылки просто не находятся на своем месте до того, как произойдет какое-либо событие мыши. Как только происходит событие мыши, элементы добавляются в DOM, предположительно, Facebook таким образом избегает того, чтобы люди слишком легко обходили его.
Итак, если у вас есть задание найти рекламные ссылки, вам нужно будет выполнить следующее
- узнайте, какое именно событие приводит к добавлению ссылок
- проводите эксперименты, пока не узнаете, как вы можете программно сгенерировать это событие
- реализуйте алгоритм обхода, который выполняет некоторую прокрутку на стене в течение длительного времени, а затем вызывает данное событие. В этот момент вы можете получить много рекламных ссылок
Примечание: рекламные ссылки оплачиваются компаниями, и они были бы не очень довольны, если бы их рекламные слоты использовались незаинтересованными ботами.
Ответ №2:
Подход, который я использовал для решения этой проблемы, заключается в следующем:
// using an IIFE ("Immediately-Invoked Function Expression"):
(function() {
'use strict';
// using Arrow function syntax to define the callback function
// supplied to the (later-created) mutation observer, with
// two arguments (supplied automatically by that mutation
// observer), the first 'mutationList' is an Array of
// MutationRecord Objects that list the changes that were
// observed, and the second is the observer that observed
// the change:
const nodeRemoval = (mutationList, observer) => {
// here we use Array.prototype.forEach() to iterate over the
// Array of MutationRecord Objects, using an Arrow function
// in which we refer to the current MutationRecord of the
// Array over which we're iterating as 'mutation':
mutationList.forEach( (mutation) => {
// if the mutation.addedNodes property exists and
// also has a non-falsy length (zero is falsey, numbers
// above zero are truthy and negative numbers - while truthy -
// seem invalid in the length property):
if (mutation.addedNodes amp;amp; mutation.addedNodes.length) {
// here we retrieve a list of nodes that have the
// "aria-label" attribute-value equal to 'Advertiser link':
mutation.target.querySelectorAll('[aria-label="Advertiser link"]')
// we use NodeList.prototype.forEach() to iterate over
// the returned list of nodes (if any) and use (another)
// Arrow function:
.forEach(
// here we pass a reference to the current Node of the
// NodeList we're iterating over, and use
// ChildNode.remove() to remove each of the nodes:
(adLink) => adLink.remove() );
}
});
},
// here we retrieve the <body> element (since I can't find
// any element with a predictable class or ID that will
// consistently exist as an ancestor of the ad links):
targetNode = document.querySelector('body'),
// we define the types of changes we're looking for:
options = {
// we're looking for changes amongst the
// element's descendants:
childList: true,
// we're not looking for attribute-changes:
attributes: false,
(if this is false, or absent, we look only to
changes/mutations on the target element itself):
subtree: true
},
// here we create a new MutationObserver, and supply
// the name of the callback function:
observer = new MutationObserver(nodeRemoval);
// here we specify what the created MutationObserver
// should observe, supplying the targetNode (<body>)
// and the defined options:
observer.observe(targetNode, options);
})();
Я понимаю, что в вашем вопросе вы ищете элементы, которые соответствуют другому атрибуту и значению атрибута ( document.querySelector('a[href*="/ads/about"]')
), но поскольку это значение атрибута не соответствует моей собственной ситуации, я не мог использовать его в своем коде, но это должно быть так же просто, как замена:
mutation.target.querySelectorAll('[aria-label="Advertiser link"]')
С:
mutation.target.querySelector('a[href*="/ads/about"]')
Хотя стоит отметить, что querySelector()
вернет только первый узел, соответствующий селектору, или null
; поэтому вам может потребоваться включить некоторые проверки в ваш код.
Хотя может показаться, что в приведенном выше коде довольно много без комментариев, это становится просто:
(function() {
'use strict';
const nodeRemoval = (mutationList, observer) => {
mutationList.forEach( (mutation) => {
if (mutation.addedNodes amp;amp; mutation.addedNodes.length) {
mutation.target.querySelectorAll('[aria-label="Advertiser link"]').forEach( (adLink) => adLink.remove() );
}
});
},
targetNode = document.querySelector('body'),
options = {
childList: true,
attributes: false,
subtree: true
},
observer = new MutationObserver(nodeRemoval);
observer.observe(targetNode, options);
})();
Ссылки:
Ответ №3:
Я столкнулся с той же проблемой в Chrome. Если это кому-нибудь поможет, я решил это, обратившись к фрейму с помощью
window.frames["myframeID"].document.getElementById("myElementID")