簡體   English   中英

Document.querySelector 返回 null 直到使用 DevTools 檢查元素

[英]Document.querySelector returns null until element is inspected using DevTools

我正在嘗試創建一個 Chrome 擴展程序,可以在 Facebook 上找到“贊助”帖子並將其刪除。

在執行此操作時,我注意到 Facebook.com 上 Google Chrome 的這種相當奇怪的行為,其中對現有元素的某些類型的查詢(在我的例子中document.querySelector('a[href*="/ads/about"]'); ) 將返回null 但是,如果您“檢查”-單擊它們(使用檢查工具或 CTRL+SHIFT+C),它們將顯示在 DevTools 中,然后在控制台中再次運行查詢將顯示該元素。 無需對頁面進行任何滾動、移動、調整大小或任何操作。

這可以使用上面的說明輕松復制,但為了清楚起見,我制作了以下視頻,准確顯示了奇怪的行為:

https://streamable.com/mxsf86

這是某種 dom 查詢緩存問題嗎? 你有沒有遇到過類似的事情? 謝謝

編輯:問題現在已減少為返回null直到元素懸停的查詢,它不再是與 DevTools 相關的問題。

正如已經注意到的,贊助商鏈接在某些鼠標事件發生之前根本不在其位置。 一旦鼠標事件發生,元素就會被添加到 DOM 中,據說這就是 Facebook 避免人們太容易抓取它的方式。

因此,如果您想找到贊助鏈接,那么您需要執行以下操作

  • 找出導致添加鏈接的確切事件是什么
  • 進行實驗,直到您發現如何以編程方式生成該事件
  • 實現一個爬行算法,在牆上長時間滾動,然后引發給定的事件。 那時你可能會得到很多贊助鏈接

注意:贊助鏈接由公司支付,如果他們的廣告位被不感興趣的機器人用完,他們不會很高興。

我解決這個問題的方法如下:

// 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 && 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 && 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);

})();

參考:

我在chrome上遇到了同樣的問題。 如果它對任何人有幫助,我通過訪問框架來解決它

window.frames["myframeID"].document.getElementById("myElementID")

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM