36氪和虎嗅网这两个网站新闻爬虫比较具有代表性,36氪是传统的html网页爬虫,虎嗅网是异步api加载加密的爬虫,这里就从简单的36氪讲起。 可以看到关键字出现在了html中,而不是xhr接口中,所以在36Kr获取最新的AI快讯就就是对HTML进行解析即可。接着看看HTML请求头信息,获取URL来获取HTML。 在控制台通过搜索关键字,我们在xhr异步接口中发现了新闻咨询内容。 如图,新闻数据通过接口请求返回json的方式渲染的,而非36Kr返回的HTML,所以虎嗅网AI新闻咨询爬虫就是一个比较常见的XHR动态加载的爬虫。 是将一个固定字符串n、timestamp、nonce放进去,然后进行排序,最后将三个元素拼接成一个字符串进行加密。我们接着探究f():t就是传进来的三合一的参数。
图1-1 可以看到提交的参数是 json 格式的数据,分别有 sign、password 这两个比较明显的加密,先逐个搜索一下。 定位加密 - sign 直接通过搜索参数名是可以直接定位到加密位置的。 图2-1 打开【图2-1】中第二个搜索结果,可以看到比较明显的加密位置。【图2-2】 ? 图2-2 重新请求可以直接断在我们断点的位置,变量 v 与 变量 g 的值都是 undefine,变量N是变量c哈希后大写的结果。【图2-3】 ? 图2-3 我们可以用 Python 代码验证一下。 图3-1 一个一个找太麻烦了,比较简单的方法是直接用 XHR 断点然后直接翻堆栈。 先根据 XHR 请求添加一个 XHR 断点【图3-2】 ? 图3-4 加密逻辑也非常简单。
图1-1 可以看到这里的加密参数名为sign 拿到加密参数名,我们现在用两种方法定位加密位置 •xhr 断点•直接搜索参数 使用 xhr 断点只要分析堆栈肯定可以找到这个参数生成的地方,不过很麻烦,建议当你没办法通过检索参数名找到加密位置的线索的时候再使用 xhr 断点。 加密分析 找到加密位置之后,我们就来看看这个 a 他的加密到底是个啥。 经过断点可以看到a是在这里生成的。【图2-1】 ? 图2-1 那么a 等于什么呢?就是下面这一串了。 同样的这里还用到了i()与e,这里的e = o就是当前的时间戳,i()这个方法返回了加密方法e。 现在每一部分缺失的都找到了,只要明白这个加密方法e是什么就完成了。 我们追进去看看【图2-2】 ? 图2-2 看到这个有没有感觉有点熟悉。 之前我写过一个文章有类似的代码。 当我追到_doFinalize之后看到了下面这段代码。【图2-3】 ?
【图2-2】 ? 不过咸鱼试过在这里打上断点,重新加载没有断上,初步判断不是这里生成了这个请求头参数。 所以这里尝试使用Xhr断点的方式分析。【图2-3】 ? 打上这个断点之后,重新加载页面。 可以在这里看到t的值中就包含了我们需要的请求头if-none-match,所以可以猜测在这个 xhr 断点之前就已经完成了这个值的生成。 所以这里可以先在这个 xhr 断点前下一个断点之后暂时取消 xhr 断点。【图2-5】 ? 到这里之后我们直接单步调试,可以看到下面这段逻辑【图2-6】 ? 经过分析可以看到在代码中有一段在字典中赋值的操作,并且这里也找到了加密的字段名。【图2-7】 ? 所以上面就是加密字段的加密位置。 加密很简单直接带入 Python 实现的加密即可。【图3-3】 ?
domain-a.com 站点发送一个 api.domain-b.com/get 的请求,默认是不会携带 api.domain-b.com 域下的 cookie,如果我们想携带(很多情况下是需要的),只需要设置请求的 xhr 跨域情况下,需要携带请求域下的cookie那么就需要配置xhr对象的withCredentials。 需要额外注意的是 当配置了xhr.withCredentials = true时,必须在后端增加 response 头信息Access-Control-Allow-Origin(CORS),且必须指定具体域名
XX文书网20190902版 这次分享的是XX文书网于2019年09月02日的加密算法。 目前该网站采用的瑞数动态混淆的加密算法,反混淆难度高,解密难度高 接下来说说0902版的加密,以下仅为参考: __RequestVerificationToken 搜索关键词__RequestVerificationToken str += arr[Math.round(Math.random() * (arr.length-1))]; } return str; } Ciphertext 通过XHR 图2-1 加密位置为【图2-2】 ? 图2-2 直接扣取ciphertext这个方法的代码即可,这里展示部分代码: cipher=function(){ var date = new Date(); var timestamp
未来发展方向是Fetch取代AJAX 回答 2: XHR vs AJAX XHR(XMLHttpRequest)对象用于与服务器交互,是AJAX技术方案的基础,也可以说,使用XHR对象来发送一个Ajax 看看如何使用 XHR 发送 AJAX请求。 对象 var xhr = new XMLHttpRequest(); //设置xhr请求的超时时间 xhr.timeout = 3000; //设置响应返回的数据格式 xhr.responseType ... }; // 监听xhr状态 xhr.onreadystatechange = function () { try { switch(xhr.readyState 支持xhr.ontimeout超时自动取消,也支持xhr.abort()主动取消请求) 无法检测请求的进度(XHR可以)
对于分类问题,我们不再像回归问题那样,找出直线的斜率和截距。为了方便理解,将拥有一个特征的回归问题所绘制的图示和拥有两个特征的分类问题绘制的图示进行对比。
为了提倡居民节约用电,某省电力公司执行“阶梯电价”,安装一户一表的居民用户电价分为两个“阶梯”:月用电量50千瓦时(含50千瓦时)以内的,电价为0.53元/千瓦时;超过50千瓦时的,超出部分的用电量,电价上调0.05元/千瓦时。请编写程序计算电费。
图2-1 可以看到有一条xxxapi的请求链接,可以看到请求参数也加密了。【图2-2】 ? 图2-2 除了参数之外,同样这个请求的返回值同样也是密文的。【图2-3】 ? 图2-3 | 部分结果截图 经过请求分析,明确了现在要分析的加密是参数和返回值。 加密参数分析 先开始关于参数的分析。 通过多次加载请求,发现所有的参数加密的名字都是不相同的,所以全局检索参数名定位到参数加密的可能性很小。所以直接用 XHR 断点。【图3-1】 ? 图3-1 重新加载页面,加载数据就断上了。 返回值解密 分析完加密参数后,再来看看返回值是如何解密的。 在上一部分,我们定位到了加密参数生成的地方,在生成的位置下方就是加密返回值解密的位置。 图4-3 这类简单的加密代码,扣取起来难度很低,也可以用 Python 直接复写。 简单扣取之后,就可以直接将加密的返回值带入运算了。【图4-4】 ?
咸鱼之所以这样搜索是出于自己的习惯,定位加密位置的方法有很多大家有兴趣可以多尝试不要局限于搜索参数,例如:Js Hook,XHR 断点等等,怎么舒服怎么来就好。 经过搜索参数名password:在一个文件中定位到 3 处疑似加密的位置。 运行的报错提示,window is undefine【图2-2】,遇到这种情况我们可以试试在代码上加上window的声明。 图2-2 var window = {} 再次运行看看,这里再次提示{} is not a function,【图2-3】到这里新手朋友有点慌了,不知道怎么处理。 var navigator = {} 再次运行就得到加密后的结果咯~【图2-5】 图2-5 总结 这次的加密是比较简单的 RSA 加密,使用文件中包含的公钥对密码的值进行加密,且Js代码没有进过混淆,
XHR的属性和方法及事件汇总 xhr.open xhr.send() xhr.onreadystatechange = function() { } 监听状态变化 xhr.reaadyState xhr.status 获取响应头信息 xhr.getResponseHeader([key]) 获得响应头的xxx信息 xhr.getResponseHeaders(‘Date ’) 获取服务器时间是标准的日期格式对象(GMT格林尼治时间) xhr.getAllResponseHeaders 获得到响应头的所有信息 获取响应主体信息 xhr.response 不限定类型 xhr.responseType 获取响应回来的类型 xhr.responText 限定类型 一般用 responseText,因为服务器返回的信息一般都是JSON格式的字符串 xhr.responseXML 限定类型 xhr.timeout 限制响应时间 xhr.abort() 终止响应 xhr.withCredentials = true 默认是false,我们会设置为true,在跨域请求中是否携带证书
= new XMLHttpRequest(); xhr.onreadystatechange = function () { console.log('readystate:', xhr.readyState ); xhr.send(); xhr.onreadystatechange = function () { console.log('readystate:', xhr.readyState); // 2、3....、4 } 四、readyState变化 const xhr = new XMLHttpRequest(); xhr.open('get', 'http://f.sinaimg.cn :', xhr.readyState); // 1、4 } xhr.send(); xhr.onreadystatechange = function () { console.log('readystate :', xhr.readyState); // 无返回 }
> x <- vector("character",length=10) > x1 <- 1:4 > x2 <- c(1,2,3,4) > x3 <- c(TRUE,10,"a") #如果给向量赋值时元素类型不一致,R就会强制转换,将他们变为同一类型 > x4 <- c("a","b","c","d")
XX街登陆密码加密 aHR0cDovL3NlbGxlci5jaHVjaHVqaWUuY29tL3NxZS5waHA/cz0vVXNlci9pbmRleA== 这个加密太简单了,五秒定位真的不是吹,所以直接来 ,直接到加密参数分析的地方。 Tip: 这次的加密不是异步的 不要在 XHR 选项卡傻乎乎的等了。 X博登陆框是嵌在页面中的加上X博的登陆页面图片以及要加载的东西很多,所以我们需要注意的包主要有两个: 登陆前返回相关加密秘钥的包【图2-1】 发起登陆请求的包【图2-2】 ? 图2-1 ? 图2-2 到这里就很清晰了,我们搞定 su 和 sp 就完事了。
在这个过程中,XHR 和 Fetch API 是两种最常见的方法,用于从 Web 服务器获取数据。XHR 是一种传统的数据请求方式,而 Fetch API 则代表了现代 Web 开发的新兴标准。 工作原理 XHR 的工作原理主要为: 创建 XHR 对象实例:通过new XMLHttpRequest()创建一个 XHR 对象。 // 创建一个新的XHR对象 const xhr = new XMLHttpRequest(); // 配置请求 xhr.open("GET", "https://api.baidu.com/test ("请求失败,状态码:" + xhr.status); } }; // 发起请求 xhr.send(); XHR 的响应处理通常在onreadystatechange事件处理程序中完成。 常用库和插件 基于 XHR 封装的库 jquery:一个 JavaScript 库,提供了用于处理 DOM 操作、事件处理和 XHR 请求的便捷方法。
写过几个油猴脚本,经常对页面请求返回的数据进行拦截或者覆盖,这篇文章就做个总结,涉及到 fetch 和 xhr 两种类型的请求。 环境搭建 先简单写个 html 页面,搭一个 koa 服务进行测试。 xhr 我们将 fetch 改为用 xhr 发送请求,因为页面简单所以请求可能在油猴脚本重写之前就发送了,正常网站不会这么快,所以这里加一个 setTimeout 进行延时。 setTimeout(() => { const xhr = new XMLHttpRequest(); xhr.open('GET', 'http://localhost:3002/api /query'); xhr.send(); xhr.onload = function() { const res = JSON.parse(this.responseText 总 通过对 fetch 和 xhr 的重写,我们基本上可以对网页「为所欲为」了,发挥想象力通过油猴脚本应该可以做很多有意思的事情。
(1)异步请求的函数封装 /* * XHR连接对象 * 把请求的函数做成一个序列,按照执行序列来完成每一个序列项的任务 * * */ (function () { //(1)一个request请求 callBack(o); } } },500) } //(2)获取XHR
XHR 断点定位 本次案例我们使用 XHR 断点来定位加密的位置,首先了解一下什么是 XHR,XHR 全称 XMLHttpRequest,XHR 可以在不重新加载页面的情况下更新网页、在页面已加载后从服务器请求 既然是 XHR 断点,那么这种方法就只能用于 XHR 请求,这也是这种方法的缺点,通过 XHR 断点,定位到的位置通常在加密处理完成之后,已经准备发送请求了,这样的优点是我们可以跟踪栈,能比较容易地找到加密的地方 XHR 断点定位有两种方法,第一种是找到发送请求的 URL 之后,截取 URL 的一部分,在 Source 面板下,右侧 XHR/fetch Breakpoints 里添加你截取的 URL,如下图所示, 已成功断下: [03.png] 第二种方法,在 Network 面板,点击 XHR 过滤 XHR 请求,在 Initiator 项里可以看到调用的 JS,鼠标移到 JS 上,可以看到调用栈,点击第一个, divide to get the high bits, // max digit bits should be 26 because // max internal value = 2*dvalue^2-
关于模块和模块化,百度百科有一段引用自《Java应用架构设计:模块化模式与OSGi》一书的解释非常好: