diff --git a/2023/07/05/trace-of-line-01/index.html b/2023/07/05/trace-of-line-01/index.html index 0695714..cffc00a 100644 --- a/2023/07/05/trace-of-line-01/index.html +++ b/2023/07/05/trace-of-line-01/index.html @@ -24,7 +24,7 @@ - + @@ -307,9 +307,9 @@

《飞石》Pt.1 未掷出的石子 第一章:不存在的

本小说任何情节均为虚构,与现实中任何国家、团体、组织与个人无关

+

不存在的历史,勾起了石月仙的注意,随着找寻真相的深入,一个隐瞒了全世界的阴谋浮出水面。而对于人类,阴谋何来,何从,何去?

-

第一章:不存在的历史

-

「第三次科技革命后,人类进入信息时代,信息化开始影响人类的历史进程……」

+

第一章:不存在的历史

「第三次科技革命后,人类进入信息时代,信息化开始影响人类的历史进程……」

「为什么初中高中上过的还要再上一遍啊?我都快烦死了。」石月仙在心中自言自语道,眼睛无神地看着教授在全息屏上指指点点。

「怎么就没有第四次科技革命呢?第一次工业革命与第二次工业革命之间几乎没有罅隙,第二次与第三次也只隔了几十年,第三次科技革命都过去快 100 年了,怎么第四次科技革命一点苗头的没有呢?」

下课铃响,教授一溜烟没影了,消失在学生们的视野中。学生们鱼贯而出,奔着食堂而去。留下石月仙一人在教室里沉思。

@@ -590,12 +590,6 @@

第一章:不存在的历史

- - - - - - @@ -814,49 +808,6 @@ - - - - - - diff --git a/2023/07/05/zhihu-aac-old/index.html b/2023/07/05/zhihu-aac-old/index.html index 2193152..8e17d15 100644 --- a/2023/07/05/zhihu-aac-old/index.html +++ b/2023/07/05/zhihu-aac-old/index.html @@ -25,7 +25,7 @@ - + @@ -305,9 +305,8 @@

聊聊知乎盐选反爬 (回答页篇)

最近,知乎上线了针对专栏[1]中盐选文章的反爬系统,随后该系统也被运用在知乎回答页面中的盐选文章上。具体表现为爬取的文章内容中出现大量的错乱词汇。而在本篇文章中,我们将一步步带领各位解开这些乱码。在这个过程中,我们将对字体反爬有更深入的认识,并学到运用字体反爬时需要注意的问题。

-

一、知乎反爬效果

-

来自知乎回答不被爱是一种什么样的感受? - 知乎

-

乱码示意图

+

一、知乎反爬效果

来自知乎回答不被爱是一种什么样的感受? - 知乎

+

乱码示意图

如图所示,在页面源码中出现了大量乱码,例如(原字,错字):[2]

这些乱码使得文章可读性大大下降,那么乱码是怎么产生的?又如何解决这个问题呢?

-

二、找寻乱码真凶

-

观察上述现象,页面源码中的字,在被显示到页面后,居然变成了正确的字。因此我们初步推断知乎在该页面运用了字体反爬。

+

二、找寻乱码真凶

观察上述现象,页面源码中的字,在被显示到页面后,居然变成了正确的字。因此我们初步推断知乎在该页面运用了字体反爬。

接下来我们打开 F12 -> Network 页面,选择 Font,观察知乎加载的字体。

-

知乎加载的字体

+

知乎加载的字体

右键选择 Open in new tab 将字体保存下来。

-

下载的字体文件

+

下载的字体文件

将字体后缀名改为 .ttf [3] 并打开。

-
正常字体
反爬字体
+
正常字体
反爬字体
+

与正常字体对比,我们下载的字体明显替换了部分字体,这便是知乎用于反爬的字体了。接下来我们将分析这个字体并给出应对方案。

-

三、致命缺陷

-

字体反爬的根本原理是替换原本的字为一个新字,再用字体将新字渲染为原字,这样对程序而言就只见到新字而不是旧字了,而用户看到的还是原本的内容。因此只要找到新字与原字间的对应关系便可解决该反爬。而要找到这个对应关系,抓住字体中各个字形的特征是必不可少的一环。

+

三、致命缺陷

字体反爬的根本原理是替换原本的字为一个新字,再用字体将新字渲染为原字,这样对程序而言就只见到新字而不是旧字了,而用户看到的还是原本的内容。因此只要找到新字与原字间的对应关系便可解决该反爬。而要找到这个对应关系,抓住字体中各个字形的特征是必不可少的一环。

我们打开 FontDrop! 加载字体,向下翻,观察字形的特征。

-

字体中的字形

+

字体中的字形

我们发现字形的 Glyph 为 uni662F 而 Unicode 为 65F6,接下来我们试着查询这两个十六进制数对应的字:

