背景交代
在反爬圈子的一个大类, 涉及的网站其实蛮多的, 目前比较常被爬虫 coder 欺负的网站, 猫眼影视, 汽车之家, 大众点评, 58 同城, 天眼查...... 还是蛮多的, 技术高手千千万, 总有五花八门的反爬技术出现, 对于爬虫 coder 来说, 干! 就完了, 反正也 996 了~
作为一个系列的文章, 那免不了, 依旧拿猫眼影视 "学习" 吧, 为什么? 因为它比较典型~
猫眼影视
打开猫眼专业版, 常规操作, 谷歌浏览器, 开发者工具, 抓取 DOM 节点,
https://piaofang.maoyan.com/?ver=normal
注意下图所有的数字位置, 在 DOM 结构中, 都是方块.
字体反爬扫盲
字体反爬, 是一种常见的反爬技术, 网站采用了自定义的字体文件, 在浏览器上正常显示, 但是爬虫抓取下来的数据要么就是乱码, 要么就是变成其他字符. 采用自定义字体文件是 CSS3 的新特性, 熟悉前端的同学可能知道, 就是 font-face 属性.
一些重要破解素材的收集
找到 font-family 属性, 查看设置的内容, 发现是 cs 字体, 这明显是自定义字体了, 在网页中检索 cs.
在页面的 html 源码中找到了字体的定义
注意文件的开头是 base64 表示文件进行过 base64 编码, 需要进行解码, 然后在保存成 ttf 字体文件
上述截图中有个 woff 格式
web 开放字体格式 (Web Open Font Format, 简称 WOFF) 是一种网页所采用的字体格式标准. 此字体格式发展于 2009 年, 现在正由万维网联盟的 Web 字体工作小组标准化, 以求成为推荐标准. 此字体格式不但能够有效利用压缩来减少档案大小, 并且不包含加密也不受 DRM(数位著作权管理) 限制.
解码操作
- import base64
- font_face = "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"
- print(len(font_face))
- b = base64.b64decode(font_face)
- with open('font.ttf','wb') as f:
- f.write(b)
对于 ttf 文件的处理, 有 3 种方式, 第一种使用软件 FontCreator 可以直接打开 ttf 文件, 第二种使用 Python 第三方库 fontTools, 借用这个库也可以操作 ttf 文件, 第三种使用百度的 fontstore,
FontCreator 软件查找这个就比较简单了
你可以自行百度寻找, 也可以直接打开我的百度网盘下载
链接: https://pan.baidu.com/s/1ZyWwk37hNeo0vIsTqdK2fg 提取码: kk2h
安装完毕, 直接试用即可, 也可以采用国家支持的和谐方法, 进行和谐
查阅一下 sources 里面的 HTML 编码
数字进行比对
顺便把这个地方的编码对应关系记录一下, 方便后续操作
- 'uniE481': '7',
- 'uniE0AA': '4',
- 'uniF71E': '9',
- 'uniE767': '1',
- 'uniE031': '5',
- 'uniE4BD': '2',
- 'uniF2AA': '3',
- 'uniE2E3': '6',
- 'uniE3C9': '8',
- 'uniEA65': '0'
数字比对完全没有问题 3.69 亿
开始编码破解字体反爬
有的网页嵌套了多套字体, 增加了反爬的成本, 届时自行研究即可
利用 fontTools 可以获取每一个字符对象, 这个对象你可以简单的理解为保存着这个字符的形状信息.
而且编码可以作为这个对象的 id, 具有一一对应的关系.
类似猫眼电影, 多套字体对应的字符的编码是变化的, 但是字符的形状是不变的, 也就是说这个对象是不变的.
通过 fontTools 进行解析字库文件
安装 fonttools
pip install fonttools
fontTools 库详解: https://darknode.in/font/font-tools-guide/
基本使用
- from fontTools.ttLib import TTFont
- font = TTFont('font.ttf')
- font.saveXML('01.xml')
打开 xml 文件
开头显示的是全部编码, 注意这里的 ID 是编号, 千万不要当成对应的数字
下面对应的是字体信息, 计算机只需要知道黑白像素点即可
注意事项, 写代码的时候需要注意一下
关于猫眼的字体反爬做个总结
在实操中, 你会发现猫眼电影, 每次刷新字符编码都是变化的, 但是字体的对象, 也就是像素点是一致的.
你可以通过第一次下载一个字体文件 base_font.ttf, 并把对应编码的记下来, 当第二次刷新页面之后, 重新抓取字体文件 online_font.ttf , 对比两个字体文件中的对象信息, 如果对象是一样的, 那么就可以知道对应的数字了.
首次获取字体文件
- # 本地已经下载好的字体处理
- base_font = TTFont('font.ttf') #打开本地的 ttf 文件
- base_uni_list = base_font.getGlyphOrder()[2:] # 获取所有编码, 去除前 2 个, 可查看前文图示
- # 写出第一次字体文件的编码和对应字体
- origin_dict = {
- 'uniE481': '7', 'uniE0AA': '4', 'uniF71E': '9', 'uniE767': '1', 'uniE031': '5', 'uniE4BD': '2','uniF2AA': '3', 'uniE2E3': '6', 'uniE3C9': '8', 'uniEA65': '0'
- }
获取在线字体
- # 获取刷新之后在线的字体
- # 获取字体文件的 base64 编码
- online_ttf_base64 = re.findall(r"base64,(.*)\) format", response)[0]
- online_base64_info = base64.b64decode(online_ttf_base64)
- with open('online_font.ttf', 'wb')as f:
- f.write(online_base64_info)
- online_font = TTFont('online_font.ttf') # 网上动态下载的字体文件.
- online_uni_list = online_font.getGlyphOrder()[2:]
- for uni2 in online_uni_list:
- obj2 = online_font['glyf'][uni2] # 获取编码 uni2 在 online_font.ttf 中对应的对象
- for uni1 in base_uni_list:
- obj1 = base_font['glyf'][uni1] # 获取编码 uni1 在 base_font.ttf 中对应的对象
- if obj1 == obj2: # 判断两个对象是否相等
- dd = "&#x" + uni2[3:].lower() + ';' # 修改为 Unicode 编码格式
- if dd in response: # 如果编码 uni2 的 Unicode 编码格式 在 response 中, 替换成 origin_dict 中的数字.
- response = response.replace(dd, origin_dict[uni1])
response 的获取采用的是 request 模块
- url = 'https://piaofang.maoyan.com/?ver=normal'
- headers = {
- 'User-Agent': '浏览器 UA',
- 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
- }
- response = requests.get(url=url, headers=headers).content # 得到字节
- charset = chardet.detect(response).get('encoding') # 得到编码格式
- response = response.decode(charset, "ignore") # 解码得到字符串
运行结果展示
关注微信公众账号: 非本科程序员, 回复 0409 获取下载地址
来源: https://www.cnblogs.com/happymeng/p/10763665.html