爬虫知识:补环境相关知识

学习目标:知道为什么要补环境,知道要补什么环境(使用Proxy检测)。没有讲解怎么补

本章没有动手去实操,只是纯理论知识

补环境介绍

DOM与BOM

DOM主要关注文档内容和结构,而BOM关注浏览器窗口和功能。在浏览器中,window对象既是BOM的核心,也是全局对象,而document对象(DOM的核心)是window对象的一个属性。

浏览器环境:指JS代码在浏览器中的运行时环境

  1. V8引擎自动构建的对象(即ECMAScript规范的内容,如Date、Array)
  2. 浏览器(内置)提供给V8引擎用于操作DOM和BOM的对象(如document、navigator)

Node环境:基于V8引擎的JavaScript运行时环境

  1. V8引擎提供的核心JavaScript功能
  2. Node.js自身的API,如fs(文件系统), http(网络请求), path(路径处理)等

环境对比

浏览器环境Node环境
JavaScript引擎V8(Chrome)V8
全局对象windowglobal
DOM API无(可通过第三方库模拟)
BOM API无(可通过第三方库模拟)
文件系统访问文件系统访问完全访问(fs模块)
网络功能XMLHttpRequest, Fetchhttp, https模块
定时器setTimeout, setIntervalsetTimeout, setInterval
console浏览器控制台终端输出
模块系统ES Modules, CommonJSCommonJS, ES Modules
典型用途前端Web开发服务器端开发,工具脚本

"补浏览器环境" :实际上是指补充浏览器环境中存在而Node环境中缺失的部分,主要是BOM(浏览器对象模型)和DOM(文档对象模型)相关的对象和API。

当我们成功提取出网站中的JavaScript加密算法代码,并确认其在浏览器环境中能够正确执行后,下一步是将其迁移到Node环境中执行。然而,由于Node环境与浏览器环境之间存在差异,可能会导致某些JavaScript代码在这两种环境中的执行结果不一致,这可能会影响我们的逆向工程成果。

window对象

window对象是JavaScript中的全局对象,在浏览器环境中代表了当前打开的浏览器窗口。它是所有全局JavaScript对象、函数和变量的顶层容器。以下是window对象的一些重要特性和用途:

在爬虫和反爬context中,window对象尤为重要:

  • 许多网站使用window对象的属性来检测是否在真实浏览器环境中运行。
  • 一些反爬措施会检查window对象的特定属性或方法是否存在或行为是否正常。
  • 在补环境时,常常需要模拟window对象及其众多属性和方法,以欺骗网站的检测机制。

需要注意的是,在Node.js等非浏览器环境中,默认是没有window对象的。在这些环境中补充window对象是模拟浏览器环境的重要步骤。

常见对象

  1. document对象:代表整个HTML文档
    • 包含了操作DOM的方法和属性
    • 例如:getElementById(), createElement(), querySelector(),cookie等
  2. location对象:包含有关当前URL的信息
    • 如href, protocol, host, pathname, search, hash等
    • 还有方法如assign(), replace(), reload()等
  3. history对象:包含浏览器的历史记录信息
    • 方法如back(), forward(), go()等
  4. navigator对象:包含有关浏览器的信息
    • 如userAgent, platform, language等
  5. screen对象:包含有关用户屏幕的信息
    • 如width, height, availWidth, availHeight等
  6. localStorage对象:提供本地存储功能
  7. sessionStorage对象:提供会话存储功能
  8. console对象:提供控制台调试功能
    • 如log(), error(), warn()等方法
  9. setTimeout和setInterval:用于设置定时器的函数
  10. alert(), confirm(), prompt():用于创建对话框的方法
  11. JSON对象:用于JSON数据的解析和序列化
  12. Math对象:提供数学计算相关的方法和常量
  13. Date对象:用于日期和时间操作
  14. Array, String, Number等基本对象的构造函数
  15. XMLHttpRequest或fetch:用于网络请求
  16. performance对象:用于性能相关的测量
  17. WebSocket:用于全双工通信

