做加工都在哪个网站推广,wordpress个人中心,wordpress建网站,代写软文学习目标#xff1a;知道为什么要补环境#xff0c;知道要补什么环境#xff08;使用Proxy检测#xff09;。没有讲解怎么补
本章没有动手去实操#xff0c;只是纯理论知识
补环境介绍
DOM与BOM
DOM主要关注文档内容和结构#xff0c;而BOM关注浏览器窗口和功能。在浏…学习目标知道为什么要补环境知道要补什么环境使用Proxy检测。没有讲解怎么补
本章没有动手去实操只是纯理论知识
补环境介绍
DOM与BOM
DOM主要关注文档内容和结构而BOM关注浏览器窗口和功能。在浏览器中window对象既是BOM的核心也是全局对象而document对象DOM的核心是window对象的一个属性。 浏览器环境指JS代码在浏览器中的运行时环境
V8引擎自动构建的对象即ECMAScript规范的内容如Date、Array浏览器内置提供给V8引擎用于操作DOM和BOM的对象如document、navigator
Node环境基于V8引擎的JavaScript运行时环境
V8引擎提供的核心JavaScript功能Node.js自身的API如fs文件系统, http网络请求, path路径处理等
环境对比
浏览器环境Node环境JavaScript引擎V8ChromeV8全局对象windowglobalDOM API有无可通过第三方库模拟BOM API有无可通过第三方库模拟文件系统访问文件系统访问完全访问fs模块网络功能XMLHttpRequest, Fetchhttp, https模块定时器setTimeout, setIntervalsetTimeout, setIntervalconsole浏览器控制台终端输出模块系统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对象是模拟浏览器环境的重要步骤。
常见对象
document对象代表整个HTML文档 包含了操作DOM的方法和属性例如getElementById(), createElement(), querySelector(),cookie等location对象包含有关当前URL的信息 如href, protocol, host, pathname, search, hash等还有方法如assign(), replace(), reload()等history对象包含浏览器的历史记录信息 方法如back(), forward(), go()等navigator对象包含有关浏览器的信息 如userAgent, platform, language等screen对象包含有关用户屏幕的信息 如width, height, availWidth, availHeight等localStorage对象提供本地存储功能sessionStorage对象提供会话存储功能console对象提供控制台调试功能 如log(), error(), warn()等方法setTimeout和setInterval用于设置定时器的函数alert(), confirm(), prompt()用于创建对话框的方法JSON对象用于JSON数据的解析和序列化Math对象提供数学计算相关的方法和常量Date对象用于日期和时间操作Array, String, Number等基本对象的构造函数XMLHttpRequest或fetch用于网络请求performance对象用于性能相关的测量WebSocket用于全双工通信
爬虫重点关注的对象
document对象 用于解析和操作页面内容重要方法querySelector(), getElementById(), getElementsByClassName(),cookie 等用于提取目标数据location对象 用于获取和操作URL重要属性href, pathname, search, hash用于页面导航和URL解析navigator对象 用于伪造浏览器信息重要属性userAgent, platform, language常用于反爬绕过history对象 模拟浏览历史方法如back(), forward()用于模拟真实用户行为localStorage 和 sessionStorage 用于存储和获取网站可能用于验证的数据模拟持久化存储XMLHttpRequest 或 fetch 用于发送网络请求模拟AJAX调用setTimeout 和 setInterval 用于处理异步操作和定时任务模拟页面加载和动态内容window.crypto 用于处理加密操作某些网站可能用于生成特定的加密参数performance对象 用于模拟真实的页面加载性能指标screen对象 用于模拟屏幕分辨率等信息console对象 用于调试和日志输出某些网站可能会检查console的行为
在爬虫中这些对象主要用于以下目的
数据提取使用document对象解析页面结构提取所需信息。请求伪造使用navigator和其他对象伪造浏览器特征绕过反爬检测。模拟交互使用history、setTimeout等模拟用户行为。处理动态内容应对JavaScript渲染的页面需要模拟完整的浏览器环境。绕过反爬措施某些反爬技术会检查这些对象的存在性和行为需要精确模拟。
在实际爬虫开发中根据目标网站的特性和反爬措施可能需要重点关注和模拟其中的一部分对象。通常越是复杂的网站需要模拟的对象和行为就越多。 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);
这里有两个主要参数
target: 这是要代理的原始对象。可以是任何类型的对象包括数组、函数甚至另一个代理。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 操作符。
代码示例
在这个例子中
target 是我们要代理的原始对象。handler 定义了如何拦截对对象的操作。我们定义了 get 和 set 捕获器来拦截读取和设置属性的操作。当我们通过代理对象访问或修改属性时相应的捕获器会被调用。
// 目标对象
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
更多的检测功能
代码包含了以下功能
模拟window对象模拟document对象处理cookie的特殊逻辑记录所有属性的访问和设置模拟不存在的方法访问真实的全局属性
// 创建一个模拟的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 userjohn;
console.log(fakeWindow.document.cookie);// 测试访问其他document属性
fakeWindow.document.title Test Page;
console.log(fakeWindow.document.title);