破解动态网页:如何用JavaScript获取自动消失的联想词

前几天在做数据分析时,我尝试获取某网站上输入搜索词后的联想词,输入搜索词后会弹出一个显示联想词的框。有趣的是,当我尝试通过按F12定位这个弹框在HTML中的位置时,输入框失去焦点后,联想词弹框就自动消失了。我观察到 HTML 代码中div元素也从代码中消失了。这种情况下,我该如何才能准确地定位这个元素弹框并获取其中的联想词呢?

动画.gif

解决方案

方法一:查找DOM节点

这算是最简单的操作,通过调试框可以看到网页dom结构的变化,当触发联想词弹框时,记下弹框对应标签的类名或者id,然后查找得到这个标签的html代码,从中解析出联想词。

const elementByClassName = document.querySelector(".luoxiaodou");
if (elementByClassName) {const htmlContent = elementByClassName.innerHTML;console.log(htmlContent);
}

输入框获取焦点时,联想词弹框出现,输入框失去焦点时,联想词弹框消失。咱们先给输入框添加焦点,弹框出现时,运行上面的代码获取节点对应的html内容。

这个想法很好,但是这里有一个问题:就是元素的加载需要时间,需要请求服务端获取数据,然后再加载出来。,如果是输入框获取焦点后立即去查找元素,大概率获取的结果是空,所以这中间要有延迟的时间,咱们就说这坑大家有没有踩过吧。

方法二:使用MutationObserver来监视DOM变化

我还有两个想法,第一个是:咱们能不能拦截一下网络,然后从服务器的响应里头捞点联想词出来?我个人觉得这招儿挺靠谱的,但目前还没来得及试试。等我尝试之后写一下关于监听网络请求获取联想词的内容,咱们就先记个账,到时候一定补上。

另一种方式就是使用MutationObserver来监视DOM变化,可以在控制台中编写一个JavaScript函数,当包含特定类的元素出现在DOM中时,打印出该元素的HTML内容。为此,你可以使用MutationObserver来监视DOM变化。

而我选择了另一种可能的解决方案,就是利用MutationObserver这个JavaScript API。一旦检测到DOM中有特定类的元素出现,就立即打印出它的HTML内容。MutationObserver 是 JavaScript 自带的 API,它用于监视DOM树的变化。这是浏览器原生支持的功能,包括我们常用的Chrome在内。正好在插件开发中使用。

咱们可以创建一个函数,传参是标签选择器和一个回调函数,当获取到变化的网页时,调用回调函数解析获取联想词。这里使用一个map集合,可以保证管理多个监视器,以下是实现代码:

const observers = new Map()/*** 启动监视指定选择器的元素变化。* @param {string} selector - CSS选择器,可以是类名(以`.`开头)或ID(以`#`开头)。* @param {function} callback - 回调函数,当符合选择器的元素添加到DOM时调用。*/
function startObserving(selector, callback) {/*** 观察者回调函数,监视DOM树的变化。* @param {MutationRecord[]} mutationsList - DOM变化记录的列表。* @param {MutationObserver} observer - 观察者实例。*/const observerCallback = function (mutationsList, observer) {for (const mutation of mutationsList) {if (mutation.type === 'childList') {mutation.addedNodes.forEach((node) => {if (node.nodeType === Node.ELEMENT_NODE) {if (selector.startsWith('#') && node.id === selector.slice(1)) {callback(node.outerHTML)} else if (selector.startsWith('.') && node.classList.contains(selector.slice(1))) {callback(node.outerHTML)}}})}}}// 创建一个观察者实例并开始观察指定的目标节点和配置const observer = new MutationObserver(observerCallback)// 观察配置,配置对象指定我们希望观察子节点的变化(`childList: true`)以及观察整个子树中的变化(`subtree: true`)const config = { childList: true, subtree: true }// 观察整个文档,所以将目标节点设置为`document.body`。observer.observe(document.body, config)// 将观察者存储在Map中observers.set(selector, observer)// 设置定时器,指定时间后自动停止观察并删除观察者,回收资源setTimeout(() => {stopObserving(selector)}, 5 * 60 * 1000)
}/*** 停止监视指定选择器的元素变化。* @param {string} selector - CSS选择器,可以是类名(以`.`开头)或ID(以`#`开头)。*/
function stopObserving(selector) {const observer = observers.get(selector);if (observer) {observer.disconnect();observers.delete(selector);}
}export { startObserving, stopObserving };

然后就是在使用的地方,导入这些方法,传一下参数就可以了,有一点要注意:回调函数中的参数是获取到的网页信息

import { startObserving, stopObserving } from './element-observer.js';// 通过类名启动监视
startObserving('.xiaodou-class', (htmlContent) => {console.log('Element with class added:', htmlContent);
});// 通过ID启动监视
startObserving('#xiaodou-id', (htmlContent) => {console.log('Element with ID added:', htmlContent);
});// 停止监视
setTimeout(() => {stopObserving('.xiaodou-class');stopObserving('#xiaodou-id');
}, 6000);