爬虫重点关注的对象

  1. document对象
    • 用于解析和操作页面内容
    • 重要方法:querySelector(), getElementById(), getElementsByClassName(),cookie 等
    • 用于提取目标数据
  2. location对象
    • 用于获取和操作URL
    • 重要属性:href, pathname, search, hash
    • 用于页面导航和URL解析
  3. navigator对象
    • 用于伪造浏览器信息
    • 重要属性:userAgent, platform, language
    • 常用于反爬绕过
  4. history对象
    • 模拟浏览历史
    • 方法如back(), forward()
    • 用于模拟真实用户行为
  5. localStorage 和 sessionStorage
    • 用于存储和获取网站可能用于验证的数据
    • 模拟持久化存储
  6. XMLHttpRequest 或 fetch
    • 用于发送网络请求
    • 模拟AJAX调用
  7. setTimeout 和 setInterval
    • 用于处理异步操作和定时任务
    • 模拟页面加载和动态内容
  8. window.crypto
    • 用于处理加密操作
    • 某些网站可能用于生成特定的加密参数
  9. performance对象
    • 用于模拟真实的页面加载性能指标
  10. screen对象
    • 用于模拟屏幕分辨率等信息
  11. console对象
    • 用于调试和日志输出
    • 某些网站可能会检查console的行为

在爬虫中,这些对象主要用于以下目的:

  1. 数据提取:使用document对象解析页面结构,提取所需信息。
  2. 请求伪造:使用navigator和其他对象伪造浏览器特征,绕过反爬检测。
  3. 模拟交互:使用history、setTimeout等模拟用户行为。
  4. 处理动态内容:应对JavaScript渲染的页面,需要模拟完整的浏览器环境。
  5. 绕过反爬措施:某些反爬技术会检查这些对象的存在性和行为,需要精确模拟。

在实际爬虫开发中,根据目标网站的特性和反爬措施,可能需要重点关注和模拟其中的一部分对象。通常,越是复杂的网站,需要模拟的对象和行为就越多。


Proxy对象

从上面的知识点可以看出,我们本地模拟浏览器需要各式各样的对象属性,而怎么确定使用什么对象,就要使用Proxy来进行观察了。

为什么使用Proxy

a) 环境模拟:Node.js环境与浏览器环境不同,缺少许多浏览器特有的对象和方法(如window、document等)。使用Proxy可以模拟这些缺失的对象和方法。

b) 动态监控:Proxy允许我们拦截和自定义对象的基本操作,如属性查找、赋值、枚举等。这使我们能够动态地监控和修改JS代码的行为。

c) 按需补充:我们可以只补充代码实际需要的部分,而不是完整模拟整个浏览器环境,这样更加高效。

d) 灵活性:Proxy提供了一种灵活的方式来处理未知的属性访问,这在处理复杂的反爬逻辑时非常有用。

Proxy如何工作

Proxy对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义。在补充JS环境时,我们通常会这样使用它:

  • 这段代码创建了一个假的window对象。当代码尝试访问window的属性时,Proxy会:
    • 首先检查自己是否有这个属性
    • 如果没有,检查全局对象是否有这个属性
    • 如果全局对象也没有,返回一个空函数,防止代码报错

优势

a) 精确控制:我们可以精确控制每个属性的行为,包括读取、写入和方法调用。

b) 调试便利:通过Proxy,我们可以轻松记录所有被访问的属性,这对于理解和调试目标JS代码非常有帮助。

c) 性能优化:相比完全模拟整个浏览器环境,使用Proxy按需模拟可以显著提高性能。

d) 适应性强:对于未知或复杂的环境依赖,Proxy提供了一种灵活的处理方式。

实际应用

在爬虫中,我们通常会遇到需要执行目标网站JS代码的情况,特别是在处理加密参数时。使用Proxy可以让我们在Node.js环境中"骗过"这些JS代码,使其以为自己是在浏览器中运行,从而正确执行并得到我们需要的结果。

Proxy对象的基本语法

let proxy = new Proxy(target, handler);

