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

news2024/11/15 17:36:51

前几天在做数据分析时,我尝试获取某网站上输入搜索词后的联想词,输入搜索词后会弹出一个显示联想词的框。有趣的是,当我尝试通过按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 完全渲染后获取 outerHTML
          setTimeout(() => callback(node.outerHTML), 1000);
        } else if (selector.startsWith('.') && node.classList.contains(selector.slice(1))) {
          // 使用 setTimeout 确保 DOM 完全渲染后获取 outerHTML
          setTimeout(() => callback(node.outerHTML), 1000);
        }
      }
    });
  }
}

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


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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

UnityAPI学习之Animator的基本使用

动画与动画控制器 示例1: 创建Animator对动画控制器进行统一管理,在Gris中创建Animator组件,并对其中的Controller属性进行赋值 在进行动画创作前,需先将图片的Texture Type属性改为Sprite(2D and UI) 再将一系列图片拖入Gris物…

nss刷题(4)

1、[SWPUCTF 2021 新生赛]easyrce <?php error_reporting(0); highlight_file(__FILE__); if(isset($_GET[url])) { eval($_GET[url]); } ?> if(isset($_GET[url])) isset函数用来检测url变量是否存在&#xff1b;$_GET函数获取变量数据 eval($_GET[url]); eval函数用…

基于Java+Swing+mysql幼儿园信息管理系统V2

博主介绍&#xff1a; 大家好&#xff0c;本人精通Java、Python、C#、C、C编程语言&#xff0c;同时也熟练掌握微信小程序、Php和Android等技术&#xff0c;能够为大家提供全方位的技术支持和交流。 我有丰富的成品Java、Python、C#毕设项目经验&#xff0c;能够为学生提供各类…

和鲸101领航北中医:助力健康医疗AI实验室建设,培养交叉数据人才

2024 年 3 月开学季&#xff0c;北京中医药大学&#xff08;简称“北中医”&#xff09;的健康医疗人工智能实验室迎来了正式投入使用后的第一堂课。除了配备全新的桌椅和尖端的硬件服务器外&#xff0c;实验室还引入了先进的人工智能实训平台&#xff0c;为大数据管理与应用专…

Linux1(介绍与基本命令)

目录 一、初始Linux 1. Linux的起源 2. Linux是什么&#xff1f; 3. Linux内核版本 4. Linux的应用 5. 终端 6. Shell 7. Linux目录结构 二、基本命令 1. 基本的命令格式 2. shutdown 关机命令 3. pwd 当前工作目录 4. ls 查看目录内容 5. cd 改变工作目录 …

【制作100个unity游戏之27】使用unity复刻经典游戏《植物大战僵尸》,制作属于自己的植物大战僵尸随机版和杂交版10(附带项目源码)

最终效果 系列导航 文章目录 最终效果系列导航前言使用DoTween优化阳光生成和拾取效果拾取阳光优化生成阳光优化 场景加载进度条新增加载场景Loading&#xff0c;绘制开始界面绘制菜单界面滑动滚轮一直滚动 场景加载源码结束语 前言 本节主要实现使用DoTween优化阳光生成和拾取…

Linux运维实用小脚本,登录即自动显示系统信息

systeminfo.sh #!/bin/bash # systeminfo.sh # by 运维朱工 # site&#xff1a;bash.lutixia.cn ##################################### 获取IP地址和主机名 IP_ADDR$(hostname -I | cut -d -f1) HOSTNAME$(hostname)# CPU负载信息&#xff1a; cpu_load() {echo -e "\…

JAVA基础--MAVEN

MAVEN的认识 什么是MAVEN Maven是一个项目构建及管理工具&#xff0c;开发团队几乎不用花多少时间就能够自动完成工程的基础构建配置&#xff0c; Maven 使用了一个标准的目录结构在不同开发工具中也能实现项目结构的统一。 统一项目结构 Maven提供了清理&#xff0c;编译&a…

【二进制部署k8s-1.29.4】十三、metrics-server的安装部署

文章目录 简介 一.metrics-server的安装 简介 本章节主要讲解metrics-server的安装&#xff0c;metrics-server主要是用于采集k8s中节点和pod的内存和cpu指标&#xff0c;在观察几点和pod的实时资源使用情况还是比较有用的&#xff0c;如果需要记录历史信息&#xff0c;建议采用…

Java到AI大模型,我为什么选择的后者