你是不是以为这就结束?我当时就是这么想的,但是还是有问题:从第二次开始获取到的内容是上一个输入词的联想词。假设第一次输入“猫咪”,然后获取的“猫咪”的联想词,第二次输入“狗狗”,但是获取的还是“猫咪”的联想词,第三次输入“兔兔”,这次获取的是“狗狗”的联想词,这是哪里出问题了呢?

接着咱们来分析一下原因,首先观察一下联想词弹框的变化,比如下图,修改”猫咪狸花猫“到”猫咪狸“的这个过程中,联想词弹框先出来跟”猫咪狸花猫“相关的内容, 再请求服务器获取”猫咪狸“的联想词,再更新弹框内容。
动画.gif

当页面变动时,监控页面变化的函数会立即执行,这个执行速度是优于请求服务器更新弹框内容的速度,所以这里导致获取的内容是是上一个联想词的。

发现了问题,就好修改了,可以尝试在 MutationObserver 回调函数中使用 setTimeout,以确保 DOM 完全渲染后再获取 outerHTML

/**
* 观察者回调函数,监视DOM树的变化。
* @param {MutationRecord[]} mutationsList - DOM变化记录的列表。
* @param {MutationObserver} observer - 观察者实例。
*/
const observerCallback = function (mutationsList, observer) {
for (const mutation of mutationsList) {if (mutation.type === 'childList') {mutation.addedNodes.forEach((node) => {if (node.nodeType === Node.ELEMENT_NODE) {if (selector.startsWith('#') && node.id === selector.slice(1)) {// 使用 setTimeout 确保 DOM 完全渲染后获取 outerHTMLsetTimeout(() => callback(node.outerHTML), 1000);} else if (selector.startsWith('.') && node.classList.contains(selector.slice(1))) {// 使用 setTimeout 确保 DOM 完全渲染后获取 outerHTMLsetTimeout(() => callback(node.outerHTML), 1000);}}});}
}

这里确实解决了问题,但是我还有一个疑问:为什么在修改”猫咪狸花猫“到”猫咪狸“的这个过程中,弹框内容有两次变化,观察者只触发了一次?,在上面的观察者配置是希望观察子节点的变化以及观察整个子树中的变化,这个变化不包含节点内容的变化,不知道这样理解对不对?


做完这些,我觉得监听网络请求或更好操作一点,不知道监听网络请求又会遇到哪些坑……

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/347576.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【PowerDesigner】PDM生成REPORT

目录 🌊1. PowerDesigner简介 🌍1.1 常用模型文件 🌍1.2 PowerDesigner使用环境 🌊2. PDM生成REPORT 🌊3. 研究心得 🌊1. PowerDesigner简介 🌍1.1 常用模型文件 主要使用PowerDesigner的…

你觉得前端开发人员有必要学习Rust吗?

有必要,为什么? 1. 性能优势 Rust能编译成高效的机器码,这对于需要高性能处理的前端项目尤其有利。例如,处理复杂的数据计算或图像处理时,Rust可以提供接近于C/C的性能,同时避免诸如内存泄漏或缓冲区溢出…

外汇天眼:Equals集团发布战略评估通知:MDP不再考虑收购提议

Equals Group plc (LON)今天发布了一份关于其战略评估的通知。 Equals公司不再与Madison Dearborn Partners, LLC (MDP)就公司的收购提议进行讨论。MDP因此发布了一份声明,确认其不打算为公司提出收购提议。 然而,MDP与其投资组合公司MoneyGram Interna…

Vue 面试通杀秘籍

理论篇: 1. 说说对 Vue 渐进式框架的理解(腾讯医典) a) 渐进式的含义: 主张最少, 没有多做职责之外的事 b) Vue 有些方面是不如 React,不如 Angular.但它是渐进的,没有强主张, 你可以在原有…

LogicFlow 学习笔记——1. 初步使用 LogicFlow

什么是 LogicFlow LogicFlow 是一个开源的前端流程图编辑器和工作流引擎,旨在帮助开发者和业务人员在网页端创建、编辑和管理复杂的业务流程和工作流。它提供了一个直观的界面和强大的功能,使得设计和管理工作流变得更加高效和便捷。 官网地址&#xff…

RN:Error: /xxx/android/gradlew exited with non-zero code: 1

问题 执行 yarn android 报错: 解决 这个大概率是缓存问题,我说一下我的解决思路 1、yarn doctor 2、根据黄色字体提示,说我包版本不对(但是这个是警告应该没事,但是我还是装了) npx expo install --…

企事业单位安全生产月活动怎样向媒体投稿?

作为一名单位的信息宣传员,我肩负着将每一次重要活动的精彩瞬间转化为文字,向外界传递我们单位声音的重任。初入此行时,我满怀热情,坚信通过传统的方式——电子邮件投稿,能够有效地将我们的故事传播出去。然而,现实却给我上了生动的一课。 记得在筹备“安全生产月”活动的宣传时…

Ubuntu22.04之解决:emacs无法输入中文问题(二百四十)

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 优质专栏:多媒…

代码随想录 | Day18 | 二叉树:完全二叉树的节点个数平衡二叉树

代码随想录 | Day18 | 二叉树:完全二叉树的节点个数&&平衡二叉树 主要学习内容: 1.完全二叉树的性质,满二叉树的节点数量的计算 2.树的高度和深度问题要用后序遍历更加合适 222.完全二叉树的节点个数 222. 完全二叉树的节点个数…

MT2096 数列分段

代码&#xff1a; #include <bits/stdc.h> using namespace std; const int N 1e5 10; int n, m; int a[N]; int ans 1; int main() {cin >> n >> m;for (int i 1; i < n; i)cin >> a[i];int num 0;for (int i 1; i < n; i){if (num a[i…

【QT】记录一次QT程序发布exe过程

记录一次QT程序发布exe过程 使用windeploy与enigma发布独立的QT程序第一步 QT编译输出 **release** 版本第二步 QT 自带 windepoyqt 补全链接库第三步 enigma virtual box压缩打包为单一exe最后【2024-06-07 17】- 【补充】 贴一个自己用的bat脚本【**QtDeploy2exe.bat**】半自…

6月11号作业

思维导图 #include <iostream> using namespace std; class Animal { private:string name; public:Animal(){}Animal(string name):name(name){//cout << "Animal&#xff1b;有参" << endl;}virtual void perform(){cout << "讲解员的…

WordPress——Argon主题美化

文章目录 Argon主题美化插件类类别标签页面更新管理器文章头图URL查询监视器WordPress提供Markdown语法评论区头像设置发信设置隐藏登陆备份设置缓存插件 主题文件编辑器页脚显示在线人数备案信息(包含备案信息网站运行时间)banner下方小箭头滚动效果站点功能概览下方Links功能…

Spring Boot入门

目录 前言 1.安装Spring Boot Help插件 1.1查找插件并下载 2.2安装插件 2.Idea创建SpringBoot项⽬ 3.其他方式创建SpringBoot项⽬ 3.1 Spring 官网创建 3.2 阿里云创建 3.3 不基于任何页面&#xff0c;插件进行创建 4.⽬录介绍 5.项目启动 5.1项目启动前可能会遇到…

统计绘图 | 既能统计分析又能可视化绘制的技能

在典型的探索性数据分析工作流程中&#xff0c;数据可视化和统计建模是两个不同的阶段&#xff0c;而我们也希望能够在最终的可视化结果中将相关统计指标呈现出来&#xff0c;如何让将两种有效结合&#xff0c;使得数据探索更加简单快捷呢&#xff1f;今天这篇推文就告诉你如何…

Nginx 网站服务

一.Nginx 概述 1.一款高性能、轻量级Web服务软件 稳定性高 系统资源消耗低 对HTTP并发连接的处理能力高 单台物理服务器可支持30000~5000个并发请求 2.Nginx与Apache区别 最核心的区别在于 Nginx 采用异步非阻塞机制&#xff0c;多个连接可以对应一个进程&#xff1b;Apache 采…

HyperAI超神经 x MoonBit | 与中科院、Intel 等专家共话基础软件前沿发展与期待

本次 Meetup 将讨论 MoonBit 编程语言、RuyiSDK、WAMR和 RISC-V 等技术&#xff0c;来现场参与不仅可以学习到最前沿的技术知识&#xff0c;更可与大咖面对面互动交流心得&#xff0c;还有美食茶歇与精美礼品&#xff0c;期待你的到来&#xff01; 扫码立即报名 ⬇️ 活动详情…

自动驾驶#芯片-1

概述 汽车是芯片应用场景之一&#xff0c;汽车芯片需要具备车规级。  车规级芯片对加工工艺要求不高&#xff0c;但对质量要求高。需要经过的认证过程&#xff0c;包括质量管理标准ISO/TS 16949、可靠性标准 AEC-Q100、功能安全标准ISO26262等。  汽车内不同用途的芯片要求…

SAP CS01/CS02/CS03 BOM创建维护删除BAPI使用及增强改造

BOM创建维护删除相关BAPI的使用代码参考示例&#xff0c;客户电脑只能远程桌面&#xff0c;代码没法复制粘贴出来&#xff0c;只能贴图。 创建及修改BAPI: CSAP_MAT_BOM_MAINTAIN。 删除BAPI: CSAP_MAT_BOM_DELETE。 改造BAPI: CSAP_MAT_BOM_MAINTAIN 改造点1&#xff1a;拷…

贪吃蛇小游戏简单制作-C语言

文章目录 游戏背景介绍实现目标适合人群所需技术浅玩Window API什么是API控制台程序窗口大小,名称设置 Handle(句柄)获取句柄 坐标结构体设置光标位置 光标属性获取光标属性设置光标属性 按键信息获取 贪吃蛇游戏设计游戏前的初始化设置窗口的大小和名称本地化设置 宽字符Waht …