这里有两个主要参数:

  1. target: 这是要代理的原始对象。可以是任何类型的对象,包括数组、函数,甚至另一个代理。
  2. handler: 这是一个对象,其属性是定义代理行为的函数。这些函数被称为"捕获器"(traps)。

handler对象可以定义以下主要的捕获器:

  • get(target, property, receiver): 用于拦截对象属性的读取操作。
  • set(target, property, value, receiver): 用于拦截对象属性的设置操作。
  • has(target, prop): 用于拦截 in 操作符。
  • deleteProperty(target, property): 用于拦截删除操作。
  • apply(target, thisArg, argumentsList): 用于拦截函数调用。
  • construct(target, argumentsList, newTarget): 用于拦截 new 操作符。

代码示例

在这个例子中:

  1. target 是我们要代理的原始对象。
  2. handler 定义了如何拦截对对象的操作。
  3. 我们定义了 get 和 set 捕获器来拦截读取和设置属性的操作。
  4. 当我们通过代理对象访问或修改属性时,相应的捕获器会被调用。
// 目标对象
let target = {name: "John",age: 30
};// 处理器对象
let handler = {// 拦截读取属性操作get: function(obj, prop) {console.log(`正在获取 ${prop} 属性`);return prop in obj ? obj[prop] : `${prop} 不存在`;},// 拦截设置属性操作set: function(obj, prop, value) {console.log(`正在设置 ${prop} 属性为 ${value}`);obj[prop] = value;return true;}
};// 创建代理
let proxy = new Proxy(target, handler);// 使用代理
console.log(proxy.name);  // 输出: 正在获取 name 属性 \n John
console.log(proxy.age);   // 输出: 正在获取 age 属性 \n 30
console.log(proxy.job);   // 输出: 正在获取 job 属性 \n job 不存在proxy.name = "Jane";      // 输出: 正在设置 name 属性为 Jane
console.log(proxy.name);  // 输出: 正在获取 name 属性 \n Jane

 这就是Proxy的基本工作原理。在更复杂的场景中,比如模拟浏览器环境,我们可以使用这种机制来创建看起来像浏览器对象(如window、document等)的对象,并控制对这些对象的访问和修改。

Proxy实验

运行测试

创建demo.js,打开命令行终端,导航到您保存 demo.js 文件的目录,然后运行以下命令:

node demo.js

