海安零距离 海安论坛 海安新闻 海安

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 2185|回复: 0

深入细枝末节,Python的字体反爬虫到底怎么一回事

[复制链接]

6234

主题

6234

帖子

1万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
18716
发表于 2019-12-27 18:15 | 显示全部楼层 |阅读模式
内容选自 即将出书 的《Python3 反爬虫原理与绕过实战》,本次公开书稿范围为第 6 章——文本肴杂反爬虫。本篇为第 6 章中的第 4 小节,别的小节将 徐徐放送

字体反爬虫开篇概述

在 CSS3 之前,Web 开发者必须利用用户盘算机上已有的字体。但是在 CSS3 时代,开发者可以利用@font-face 为网页指定字体,对用户盘算机字体的依靠。开发者可将心仪的字体文件放在 Web 服务器上,并在 CSS 样式中利用它。用户利用欣赏器访问 Web 应用时,对应的字领会被欣赏器下载到用户的盘算机上。
[img=auto,auto]http://www.dlct.net/https://upload-images.jianshu.io/upload_images/20592807-39c89505b890a673?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240[/img]

在学习欣赏器和页面渲染的相关知识时,我们相识到 CSS 的作用是修饰 HTML ,以是在页面渲染的时候不会改变 HTML 文档内容。由于字体的加载和映射工作是由 CSS 完成的,以是纵然我们借助 Splash、Selenium 和 Puppeteer 工具也无法获得对应的笔墨内容。字体反爬虫正是利用了这个特点,将自界说字体应用到网页中告急的数据上,使得爬虫步伐无法获得精确的数据。
6.4.1 字体反爬虫示例

示例 7:字体反爬虫示例。
网址: http://www.porters.vip/confus...
任务:爬取影片信息展示页中的影片评分、评价人数和票房数据,页面内容如图 6-32 所示。

图 6-32 示例 7 页面
在编写代码之前,我们须要确定目的数据的元素定位。定位时,我们在 HTML 中发现了一些奇怪的符号,HTML 代码如下:
  1. <div class="movie-index">
复制代码
页面中告急的数据都是一些奇怪的字符,本应该表现“9.7”的地方在 HTML 中表现的是“.”,而本应该表现“56.83”的地方在 HTML 中表现的是“.”。与 6.3 节中的映射反爬虫差别,案例中的笔墨都被“”符号取代了,根本无法分辨。这就很奇怪了,“”能代表这么多种数字吗?
要注意的是,Chrome 开发者工具的元素面板中表现的内容不愿定是相应正文的原文,要想知道“”符号是什么,还须要到网页源代码中确认。对应的网页源代码如下:
  1. <div class="movie-index">
复制代码
从网页源代码中看到的并不是符号,而是由 开头的一些字符,这与示例 6 中的 SVG 映射反爬虫非常相似。我们将页面表现的数字与网页源代码中的字符举行比力,映射关系如图 6-33 所示。

图 6-33 字符与数字的映射关系
字符与数字是一一对应的,我们只须要多找一些页面,将 0 ~ 9 数字对应的字符凑齐即可。但假如目的网站的字体是动态厘革的呢?映射关系也是厘革的呢?
根据 6.3 节的学习和分析,我们知道人为映射并不能解决这些问题,必须找到映射关系的规律,并利用 Python 代码实现映射算法才行。继承往下分析,岂非字符映射是先异步加载数据再利用 JavaScript 渲染的?

图 6-34 哀求纪录
网络哀求纪录如图 6-34 所示,哀求纪录中并没有发现异步哀求,这个推测并没有得到证明。CSS 样式方面有没有线索呢?页面中包裹符号的标签的 class 属性值都是 stonefont:
  1. class="stonefont">.