1
2
3
4
glyph = "\u662F"
unicode = "\u65F6"
print(glyph, unicode)
# output: 是 时
+

正好,上文提到,「是」在源码中被替换为了「时」。知乎在反爬字体中保留了原字与新字的对应关系,为我们提供了一个极为便捷的捷径。我们可以直接读取这个对应关系,而不是比对每个字的笔画[4]。然而,这也是其字体反爬系统的致命缺陷,各位在自己的网站运用字体反爬时也要注意这一点。

至此,字形的特征与对应关系都被我们分析出了,接下来我们将编写程序从字体中提取对应关系。

-

四、提取对应关系

-

要提取各个字间的对应关系,首先我们需要安装 fontTools [5]

+

四、提取对应关系

要提取各个字间的对应关系,首先我们需要安装 fontTools [5]

1
pip install fonttools
+

ttLib.TTFont(filename) 打开字体:

1
2
3
from fontTools import ttLib

font = ttLib.TTFont(input("Input font filename: "))
+

初始化一个存储对应关系的字典:

1
zhihu_dict = {}
+

遍历字形,获得其 Glyph 与 Unicode,并写入字典(注意这里的Glyph对应的字可能不是标准的字,比如是康熙部首[6],因此我们要对其标准化[7]):

1
2
3
4
5
6
7
8
from unicodedata import normalize

cmap = font.getBestCmap()

for x in cmap.items():
zhihu_dict[chr(x[0])] = normalize("NFKC", chr(int(x[1][3:], 16)))

print(zhihu_dict) # {'一': '不', ......, '这': '发'}
+

(这里的 cmap 是一个 dict,是字形的 {Unicode: Glyph}[8]

接下来,我们将使用得到的对应关系将带乱码的文章转为正常文章。

-

五、去除乱码

-

这段代码很简单,不作解释。

+

五、去除乱码

这段代码很简单,不作解释。

1
2
3
raw_content = "在间那块奶酪夹心,时饼干被的喜爱了灵魂。"
new_content = raw_content.translate(str.maketrans(zhihu_dict))
print(new_content) # 中间那块奶酪夹心,是饼干被人喜爱的灵魂。
-

六、全部代码

-
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from fontTools import ttLib
from unicodedata import normalize

font = ttLib.TTFont("DynamicFonts30.ttf")

zhihu_dict = {}
cmap = font.getBestCmap()

for x in cmap.items():
zhihu_dict[chr(x[0])] = normalize("NFKC", chr(int(x[1][3:], 16)))

print(zhihu_dict) # {'一': '不', ......, '这': '发'}

raw_content = "在间那块奶酪夹心,时饼干被的喜爱了灵魂。"
new_content = raw_content.translate(str.maketrans(zhihu_dict))
print(new_content) # 中间那块奶酪夹心,是饼干被人喜爱的灵魂。
+ +

六、全部代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from fontTools import ttLib
from unicodedata import normalize

font = ttLib.TTFont("DynamicFonts30.ttf")

zhihu_dict = {}
cmap = font.getBestCmap()

for x in cmap.items():
zhihu_dict[chr(x[0])] = normalize("NFKC", chr(int(x[1][3:], 16)))

print(zhihu_dict) # {'一': '不', ......, '这': '发'}

raw_content = "在间那块奶酪夹心,时饼干被的喜爱了灵魂。"
new_content = raw_content.translate(str.maketrans(zhihu_dict))
print(new_content) # 中间那块奶酪夹心,是饼干被人喜爱的灵魂。
+

温馨提示:上面字体文件名记得换成你自己下载的字体文件名

-

结语

-

在本文的带领下,我们粗略地了解了知乎所使用的反爬技术,分析了其使用的反爬字体,找出了原字与新字的对应关系,最终将带乱码的文章转为了正常文章。其中,知乎使用的反爬字体没有去掉 Unicode 与 Glyph 的对应关系,虽然这使我们更轻松地得到了对应关系,但是对于知乎而言,这种错误无疑是致命的,因此,在字体反爬的实际运用中,我们更需要避免这种错误。[9]

+ +

结语

在本文的带领下,我们粗略地了解了知乎所使用的反爬技术,分析了其使用的反爬字体,找出了原字与新字的对应关系,最终将带乱码的文章转为了正常文章。其中,知乎使用的反爬字体没有去掉 Unicode 与 Glyph 的对应关系,虽然这使我们更轻松地得到了对应关系,但是对于知乎而言,这种错误无疑是致命的,因此,在字体反爬的实际运用中,我们更需要避免这种错误。[9]

知乎也在该反爬系统部署到回答页不久以后升级了其专栏反爬系统,本文所介绍的致命缺陷已被修复[10],而解码新反爬系统的内容,就留到本系列的下篇吧。

(敬请期待)

-

友情链接

-