Skip to content

某小说站点逆向还原文本

昨天逛论坛, 发现一篇大牛的技术文章某小说站点逆向还原文本——CSS 反爬,AST 解混淆, 作者是 hans774882968

样本地址: aHR0cHM6Ly9nLmhvbmdzaHUuY29tL2NvbnRlbnQvMTIxMTAyLzI3NzM2MDkuaHRtbA==

1. 分析

网站特点:

  • 使用 css 反爬
  • 使用 OB 混淆

简单复述一下作者思路:

  1. 解读网站算法
  2. 还原文本

具体思路可以看原文, 这里就不再赘述了。我刚看了个开头,直呼看不懂看不懂,所以想着依靠自己掌握的技能能不能实现一下, 于是就有了这篇文章。

我个人想到的方法:

  1. 去除网页干扰项(如广告, 头部, 底部等)
  2. 对指定 dom 元素进行截图
  3. 使用 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-imagedom-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 识别的时候,我就意识到在效率上,肯定没法和算法解题的大佬相比,

没想到的是最后连成品都无法实现,但在这个过程中,我也算是学到了蛮多东西,

最起码熟悉了两个第三方库吧,当然最重要的是看到了塞北的雪大佬的解法,

不依靠算法, 纯前端实现,令人折服!