我为什么从Java转到AI大模型 在编程的海洋里&#xff0c;Java一直是我信赖的“小船”&#xff0c;载着我航行在代码的世界中。然而&#xff0c;随着行业的不断发展和变化&#xff0c;我开始感受到了一丝的迷茫和不安。我开始担心&#xff0c;随着技术的不断更新&#xff0c;Ja…

材料科学基础:期末计算题(第6章)结晶驱动力与过冷度

材料科学基础&#xff1a;计算题&#xff08;第6章&#xff09; 结晶驱动力与过冷度 ∆ G < 0 ; G H − T S ∆G<0; GH-TS ∆G<0;GH−TS d G d T d H d T − S − T d S d T \frac{dG}{dT}\frac{dH}{dT}-S-T\frac{dS}{dT} dTdG​dTdH​−S−TdTdS​ d G d T d H d …

B站画质补完计划(3):智能修复让宝藏视频重焕新生

1 老片存在什么画质问题&#xff1f; B站作为一个拥有浓厚人文属性的平台社区&#xff0c;聚集了诸如《雍正王朝》、《三国演义》等经典影视剧集&#xff0c;同时也吸引了大量用户欣赏、品鉴这些人文经典 。但美中不足的是&#xff0c;由于拍摄年代久远、拍摄设备落后、数据多次…

一次会见苹果App Review专家的在线研讨会

本篇我们来聊聊一次会见苹果App Review专家的见闻&#xff0c;希望能够借助本次会见的内容纪要分享&#xff0c;给广大出海的iOS开发者提供一些有价值的资讯信息&#xff0c;帮助大家都能够轻松应对App的每一次审核。 近期&#xff0c;小编收到了来自苹果设计开发加速器的邀请…

园区无线网新架构:无CAPWAP的集中式转发

1、从经典的APAC组网说起 谈及园区无线网&#xff0c;大家脑子里不免会蹦出同一个关键词。 没错&#xff0c;市面上常见的中大型企业/园区的无线网络组网方案&#xff0c;大多都是基于集中式网关转发的”APAC”模式。 顾名思义&#xff0c;该架构包括 AP 和AC两个关键角色。 …

力扣每日一题 6/12 + 随机一题

博客主页&#xff1a;誓则盟约系列专栏&#xff1a;IT竞赛 专栏关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ 2806.取整够买后的账户余额【简单】 题目&#xff1a; 一开始&#xff0c;你…

脾虚,人就废了一半!脾虚分3种,分清是哪一种,才能对症补脾!

入夏养什么&#xff1f;除心之外&#xff0c;还要多养养脾胃&#xff01;因为夏季暑热潮湿&#xff0c;加上天气变热后&#xff0c;大家喜欢吃冰的食物&#xff01;“喜燥恶湿”的脾胃在夏季就很容易受伤&#xff0c;导致脾虚&#xff01; 中医认为&#xff0c;脾主运化&#x…

ArcGIS Pro 3.0加载在线高德地图

1、打开ArcGIS Online官网&#xff0c;登录自己的账号&#xff0c;登录后效果如下图所示 官网地址&#xff1a;https://www.arcgis.com/home/webmap/viewer.html 2、点击Add&#xff0c;选择Add Layer from Web&#xff0c;如下图所示 3、在显示的Add Layer from Web页面内&am…

GA/T 1400 (非标)视图库网关

GA/T 1400 &#xff08;非标&#xff09;视图库网关 应用概述&#xff1a; GAT1400视图库网关产品是公司“分布式综合安防管理平台”下的子系统 针对以下遇到应用场景定制开发、优化后形成的网关产品&#xff0c;具备兼容性高、可扩展、可功能定制、可OEM等优点。 视图库网关…

python中魔术方法__str__与__repr__的区别

在Python中&#xff0c;__str__和__repr__是两个常见的魔法方法&#xff08;也称为双下方法或dunder方法&#xff09;&#xff0c;它们用于定义对象的字符串表示形式。它们的主要区别在于它们的用途和使用场景。 __str__ 用途&#xff1a;__str__方法用于为用户提供一个易读的…

适合营销的叙事可视化

背景 数据可视化与数据故事化的差异和相似点&#xff0c;以及它们如何协同工作&#xff0c;将你的数据转化为清晰、简洁、可操作的信息&#xff0c;以便您的组织使用。 什么是数据可视化&#xff1f; 数据可视化通过图像传达信息——这是你所收集数据的视觉表示。通过提供原…