JS反爬虫根本原因 / 基本原理:
(1) 反爬虫:
限制爬虫程序访问服务器资源和获取数据的行为称为反爬虫。
(2)限制手段:
包括但不限于请求限制、拒绝响应、客户端身份验证、文本混淆和使用动态渲染技术。
这些限制根据出发占可以分为主动型反爬虫、被动型反爬虫。
该章节内容:
- Web 网页的基本构成
- 浏览器的组件和作用
- HTML DOM与网页渲染过程
- 编程语言或工具与浏览器的差异
(1)Web 网页的基本构成
导航栏、LOGO、搜索框、轮播图等等——>组成主要元素:文字,图片
操作:打开浏览器观察资源加载
(2)浏览器的组件和作用
因此游览器打开网页的结构图如下:
(3)HTML DOM与网页渲染过程
(1)HTML DOM:
文档对象模型。 中立于平台和语言的接口,它允许程序动态地更新文档内容、结构和样式。
HTML 文档的标签对可以抽象为 HTML DOM<title>Harry Potter</title> <year>2005<year>
(2) 页面渲染过程:
渲染引擎通过解释器结果来操作 DOM 重新把页面内容进行排版,最后排版结果展现到页面内容。
(4)编程语言或工具与浏览器的差异
操作:
(1)用浏览器打开指定网址
(2)用 Python 代码请求指定网址
(3)Postman 用工具请求指定网址
以上对比总结如上图
因此JavaScript 反爬虫的根本原因:浏览器与其他工具的差异(即其他工具当中没有JS解析器)
CSS反爬虫同理:利用没有 CSS 解释器和渲染引擎的特点来实现反爬虫(字体反爬虫、文本偏移反爬虫、文本混淆反爬虫等等)。
JS概述
(1)简介:
JS 与 CSS 和 HTML 之间的关系:
JS的发展:
(2)🌟JS 语法:
包含以下内容:
- 数据类型
- 控制流
- 函数
- 特殊对象
①数据类型:
- Object 对象
- Array 数组
- String 字符串
- Number数字
- Boolean 布尔值
- Map 映射
- Set 集合
- null /undefined
1.Object 对象
- 是以 Key-Value 键值对的形式存在的集合——>用来表示映射的数据结构(类似于Python的字典 dictionary)
- 键(Key)都是字符串(String)类型(限制)
- 值(Value)可以是任意类型
- 对象的拷贝分为 深 / 浅拷贝
- 浅拷贝: 只复制对象内存地址,类似于指针
- 深拷贝: 完全克隆,生成一个新对象
2.Array 数组
- 数组是一个有序排列的集合
- 数组的值可以是任意类型
- 数组的拷贝分为深浅拷贝
- 与对象一致
查找通过索引实现,遍历数组可以通过map(会返回一个新数组)和foreach
3.String 字符串
- 字符串是任何由单引号或双引号定义的类型(不区分)
4.Number数字
- 数字是任何表示数字的类型(没有整型和浮点型区别)
5.Boolean 布尔值
- 布尔值是表示 true 或 false 的类型
映射(Map)和集合(Set)是 ES6 中新增的类型,以解决ES5中对象(Object)和数组(Array)的不足
6.Map 映射
- 键(Key)值(Value)对关系的集合
- 与对象相似,但是不同的是,键 key 可以为任何类型
7.Set 集合
- 相当于不重复值(去重)的数组
8.null
- 相当于一个“空”的值
- 表示该值为空
9.undefined
- 表示“未定义”
- 通常用于比较不存在的属性或值
建议:赋值的时候永远用null,做比较的时候永远用三个等号,而不是两个等号(弱类型语言——>任何类型的值都可以做比较。三个等号为true即保证比较双方值都相等,而且类型相同。而两个等号比较会将数据类型转化成一个数据类型后再进行比较。因此三个等号比较稳定!)
②控制流:
- while
- for
- Array
- map
- forEach
条件判断
- 可以是if(){} else {} 的形式
- 也可以是if ()else 的形式
- 中间有条件用 else if 的形式
③函数:
- 定义
- 变量作用域
- 高阶函数
- 闭包
- 特殊对象
1.函数定义:
- 带函数名
- function funcName (param) { statement } - function关键字 函数名 (定义参数) {函数的内容} ——> function关键字定义即函数声明,JS声明中函数声明高于一切。即浏览器加载好这段代码的时候会首先将这个函数加载进来。可以不用管这个定义在哪个位置。
- const funcName = function(param){ statement } - 用定义变量 const = ——> 用变量的定义就会有一定的执行顺序了。如果用变量形式的定义的函数在引用之后,则会出现报错的情况
- 不带函数名 (匿名函数 定义) ——> 爬虫逆向更为常见
- ( function (param) {statement} () )
2.变量作用域:
- 变量定义
- var, const, let 定义的变量是有作用域的
- var 定义的变量在各自的函数内部起作用
- const、let 定义的变量为块级作用域
- 变量提升
- 扫描整个函数体的语句,将所有申明变量提升到函数顶部(定义的变量被提前引用的话,就不会出现 undefined 的错误。)
- 全局作用域
- 如果不指定 var,const, let 申明关键字来定义变量,该变量将被绑定到全局变量 window 上
- 块级作用域
- let,const 将作用在 for、while等循环语句里,而不能被外部访问到。提升了封装性。
3.高阶函数:
- 定义:
- 接收另一个函数作为参数的函数被称作高阶函数(进行异步操作)
- 用途:
- 回调 - Callback
- 数组操作 - filter、sort、map、forEach
4.闭包(类似Python中的装饰器):
- 定义:
- 函数的返回值可以为函数
- 所有的参数和变量都保存在返回函数中
- 当调用返回函数时才会执行所有的运算逻辑
- 用途:
- 匿名自执行函数
- 封装
- 结果缓存(留在后来执行)
④特殊对象:
- JSON:
- JSON 静态变量 负责对象的序列化 / 反序列化操作 ——> 深拷贝
- JSON.stringify 序列化
- JSON.parse 反序列化
- Date:
- JS 的时间操作对象
- new Date(dateString)
(3)JS 进阶:
该小结内容:
- 事件循环
- 原型链
- 异步编程
- 浏览器储存
- 跨域
- Webpack 打包
①事件循环(Event Loop):
(1)定义: 主线程不断的重复获取执行消息、再获取执行不断循环的机制被称为事件循环
(2)为什么需要事件循环?
- JS 是单线程的
- 在处理异步操作的时候需要事件循环机制
(3)相关概念
- 堆(Heap):大块非结构化内存区域,储存对象、数据
- 栈(Stack):调用栈,储存该次循环待主程序执行的任务
- 队列(Queue):事件队列,先进先出被推入调用中
- 宏任务(Macro Task)和微任务(Micro Task )
- Nodejs 事件循环
②原型链:
(1)概念:
- prototype
- _proto_
- constructor
每一个函数都有一个原型 prototype 属性,这个属性指向函数的原型对象。每个new出来的对象都有一个 _proto_ 属性指向对象的原型。每个原型都有一个 constructor 属性指向该关联的构造函数。当读取实例的属性时,如果找不到,就会查找与对象关联的原型中的属性。如果还查不到,就会去找原型的原型,一直找到最顶层为止。
原型链的用途主要是理解JavaScript当中继承和代码复用的。ES6之前,JS中只能用原型来进行对象的封装和继承。因此原型链有助于我们理解继承和调用的过程。
- class 关键字(类似 类的语法糖可以直观进行面向对象操作)
(2)应用场景:
继承、代码复用
ES6 出来后是否需要理解原型链 ?
③异步编程:
1.回调函数 Callback:
- 通过传入回调函数作为参数在函数中异步执行
- 优点: 简单
- 缺点: 回调地狱
2.Promise:
- ES6 中出现的异步解决方案
- 可以获取异步操作消息的对象
- resolve / reject , then / catch
- 优点: 解决了回调地狱
- 缺点: 代码可读性不高
3.async/await:
- ES8(ES2017)中出现的异步解决方案
- 是基于 Promise 的语法糖,需要了解 Promise 相关知识
- async 返回 Promise 对象
- async 函数遇到 await 时会终止运行,直到相应的 Promise 状态变为 resolved
- 优点:解决了 Promise 代码可读性问题,代码可读性高
- 缺点:多个并行异步操作需要用 Promise.all 来执行
④浏览器储存:
1.Cookies
- 主要用于与服务端通信
- 储存量小
2.Local Storage
- 储存量相较于 Cookies 更大
- 只能储存字符串
3.Session Storage
- 只存在与当前 Session,关闭浏览器就丢失了
- 其他与 Local Storage 一样
4.IndexedDB
- 相当于浏览器上的 SQL 数据库
- 更大的储存空间
- API较难掌握
⑤ 跨域:
(1)跨域定义: 客户端与不同源的服务端通信
(2)解决办法:
1.CORS:跨域资源共享,解决跨域请求的方案的成熟方案(可能会暴露端口,安全性有一定的风险)
2.JSONP:
- 基于 <script> 标签具有可跨域特性
- 只能用于 GET 请求(局限性)
3.iframe:
- 通过<iframe>标签在一个页面展示不同源的页面
- 通过 PostMessage 进行页面之间的通信
4.反向代理 :
- 通过Nginx或者IIS对请求路由做反向代理让客户端与服务端保持同源(让静态资源与API是以同一个源达到解决跨域的目的——>隐藏端口,安全性较高)
跨域以及解决方案-CSDN博客文章浏览阅读591次,点赞9次,收藏25次。随着API的广泛使用和前后端分离架构的流行,跨域的处理将成为开发者不可或缺的技能之一。正确地实施跨域解决方案不仅能够提高应用的灵活性,还能增强用户体验,为开发者创造高效、安全的Web环境。https://blog.csdn.net/m0_61662775/article/details/140901734?spm=1001.2014.3001.5501
⑥Webpack 打包
(1)目的:
- 将不同类型的源文件编译打包成静态文件
(2)为什么使用 Webpack:
·前端技术纷繁复杂,缺乏统一管理
·大型项目需要模块化
·对于例如 JSX、TS 之类的新技术需要编译后才能使用
- 编译器 babel
- 插件
- 优化
调用 JS 执行代码
本章节内容:
- 了解为什么我们需要直接调用JS
- 了解常见的 Python 调用JS 的库
- 了解一种性能更高的操作方式
- 知道什么场景下应该使用什么方式进行调用
(1)直接调用JS :
简单JS 破解: 通过Python代码轻松实现
复杂的JS破解: 代码不容易重写, 使用程序直接调用 JS 运行获取结果
1.常见的简单JS重写:
MD5是哈希而非加密(32位 英文数字混合的字符串加密)
2.复杂的JS运行:
- 使用Python调用JS
- 一种性能更高的调用方式
- 到底选择哪种方案比较好
- 使用非浏览器存在的问题,以及解决方法
(2)各种调用 JS 的库:
- PyV8
- Js2Py
- PyExecjs
- PyminiRacer
- Selenium
- Pyppeteer
PyV8
- V8是Google的开源JavaScript引擎,被使用在了Chrome中。
- PyV8是V8引擎的一个Python层包装,可以用来调用V8引擎执行JS代码
- 网上很多使用它来执行JS代码的文章
- 年久失修,最新的正式版本是2010年的(https://pypi.org/project/PyV8/#history)
Js2Py
- JS2Py是一个纯Python实现的Javascript解释器和翻译器
- 虽然它2019年依然有更新,但那也是6月份的事情了,而且它的issues里还有很多BUG未被修复(https://github.com/PiotrDabkowski/Js2Py/issues)
解释器部分:
- 性能不高
- 存在一些BUG
翻译器部分:
- 对于高度混淆的大型JS 会转换失败
- 而且转换出来的代码可读性差、性能不高
PyMiniRacer
- 同样是V8引擎的包装,和PyV8效果一样
- 一个继任PyExecJS和PyV8的库
- 一个比较新的库
PyExecjS
- 一个最开始诞生于Ruby中的库,后来被移植到了Python上
- 较新的文章一般都会说用它来执行IS代码,
- 有多个引擎可选,但一般我们会选择使用NodeJS作为引擎执行代码
Python终端输入
选择不同引擎进行解析
代码示例:
潜在问题:
- 执行大型JS时会有点慢
- 特殊编码的输入或输出参数会出现报错的情况
- 可以把输入或输出的参数使用Base64编码一下、
Selenium
- 一个Web自动化测试框架,可以驱动各种浏览器进行模拟人工操作
- 用于渲染页面以方便提取数据或过验证码
- 可以直接驱动游览器执行JS
Pyppeteer
- Puppeteer的Python版本,第三方开发的,是一个Web自动化测试框架
- 原生支持以协程的方式调用,同时性能比Selenium更高一些
- 对于用Asyncio+Aiohttp写爬虫的人而言可以直接使用
页面加载前:
(3)性能更高地调用:
(1)RPC:写一个简单的RPC服务接口,然后调用JS。
- 使用Google出品的gRPC框架: 和正常写API一样,调用一下目标JS就好了
(2)HTTP API
简单来说就是,提供一个可以执行JS的HTTP API,然后通过调用这个API来执行JS并获取想要的结果。
- 使用Nodejs的Express框架来实现: 和正常写API一样,调用一下目标JS就好了
(4)使用Node.js 存在的问题:
window对象:
- NodeJS没有window对象,如果使用window对象需要自己创建一个或者指向global
- 使用jsdom之类的库
Base64:
- window.btoa在nodejs中不存在
- Buffer.from('NightTeam').toString('base64')
游览器开发者工具
该章节内容:
- 浏览器开发者工具的介绍
- Network 面板的介绍与使用
- Console 面板的介绍与使用
- Source 面板的介绍与使用
初学者必看,前端 Debugger 调试学习_前端debugger怎么用-CSDN博客文章浏览阅读2k次,点赞6次,收藏13次。前端调试是指在开发过程中,通过检测和修复前端代码中的错误和问题,以确保网页或应用程序在各种设备和浏览器中正常运行的过程。它是前端开发过程中不可或缺的一部分,可以帮助开发人员快速定位并解决潜在的问题,提高代码的质量和用户体验。_前端debugger怎么用https://blog.csdn.net/m0_61662775/article/details/133801268?spm=1001.2014.3001.5501
(1)Chrome 开发者工具介绍
Chrome 浏览器相对于其他的浏览器而言,他的开发者工具非常强大,可以用来对网站进行迭代,调试和分析。
(1)使用快捷键打开 Chrome 开发者工具
- Window用户使用 Ctrl+Shift +I
- 打开Mac 用户使用Cmd+Opt+I打开
- 右键“检查”即可呼出开发者面板
- Elements(元素面板): 使用“元素”面板可以通过自由操纵DOM和CSS来重演您网站的布局和设计
- Console(控制台面板): 在开发期间,可以用控制台面板记录诊断信息,或者使用它作为shell,在页面上与JavaScript交互
- Sources(源代码面板): 在源代码面板中设置断点来调试JavaScript,或者通过Workspaces(工作区)连接本地文件来使用开发者工具的实时编辑器
- Network(网络面板): 从发起网页页面请求equest后得到的各个请求资源信息(包括状态资源类型、大小、所用时间等),并可以根据这个进行网络性能优化
- Performance(性能面板): 使用时间轴面板,可以通过记录和查看网站生命周期内发生的各种事件来提高页面运行时的性能
- Memory(内存面板): 分析web应用或者页面的执行时间以及内存使用情况
- Application(应用面板): 记录网站加载的所有资源信息,包括存储数据(Localstorage、Session Storage、-IndexedDB、Web SQL、Cookies)、缓存数据、字体、图片、脚本、样式表等Security(安全面板): 使用安全面板调试混合内容问题,证书问题等等
- Audits(审核面板): 对当前网页进行网络利用情况、网页性能方面的诊断,并给出一些优化建议。比如列出所有没有用到的CSS文件等。
(2)Network 面板使用
该小节内容:
- Network面板介绍
- 异步请求重发
- 如何5秒钟生成爬虫代码
1.Network面板介绍
1.控制器区域
2.过滤器区域:显示请求列表显示哪些资源
3.概览部分:显示资源请求时间的时间线
4.请求列表:默认排序为时间顺序排序
5.概要区域:从数据角度,我们发起了多少个请求,传输了多少的数据,加载耗时,DOM框架加载耗时
1.Controls(控制器): 使用这些选项可以控制Network面板的外观和功能
2.Filters(过滤器): 使用这些选项可以控制在 Requests Table 中显示哪些资源。提示:按住Cmd(Mac)或 Ctrl(Windows/Linux)并点击过滤器可以同时选择多个过滤器
3.Overview(概览):此图表显示了资源检索时间的时间线。如果您看到多条竖线堆叠在一起,则说明这些资源被同时检索4.Requests Table(请求列表): 此表格列出了检索的每一个资源。默认情况下,此表格按时间顺序排序,最早的资源在顶部。点击资源的名称可以显示更多信息。提示:右键点击 Timeline 以外的任何一个表格标题可以添加或移除信息列
5.Summary(概要): 此窗格可以一目了然地告诉您请求总数、传输的数据量和加载时间
①控制器:
②过滤器:
- domain: 仅显示来自指定域的资源。您可以使用通配符()来包括多个域。例如,.com显示以.com结尾的所有域名中的资源。DevTools会在自动完成下拉菜单中自动填充它遇到的所有域has-response-header: 显示包含指定HTTP响应头信息的资源。DevTools会在自动完成下拉菜单中自动填充它遇到的所有响应头。
- is: 通过is:running找出WebSocket请求。
- larger-than(大于): 显示大于指定大小的资源(以字节为单位)。设置值1000等效于设置值1k。
- method(方法): 显示通过指定的HTTP方法类型检索的资源。DevTools使用它遇到的所有HTTP方法填充下拉列表。
- mime-type(mime类型: 显示指定MIME类型的资源。DevTools使用它遇到的所有MIME类型填充下拉列表。
- mixed-content(混合内容: 显示所有混合内容资源(mixed-content:all)或仅显示当前显示的内睿(mixed-content:displayed)。
③ 请求列表:
此列表列出了检索的每个资源。默认情况下,此表按时间顺序排序,也就是最早的资源在顶部。单击资源名称可以获得更多信息。
查看单个请求详情
- 查看请求头
- 查看 Cookie
- 预览响应正文:图像,字体等
- 查看响应正文
- 查看时间详细分布
- 查看请求的上下游(选中请求,按住Shift)
- 将请求数据复制导出
如何 5 秒钟写一个爬虫
- 选中请求,右键 Copy-Copy as Curl
- 打开 Postman
- 选择lmport-Paste Raw Text
- 在生成的请求中点击Code
- 在弹出的对话框中点击下拉列表选择PythonRequests生成Python代码
(3)Source 面板
该小节内容:
- File Navigotar
- Code Editor
- JavaScript Debugging
- 在Source 面板中找到 Overrides 子面板
- 点击 Select folder for Overrides选择一个目录,作为文件的存储目录,同时确保打开了 Enable Local Overrides
- 在 Network面板,选中一个请求右键,点击Savefor overrides
- DevTools 会在本地创建一个与请求内容相同的文件,并在Source 面板中打开编辑完刷新页面以查看效果
调试面板:
- Debug 调试
- 条件断点
- 行断点
- XHR断点
- 事件侦听器断点
- Watch-变量监听
- Call stack-断点的调用栈列表
- Scope-断点所在作用域的内容
- Breakpoints-断点列表
- XHR/fetch Breakpoints-请求断点列表
- DOM Breakpoints-Dom断点列表
- Event Listener Breakpoints-可断点的事件监听列表
(4)Console 面板的使用
(1)Console 的基本用法
- console.info -向控制台输出提示信息
- console.error-向控制台输出错误信息
- console.warn -向控制台输出警示信息
- console.assert-断言
1.Console.table——表格形式展示数据
2.Copy(...)——复制变量的值
3.Console 中的$
- $_即可调用这最后一次执行的结果
- $可以当做document.querySelector,$$当做document.querySelectorAll
- $X可以结合XPath
4.Console 中使用XPath查询 DOM