// 创建一个模拟的window对象
const fakeWindow = new Proxy({}, {get: function(target, property) {console.log(`Accessing property: ${property}`);if (property in target) {return target[property];} else if (typeof global[property] !== 'undefined') {return global[property];} else {// 模拟缺失的属性或方法return () => console.log(`Called method: ${property}`);}},set: function(target, property, value) {console.log(`Setting property: ${property} = ${value}`);target[property] = value;return true;}});// 测试访问属性console.log(fakeWindow.navigator);// 测试设置属性fakeWindow.location = 'https://example.com';// 测试调用方法fakeWindow.alert('Hello, world!');// 测试访问真实的全局属性console.log(fakeWindow.console === console);  // 应该返回 true// 测试访问不存在的属性fakeWindow.nonExistentMethod();

观察结果

这个输出展示了Proxy如何拦截和处理各种操作:

  • 访问属性(navigator, console)
  • 设置属性(location)
  • 调用方法(alert, nonExistentMethod)
  • 处理存在和不存在的属性
Accessing property: navigator
undefined
Setting property: location = https://example.com
Accessing property: alert
Called method: alert
Accessing property: console
true
Accessing property: nonExistentMethod
Called method: nonExistentMethod

更多的检测功能

代码包含了以下功能:

  1. 模拟window对象
  2. 模拟document对象
  3. 处理cookie的特殊逻辑
  4. 记录所有属性的访问和设置
  5. 模拟不存在的方法
  6. 访问真实的全局属性
// 创建一个模拟的window对象
const fakeWindow = new Proxy({document: new Proxy({_cookie: '',}, {get: function(target, property) {console.log(`Accessing document property: ${property}`);if (property === 'cookie') {console.log('Reading cookie');return target._cookie;}return target[property];},set: function(target, property, value) {console.log(`Setting document property: ${property} = ${value}`);if (property === 'cookie') {console.log(`Setting cookie: ${value}`);target._cookie = value;} else {target[property] = value;}return true;}})
}, {get: function(target, property) {console.log(`Accessing window property: ${property}`);if (property in target) {return target[property];} else if (typeof global[property] !== 'undefined') {return global[property];} else {// 模拟缺失的属性或方法return () => console.log(`Called window method: ${property}`);}},set: function(target, property, value) {console.log(`Setting window property: ${property} = ${value}`);target[property] = value;return true;}
});// 测试访问window属性
console.log(fakeWindow.navigator);// 测试设置window属性
fakeWindow.location = 'https://example.com';// 测试调用window方法
fakeWindow.alert('Hello, world!');// 测试访问真实的全局属性
console.log(fakeWindow.console === console);  // 应该返回 true// 测试访问不存在的window属性
fakeWindow.nonExistentMethod();// 测试document.cookie
fakeWindow.document.cookie = 'user=john';
console.log(fakeWindow.document.cookie);// 测试访问其他document属性
fakeWindow.document.title = 'Test Page';
console.log(fakeWindow.document.title);

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

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

相关文章

2023 联邦推荐系统综述

本博客结合2023年发表的综述文章,对近期一些联邦推荐文章进行总结,综述原文: SUN Z, XU Y, LIU Y, et al. A Survey on Federated Recommendation Systems[J]. 2023.https://doi.org/10.48550/arXiv.2301.00767 引言 最近,已有许多…

【linux网络(六)】IP协议详解

💓博主CSDN主页:杭电码农-NEO💓   ⏩专栏分类:Linux从入门到精通⏪   🚚代码仓库:NEO的学习日记🚚   🌹关注我🫵带你学更多操作系统知识   🔝🔝 Linux网络 1. 前言2. IP协议报…

链家房屋数据爬取与预处理-大数据采集与预处理课程设计

芜湖市链家二手房可视化平台 成品展示 重点说明 1.数据特征数量和名称、数据量 数据特征数量:14; 名称:小区名、价格/万、地区、房屋户型、所在楼层、建筑面积/平方米、户型结构、套内面积、建筑类型、房屋朝向、建筑结构、装修情况、梯户…

(上位机APP开发)调用华为云命令API接口给设备下发命令

一、功能说明 通过调用华为云IOT提供的命令下发API接口,实现下面界面上相同的功能。调用API接口给设备下发命令。 二、JavaScript代码 function sendUnlockCommand() {var requestUrl = "https://9bcf4cfd30.st1.iotda-app.cn-north-4.myhuaweicloud.com:443/v5/iot/60…

Springboot 整合 DolphinScheduler(一):初识海豚调度

目录 一、什么是 DolphinScheduler 二、DolphinScheduler 的特性 三、DolphinScheduler 核心架构 四、单机环境部署流程 1、下载安装包 2、上传至服务器,解压缩 3、单机启动 4、登录 dolphinscheduler UI 5、配置数据库【非必需】 (1&#xff…

前端:Nuxt3 + Vuetify3 + Element Plus + 添加常用插件

想要开发一个网站,并且支持SEO搜索,当然离不开我们的 Nuxt ,那通过本篇文章让我们一起了解一下。让我们一起来构建下 Nuxt3 集成其它插件 目录 安装 Nuxt3,创建项目 一、搭建脚手架 二、添加 Vuetify 3 2.1、安装 Vuetify 3 …

如何将一个web端程序打包成一个pc端程序(exe文件)?

如何将一个Web端程序打包成一个PC端程序,例如一个可执行的EXE文件,是许多开发者常见的需求。下面将详细解释如何使用Nativefier工具将Web端程序打包成PC端程序的具体步骤。 目录 下载并安装Node.js验证Node.js和npm的安装安装Nativefier使用Nativefier打…

革新校园环境:轻空间打造上海六十中学多功能气膜馆

在现代教育环境中,舒适、环保和多功能的建筑越来越受到重视。上海六十中学多功能气膜馆的建设正如火如荼地进行中,这个项目由轻空间(江苏)膜科技有限公司全力打造,将为学校师生带来全新的活动体验。 项目进展 自项目启…

量子计算的崛起:开启计算新纪元

人不走空 🌈个人主页:人不走空 💖系列专栏:算法专题 ⏰诗词歌赋:斯是陋室,惟吾德馨 目录 🌈个人主页:人不走空 💖系列专栏:算法专题 ⏰诗词歌…

使用命令行工具测试主机到FTP网络

使用命令行工具测试FTP服务器上的文件权限,通常涉及登录到FTP服务器并尝试执行一些基本的FTP命令来检查和交互。以下是一个基本步骤指南,假设你正在使用Linux或MacOS系统的命令行界面,并且你的FTP服务器已经设置好且可以访问: 准…

基于SpringBoot小区物业智能卡管理设计和实现(源码+LW+调试文档+讲解等)

💗博主介绍:✌全网粉丝10W,CSDN作者、博客专家、全栈领域优质创作者,博客之星、平台优质作者、专注于Java、小程序技术领域和毕业项目实战✌💗 🌟文末获取源码数据库🌟感兴趣的可以先收藏起来,还…

MySQL 外连接、内连接与自连接的区别?

引言:本文将深入探讨这些连接类型的概念、语法及其应用场景,帮助读者全面理解如何利用这些技术实现复杂的数据查询和分析。在数据库查询中,连接操作使得我们可以根据指定的关联条件(join condition)联合两个或多个表中…

【华为OD机试】 硬件产品销售方案(C++/Java/Python)

题目 题目描述 某公司目前推出了AI开发者套件,AI加速卡,AI加速模块,AI服务器,智能边缘多种硬件产品,每种产品包含若干个型号。 现某合作厂商要采购金额为_amount_元的硬件产品搭建自己的AI基座。 例如当前库存有_N_种产品,每种产品的库存量充足,给定每种产品的价格,记为…

MySQL 5.x和8.0区别

1、性能:8.0的速度要比5.7快2倍,8.0在以下方面带来了更好的性能:读/写负载、IO密集型工作负载、高竞争("hot spot"热点竞争问题)工作负载。 2、NoSQL:5.7 版本开始提供NoSQL存储功能&#xff0c…

智能分析赋能等保:大数据技术在安全审计记录中的应用

随着信息技术的飞速发展,大数据技术在各行各业中的应用愈发广泛,特别是在网络安全领域,大数据技术为安全审计记录提供了强有力的支撑。本文将深入探讨智能分析如何赋能等保(等级保护),以及大数据技术在安全…

昇思25天学习打卡Day01

实验结果 心得体会 趁着假期,跟谁官方实战营开始系统学习MindSpore深度学习框架。昇思MindSpore是一个全场景深度学习框架,旨在实现易开发、高效执行、全场景统一部署三大目标。其中易开发表现为API友好,调试难度低;高效执行包括…

2024-06-24力扣每日一题

链接: 503. 下一个更大元素 II 题意 循环数组,找出每个元素的往后最近且大于它的元素 解: 今天没试暴力啊,大概率是过不了的 思路就是先找到最大的数,最大数的结果肯定是-1,然后倒着遍历数组&#xf…

C++中的引用定义以及它与指针有何不同?

在C中,引用是一种特殊的别名,用于表示另一个已存在的变量。引用一旦定义,就不能再引用其他变量,即它始终指向同一个对象。引用主要用于作为函数参数和返回类型,以提高效率,因为它不涉及指针的解引用操作。 …

C语言常用标准头文件

头文件的基础概念 在C的系列语言程序中,头文件(通常扩展名为.h)被大量使用,它通常包含函数、变量、结构体等的声明和定义,以及一些宏定义和类型定义。头文件的主要作用是为了方便管理和重用代码,它可以被多…

c++分隔字符串

可以使用getline函数。 有两个版本: 至于为什么可以使用getline函数返回值作为while的判断条件,cprimer中表述如下: