Python爬虫入门教程 63-100 Python字体反爬之一,没办法,这个必须写,反爬第3篇
背景交代
在反爬圈子的一个大类,涉及的网站其实蛮多的,目前比较常被爬虫coder欺负的网站,猫眼影视,汽车之家,大众点评,58同城,天眼查......还是蛮多的,技术高手千千万,总有五花八门的反爬技术出现,对于爬虫coder来说,干!就完了,反正也996了~
作为一个系列的文章,那免不了,依旧拿猫眼影视“学习”吧,为什么?因为它比较典型~
猫眼影视
打开猫眼专业版,常规操作,谷歌浏览器,开发者工具,抓取DOM节点,
注意下图所有的数字位置,在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, http://fontstore.baidu.com/static/editor/index.html
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获取下载地址
Python爬虫入门教程 63-100 Python字体反爬之一,没办法,这个必须写,反爬第3篇的更多相关文章
- Python爬虫入门教程 48-100 使用mitmdump抓取手机惠农APP-手机APP爬虫部分
1. 爬取前的分析 mitmdump是mitmproxy的命令行接口,比Fiddler.Charles等工具方便的地方是它可以对接Python脚本. 有了它我们可以不用手动截获和分析HTTP请求和响应 ...
- Python爬虫入门教程 43-100 百思不得姐APP数据-手机APP爬虫部分
1. Python爬虫入门教程 爬取背景 2019年1月10日深夜,打开了百思不得姐APP,想了一下是否可以爬呢?不自觉的安装到了夜神模拟器里面.这个APP还是比较有名和有意思的. 下面是百思不得姐的 ...
- Python爬虫入门教程 37-100 云沃客项目外包网数据爬虫 scrapy
爬前叨叨 2019年开始了,今年计划写一整年的博客呢~,第一篇博客写一下 一个外包网站的爬虫,万一你从这个外包网站弄点外快呢,呵呵哒 数据分析 官方网址为 https://www.clouderwor ...
- Python爬虫入门教程 36-100 酷安网全站应用爬虫 scrapy
爬前叨叨 2018年就要结束了,还有4天,就要开始写2019年的教程了,没啥感动的,一年就这么过去了,今天要爬取一个网站叫做酷安,是一个应用商店,大家可以尝试从手机APP爬取,不过爬取APP的博客,我 ...
- Python爬虫入门教程 2-100 妹子图网站爬取
妹子图网站爬取---前言 从今天开始就要撸起袖子,直接写Python爬虫了,学习语言最好的办法就是有目的的进行,所以,接下来我将用10+篇的博客,写爬图片这一件事情.希望可以做好. 为了写好爬虫,我们 ...
- Python爬虫入门教程 1-100 CentOS环境安装
简介 你好,当你打开这个文档的时候,我知道,你想要的是什么! Python爬虫,如何快速的学会Python爬虫,是你最期待的事情,可是这个事情应该没有想象中的那么容易,况且你的编程底子还不一定好,这套 ...
- Python爬虫入门教程 61-100 写个爬虫碰到反爬了,动手破坏它!
python3爬虫遇到了反爬 当你兴冲冲的打开一个网页,发现里面的资源好棒,能批量下载就好了,然后感谢写个爬虫down一下,结果,一顿操作之后,发现网站竟然有反爬措施,尴尬了. 接下来的几篇文章,我们 ...
- Python爬虫入门教程 20-100 慕课网免费课程抓取
写在前面 美好的一天又开始了,今天咱继续爬取IT在线教育类网站,慕课网,这个平台的数据量并不是很多,所以爬取起来还是比较简单的 准备爬取 打开我们要爬取的页面,寻找分页点和查看是否是异步加载的数据. ...
- Python爬虫入门教程 10-100 图虫网多线程爬取
图虫网-写在前面 经历了一顿噼里啪啦的操作之后,终于我把博客写到了第10篇,后面,慢慢的会涉及到更多的爬虫模块,有人问scrapy 啥时候开始用,这个我预计要在30篇以后了吧,后面的套路依旧慢节奏的, ...
- Python爬虫入门教程 60-100 python识别验证码,阿里、腾讯、百度、聚合数据等大公司都这么干
常见验证码 之前的博客中已经解决了一些常见验证码的问题,但是验证码是层出不穷的,目前解决验证码除了通过常规手段解决以外,还可以通过人工智能领域的深度学习去解决 深度学习?! 无疑对爬虫coder提高了 ...
随机推荐
- DDGScreenShot —图片加各种滤镜高逼格操作
写在前面 图片加各种滤镜操作,当然苹果给开发者提供了相关的api和封装, 大部分开发者感觉这是这是晦涩难懂的,接下来就让我们来了解一下, 其实也没有那么深不可测. 代码如下(每一步已经解释的很详细) ...
- 分布式服务通讯框架XXL-RPC
<分布式服务通讯框架XXL-RPC> 一.简介 1.1 概述 XXL-RPC 是一个分布式服务通讯框架,提供稳定高性能的RPC远程服务调用功能.现已开放源代码,开箱即用. 1.2 特 ...
- python奇技淫巧——max/min函数的用法
本文以max()为例,对min/max内建函数进行说明 源码 def max(*args, key=None): # known special case of max ""&qu ...
- ImportError: numpy.core.multiarray failed to import
1. ImportError: numpy.core.multiarray failed to import pip install -U numpy http://stackoverflow.com ...
- 使用伪类before和after
.content { padding: 20px } .content::before { content: "我是before添加的内容"; font-weight: bold ...
- ImportError: cannot import name webdriver
遇到问题: 学习selenium过程中为了方便自己知道学习的脚本的存放路径,以selenium命名 起初.py文件都在selenium文件夹下面,使用 from selenium import web ...
- Spring Boot 发送邮件
需求 最近因为业务的变更,需要对老用户进行发送邮件处理.目前市面上也有很多代发邮件的接口,可以接入.由于量不是特别大,放弃了这个途径.改用我们自己通过 smtp 发送邮件来处理. 技术选择 Java ...
- 【多线程】-ThreadPool线程池
ThreadPool介绍: Thread类是一个静态类,所有不存在实例化构造函数操作,直接可以调用其内所存在的方法. 微软官网给出的解释: 提供一个线程池,该线程池可用于执行任务.发送工作项.处理异步 ...
- JAVAEE——Mybatis第一天:入门、jdbc存在的问题、架构介绍、入门程序、Dao的开发方法、接口的动态代理方式、SqlMapConfig.xml文件说明
1. 学习计划 第一天: 1.Mybatis的介绍 2.Mybatis的入门 a) 使用jdbc操作数据库存在的问题 b) Mybatis的架构 c) Mybatis的入门程序 3.Dao的开发方法 ...
- codeforces 983B XOR-pyramid
题意: 定义一个函数f(a): 给出一个数组a,有q个询问,每次询问回答在l到r的区间内,连续子串的f函数的最大值. 思路: 画图,来自codeforces SheepRanger 由此图可知,f(l ...