对于没有完全了解它是如何工作的每个人,这里是另一个示例,其中包含您可能会发现有用的解释:
所以我们在这里有两个挑战。
1)检测挑战何时显示并获取挑战的覆盖div
function detectWhenReCaptchaChallengeIsShown() {
return new Promise(function(resolve) {
const targetElement = document.body;
const observerConfig = {
childList: true,
attributes: false,
attributeOldValue: false,
characterData: false,
characterDataOldValue: false,
subtree: false
};
function DOMChangeCallbackFunction(mutationRecords) {
mutationRecords.forEach((mutationRecord) => {
if (mutationRecord.addedNodes.length) {
var reCaptchaParentContainer = mutationRecord.addedNodes[0];
var reCaptchaIframe = reCaptchaParentContainer.querySelectorAll('iframe[title*="recaptcha"]');
if (reCaptchaIframe.length) {
var reCaptchaChallengeOverlayDiv = reCaptchaParentContainer.firstChild;
if (reCaptchaChallengeOverlayDiv.length) {
reCaptchaObserver.disconnect();
resolve(reCaptchaChallengeOverlayDiv);
}
}
}
});
}
const reCaptchaObserver = new MutationObserver(DOMChangeCallbackFunction);
reCaptchaObserver.observe(targetElement, observerConfig);
});
}
首先,我们创建了一个目标元素,用于观察 Google iframe 的外观。我们将 document.body 定位为 iframe 将附加到它:
const targetElement = document.body;
然后我们为 MutationObserver 创建了一个配置对象。在这里,我们可以指定我们在 DOM 更改中跟踪的确切内容。请注意,默认情况下所有值都是“false”,因此我们只能留下“childList”——这意味着我们只会观察目标元素的子节点更改——在我们的例子中是 document.body:
const observerConfig = {
childList: true,
attributes: false,
attributeOldValue: false,
characterData: false,
characterDataOldValue: false,
subtree: false
};
然后我们创建了一个函数,当观察者检测到我们在配置对象中指定的特定类型的 DOM 更改时将调用该函数。第一个参数表示一个Mutation Observer对象数组。我们抓住了覆盖 div 并返回了 Promise。
function DOMChangeCallbackFunction(mutationRecords) {
mutationRecords.forEach((mutationRecord) => {
if (mutationRecord.addedNodes.length) { //check only when notes were added to DOM
var reCaptchaParentContainer = mutationRecord.addedNodes[0];
var reCaptchaIframe = reCaptchaParentContainer.querySelectorAll('iframe[title*="recaptcha"]');
if (reCaptchaIframe.length) { // Google reCaptcha iframe was loaded
var reCaptchaChallengeOverlayDiv = reCaptchaParentContainer.firstChild;
if (reCaptchaChallengeOverlayDiv.length) {
reCaptchaObserver.disconnect(); // We don't want to observe more DOM changes for better performance
resolve(reCaptchaChallengeOverlayDiv); // Returning the overlay div to detect close events
}
}
}
});
}
最后我们实例化了一个观察者本身并开始观察 DOM 变化:
const reCaptchaObserver = new MutationObserver(DOMChangeCallbackFunction);
reCaptchaObserver.observe(targetElement, observerConfig);
2)第二个挑战是那个帖子的主要问题——我们如何检测到挑战已经结束?好吧,我们再次需要 MutationObserver 的帮助。
detectReCaptchaChallengeAppearance().then(function (reCaptchaChallengeOverlayDiv) {
var reCaptchaChallengeClosureObserver = new MutationObserver(function () {
if ((reCaptchaChallengeOverlayDiv.style.visibility === 'hidden') && !grecaptcha.getResponse()) {
// TADA!! Do something here as the challenge was either closed by hitting outside of an overlay div OR by pressing ESC key
reCaptchaChallengeClosureObserver.disconnect();
}
});
reCaptchaChallengeClosureObserver.observe(reCaptchaChallengeOverlayDiv, {
attributes: true,
attributeFilter: ['style']
});
});
所以我们所做的是我们使用我们在 Step1 中创建的 Promise 获得了 Google reCaptcha 挑战覆盖 div,然后我们订阅了覆盖 div 上的“样式”更改。这是因为当挑战结束时 - 谷歌将其淡出。需要注意的是,当一个人成功解决验证码时,可见性也会被隐藏。这就是我们添加 !grecaptcha.getResponse() 检查的原因。除非挑战得到解决,否则它不会返回任何内容。差不多就是这样 - 我希望能有所帮助:)