复制代码
但对应的 CSS 样式中仅设置了字体:
  1. .stonefont {
复制代码
既然是自界说字体,就意味着会加载字体文件,我们可以在网络哀求中找到加载的字体文件 movie.woff,并将其下载到当地,接着利用百度字体编辑器看一看内里的内容。
百度字体编辑器 FontEditor (详见 http://fontstore.baidu.com/st... )是一款在线字体编辑软件,可以或许打开当地或者长途的 ttf、woff、eot、otf 格式的字体文件,具备这些格式字体文件的导入和导出功能,而且提供字形编辑、轮廓编辑和字体实时预览功能,界面如图 6-35 所示。

图 6-35 百度字体编辑器界面
打开页面后,将 movie.woff 文件拖曳到百度字体编辑器的灰色地区即可,字体文件内容如图 6-36 所示。

图 6-36 字体文件 movie.woff 预览
该字体文件中共有 12 个字体块,此中包罗 2 个空白字体块和 0 ~ 9 的数字字体块。我们可以大胆地推测,评分数据和票房数据中利用的数字正是以后而来。
由此看来,我们还须要相识一些字体文件格式相关的知识,在相识文件格式和规律后,才可以或许找到更公道的解决办法。
6.4.2 字体文件 WOFF

WOFF(Web Open Font Format,Web 开放字体格式)是一种网页所采用的字体格式尺度。本质上基于 SFNT 字体(如 TrueType),以是它具备 TrueType 的字体结构,我们只须要相识 TrueType 字体的相关知识即可。
TrueType 字体是苹果公司与微软公司连合开发的一种盘算机轮廓字体,TrueType 字体中的每个字形由网格上的一系列点形貌,点是字体中的最小单位,字形与点的关系如图 6-37 所示。

图 6-37 字形与点的关系
字体文件中不光包含字形数据和点信息,还包罗字符到字形映射、字体标题、命名和程度指标等,这些信息存在对应的表中,以是我们也可以认为 TrueType 字体文件由一系列的表构成,此中常用的表
及其作用如图 6-38 所示。

图 6-38 构成字体文件的常用表及其作用
怎样检察这些表的结构和所包含的信息呢?我们可以借助第三方 Python 库 fonttools 将 WOFF 等字体文件转换成 XML 文件,这样就能检察字体文件的结构和表信息了。首先我们要安装 fonttools 库, 安装下令为:
  1. $ pip install fonttools
复制代码
安装完毕后就可以利用该库转换文件范例,对应的 Python 代码为:
  1. from fontTools.ttLib import TTFont
复制代码
代码运行后就会在当前目次天生名为 movie 的 XML 文件。文件中字符到字形映射表 cmap 的内容如下:
  1. [/code]map 标签中的 code 代表字符,name 代表字形名称,关系如图 6-39 所示。
  2. [align=center][img]http://www.dlct.net/https://img2.tuicool.com/6VJ773i.jpg!web[/img][/align]
  3. 图 6-39 字符到字形映射关系示例
  4. XML 中的字符 0xe339 与网页源代码中的字符 对应,这样我们就确定了 HTML 中的字符码与 movie.woff 字体文件中对应的字形关系。字形数据存储在 glyf 表中,每个字形的数据都是独立的,比方字形 uniE339 的字形数据如下:
  5. [code]
复制代码
TTGlyph 标签中纪录着字形的名称、
x
轴坐标和
y
轴坐标(坐标也可以明白为字形的宽高)。contour 标签纪录的是字形的轮廓信息,也就是多个点的坐标位置,正是这些点构成了如图 6-40 所示的字形。

图 6-40 字形 uniE339 的轮廓
我们可以在百度字体编辑器中调解点的位置,然后生存字体文件并将新字体文件转换为 XML 格式,相同名称的字形数据如下:
  1. [/code]接着将调解前的字形数据和调解后的字形数据举行对比。
  2. 如图 6-41 所示,点的位置调解后,字形数据也会发生相应的厘革,如 xMin、xMax、yMin、yMax 还有 pt 标签中的 x 坐标 y 坐标都与之前的差别了。
  3. [align=center][img]http://www.dlct.net/https://img1.tuicool.com/F7VfMz2.jpg!web[/img][/align]
  4. 图 6-41 字形数据对比
  5. XML 文件中纪录的是字形坐标信息,实际上,我们没有办法直接通过字形数据获得笔墨,只能从其他方面想办法。固然目的网站利用多套字体,但相同笔墨的字形也是相同的。好比现在有 movie.woff 和 food.woff 这两套字体,它们包含的字形如下:
  6. [code]# movie.woff
复制代码
要实现主动识别笔墨,须要先准备参照字形,也就是人为地准备数字 0 ~ 9 的字形映射关系和字形数据,如:
  1. # 0 和 7 与字形名称的映射伪代码,data 键对应的值是字形数据
复制代码
当我们遇到目的网站上其他字体文件时,就可以利用参照字形中的字形数据与目的字形举行匹配,假如字形数据非常靠近,就认为这两个字形形貌的是相同的笔墨。字形数据包含纪录字形名称和字形起止坐标的 TTGlyph 标签以及纪录点坐标的 pt 标签,起止坐标代表的是字形在画布上的位置,点坐标代表字形中每个点在画布上的位置。在起止坐标中,
x
轴差值代表字形宽度,
y
轴差值代表字形高度。
如图 6-42 所示,两个字形的起止坐标和宽高都有很大的差别,但是却可以或许形貌相同的笔墨,以是字形在画布中的位置并不会影响形貌的笔墨,字形宽度和字形高度也不会影响形貌的笔墨。

图 6-42 形貌相同笔墨的两个字形
点坐标的数量和坐标值可以作为比力条件吗?
如图 6-43 所示,两个差别笔墨的字形数据是不一样的。固然这两种字形的 name 都是 uniE9C7,但是字形数据中大部分 pt 标签 x 和 y 的差距都很大,以是我们可以判定这两个字形形貌的并不是
同一个笔墨。你大概会想到点的数量也可以作为清除条件,也就是说假如点的数量不相同,那么这个
两个字形形貌的就不是同一个笔墨。真的是这样吗?

图 6-43 形貌差别笔墨的字形数据对比
在图 6-44 中,左侧形貌笔墨 7 的字形有 17 个点,而右侧形貌笔墨 7 的字形却有 20 个点。对应的字形信息如图 6-45 所示。

图 6-44 形貌相同笔墨的字形

图 6-45 形貌相同笔墨的字形信息
固然点的数量不一样,但是它们的字形并没有太大的厘革,也不会造成用户误读,以是点的数量并不能作为清除差别字形的条件。因此,只有起止坐标和点坐标数据完全相同的字形,形貌的才是相同字符。
6.4.3 字体反爬虫绕过实战

要确定两组字形数据形貌的是否为相同字符,我们必须取出 HTML 中对应的字形数据,然后将待确认的字形与我们准备好的基准字形数据举行对比。现在我们来整理一下这一系列工作的步调。
(1) 准备基准字形形貌信息。
(2) 访问目的网页。
(3) 从目的网页中读取字体编码字符。
(4) 下载 WOFF 文件并用 Python 代码打开。
(5) 根据字体编码字符找到 WOFF 文件中的字形轮廓信息。
(6) 将该字形轮廓信息与基准字形轮廓信息举行对比。
(7) 得出对比效果。
我们先完成前 4 个步调的代码。下载 WOFF 文件并将此中字形形貌的笔墨与人类认知的笔墨举行映射。由于字形数据比力巨大,以是我们可以将字形数据举行散列盘算,这样得到的效果既简短又唯一,不会影响对比效果。这里以数字 0 ~ 9 为例:
  1. base_font = {
复制代码
字典中的 name 代表该字形的名称,value 代表该字形形貌的笔墨,hex 代表字形信息的 MD5 值。
思量到网络哀求纪录中的字体文件路径有大概会厘革,我们必须找到 CSS 中设定的字体文件路径,引入 CSS 的 HTML 代码为:
  1. [/code]由引入代码得知该 CSS 文件的路径为 [url=http://www.porters.vip/confusion/css/movie.css]http://www.porters.vip/confus...[/url] ,文件中 @font-face 处就是设置字体的代码:
  2. [code]@font-face {
复制代码
字体文件路径为 http://www.porters.vip/confus... 。找到文件后,我们就可以开始编写代码了,对应的 Python 代码如下:
  1. import re
复制代码
由于 TTFont 可以直接读取 woff 文件的结构,以是这里不须要将 woff 生存为 XML 文件。接着以评分数据 9.7 对应的编码 #xe624.#xe9c7 举行测试,在原来的代码中引入基准字体数据 base_font,然后新增以下代码:
  1. web_code = '.'
复制代码
以上代码运行效果为:
  1. ['9', '7']
复制代码
运行效果阐明可以或许精确映射字体文件中字形形貌的笔墨。
6.4.4 小结

字体爬能给爬虫工程师带来很大的贫困。固然爬虫工程师找到了应对方法,但这种方法依靠的条件比力严苛,假如开发者频仍改动字体文件或准备多套字体文件并随机切换,那真是一件令爬虫工程师头疼的事。不外,这些工尴尬刁难于开发者来说也不是轻松的事。
转载阐明


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|深圳论坛-深圳人的网上家园  

GMT+8, 2020-6-3 11:10 , Processed in 0.141925 second(s), 30 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表