Appearance
某小说站点逆向还原文本
昨天逛论坛, 发现一篇大牛的技术文章某小说站点逆向还原文本——CSS 反爬,AST 解混淆, 作者是 hans774882968
样本地址: aHR0cHM6Ly9nLmhvbmdzaHUuY29tL2NvbnRlbnQvMTIxMTAyLzI3NzM2MDkuaHRtbA==
1. 分析
网站特点:
- 使用 css 反爬
- 使用 OB 混淆
简单复述一下作者思路:
- 解读网站算法
- 还原文本
具体思路可以看原文, 这里就不再赘述了。我刚看了个开头,直呼看不懂看不懂,所以想着依靠自己掌握的技能能不能实现一下, 于是就有了这篇文章。
我个人想到的方法:
- 去除网页干扰项(如广告, 头部, 底部等)
- 对指定 dom 元素进行截图
- 使用 OCR 识别来还原文本
2. 实现
为了方便快速调试, 我使用了油猴脚本来实现功能
2.1 去除网页干扰项
这一步非常简单,用GM_addStyle
覆盖样式即可
js
GM_addStyle(`
/*调整字体按钮/日夜间模式切换按钮,翻页按钮,加入书签,二维码 */
.readsetbtn,.frame9.frame13.rdbom.clearfix,.rdbom2.clearfix,.ewm{
display: none !important;
}
`)
2.2 对指定 Dom 元素进行截图
这一步需要借助第三方库,可以简单方便的实现,我通过搜索了解到了相关的库有dom-to-image
和dom-to-image-more
,我选择了后者,因为它支持更多的功能,比如可以设置背景色,可以设置图片质量等.
js
const downloadImage = async dom => {
try {
return await domtoimage.toJpeg(dom)
} catch (error) {
console.error(error)
}
}
然后测试效果, 发现给的图居然是黑底的,浏览器有跨域报错信息,这是因为浏览器不允许跨域访问图片,所以我们需要设置背景色为白色.
js
GM_addStyle(`
/*调整字体按钮/日夜间模式切换按钮,翻页按钮,加入书签,二维码 */
.readsetbtn,.frame9.frame13.rdbom.clearfix,.rdbom2.clearfix,.ewm{
display: none !important;
}
/* 设置文章背景色为白色 */
#wz{
background-color: #fff !important;
background-image: none !important;
}
`)
现在就可以正常截图了,下面是未设置背景颜色和设置了背景颜色的对比
2.3 使用 OCR 识别来还原文本
这一步还是要借助第三方库, 好在我运气不错,找到了一个叫tesseract.js
直接上代码:
js
import { createWorker } from 'tesseract.js'
const worker = await createWorker()
;(async () => {
await worker.loadLanguage('chi_sim')
await worker.initialize('chi_sim')
const {
data: { text },
} = await worker.recognize('./2.jpg')
console.log(text)
await worker.terminate()
})()
代码效果:
感觉可以哦, 原地起飞了! 正当我想着把这些功能结合在一起的时候,问题出现了:tesseract.js
是一个 nodejs 库,
无法在浏览器里运行,这样的话,如果要实现完整流程, 我不仅需要前端在浏览器运行的油猴脚本,
我还需要部署一个 node.js
服务,我相信最终部署后,流程上是走的通的,
但是我不想这样,我想要的是一个完整的油猴脚本,这样我就可以在浏览器里直接运行了,所以我又开始了新的探索。
2.4 使用 tesseract.js 的 wasm 版本(用不来)
提示
wasm 是 WebAssembly 的简称,是一种新的编码方式,可以在现代的网络浏览器中运行 - 它是一种低级的类汇编语言,具有紧凑的二进制格式,可以接近原生的性能运行,并为诸如 C / C ++等语言提供一个编译目标,以便它们可以在 Web 上运行。它也被设计为可以与 JavaScript 共存,允许两者一起工作。更多详情请点击我
tesseract.js 的 wasm 版本地址:https://github.com/robertknight/tesseract-wasm
我这里只是一个简单的油猴脚本, 我看文档感觉有点模糊,因为他的示例是在有脚手架的情况下使用的,我不知道怎么把他的示例代码放到油猴脚本里,所以我就放弃了这种方法。
后续我会多关注 wasm 相关的内容,如果有进展,我会在这里更新的。
3. 转折
还是在论坛贴里, 我遇到了一位大佬:塞北的雪,这是他提供的代码:
js
let css = document.styleSheets[0].cssRules
Object.keys(css).forEach(function (k, v) {
stylename = css[k].selectorText.split('::')[0]
content = css[k].style.content.replaceAll('"', '')
document.querySelectorAll(stylename).forEach(function (ek, ev) {
ek.replaceWith(content)
})
})
说实话,第一眼我完全没看懂,我只好分步骤在控制台里测试,最后我发现了这个代码的作用:
它的主要功能是将 CSS 中的 ::before
和 ::after
伪元素的 content
属性的值作为文本内容插入到相应的 HTML 元素中。
具体地,代码首先获取网页中第一个样式表的所有 CSS 规则,然后遍历这些规则,
对于每个规则,代码会将其选择器中的 ::before 或 ::after 去掉后得到真正的选择器名,再将其对应的 content 属性值插入到网页中与该选择器匹配的所有 HTML 元素中。
这样一来,我们就可以方便地通过 CSS 为 HTML 元素添加一些额外的文本内容了。
4. 结语
其实我一开始考虑 OCR 识别的时候,我就意识到在效率上,肯定没法和算法解题的大佬相比,
没想到的是最后连成品都无法实现,但在这个过程中,我也算是学到了蛮多东西,
最起码熟悉了两个第三方库吧,当然最重要的是看到了塞北的雪大佬的解法,
不依靠算法, 纯前端实现,令人折服!