Python爬虫实例之2021猫眼票房字体加密反爬策略(粗略版)


Posted in Python onFebruary 22, 2021

前言:

猫眼票房页面的字体加密是动态的,每次或者每天加载页面的字体文件都会有所变化,本篇内容针对这种加密方式进行分析

字体加密原理:简单来说就是程序员在设计网站的时候使用了自己设计的字体代码对关键字进行编码,在浏览器加载的时会根据这个字体文件对这些字体进行编码,从而显示出正确的字体。

已知的使用了字体加密的一些网站:
58同城,起点,猫眼,大众点评,启信宝,天眼查,实习僧,汽车之家
本篇内容不过多解释字体文件的映射关系,不了解的请自行查找其他资料。
如若还未入门爬虫,请往这走 简单粗暴入门法——Python爬虫入门篇

import requests
import urllib.request as down
import json
from fontTools.ttLib import TTFont
import re
#分析用
import matplotlib.pyplot as plt #绘图
import numpy as np # 科学计算库

安装:
pip install matplotlib
pip install requests
pip install numpy
pip install fonttools

首先我们对猫眼票房页面进行简单分析

Python爬虫实例之2021猫眼票房字体加密反爬策略(粗略版)

可以看到票房数字在审查中显示的是乱码,类似与这种情况的就可能是使用了字体加密,因此我们需要找到字体文件(字体文件会以链接方式存放在页面中)

Python爬虫实例之2021猫眼票房字体加密反爬策略(粗略版)

找到了字体文件,下载并对映射关系进行分析,可以得到我们需要的一组基础字形映射表;并且可以通过映射关系得到每个字形的所有坐标

baseFont=TTFont('maoyan.woff')
# 获取相应数字的namecode和形状坐标的关系,可用来获取坐标
glyf=baseFont['glyf']
#通过对一份字体样本分析得出的字体映射
baseNumberMaps={
 0:glyf['uniF632'],
 1:glyf['uniF2F1'],
 2:glyf['uniF0A4'],
 3:glyf['uniF7B7'],
 4:glyf['uniE82D'],
 5:glyf['uniF653'],
 6:glyf['uniE756'],
 7:glyf['uniF41A'],
 8:glyf['uniE79B'],
 9:glyf['uniE81E']
}
for num,name in baseNumberMaps.items():
 print(name.coordinates)

Python爬虫实例之2021猫眼票房字体加密反爬策略(粗略版)

我们将坐标绘图成图形,在进行不同组字形图形对比可以发现每套字形的坐标不同,大小比例不同,而字形是不变的,也就是相似

Python爬虫实例之2021猫眼票房字体加密反爬策略(粗略版)

对比坐标发现每套字形坐标都会有所改变,但是整体图形还是同一个,所以我想到了斜率对比,我们计算每个字形部分线段的斜率,如果斜率之差小于一个数值,就说明这两个是相同的数字。

Python爬虫实例之2021猫眼票房字体加密反爬策略(粗略版)

因此就得到了一个思路 获得基础字体映射关系表爬取页面下载所加载的字体获得需要对比的字体映射关系表计算每套字体每个字形的线段斜率,并进行差值计算循环匹配,从基础字形的0-9开始去匹配新字形的斜率,如果斜率之差小于0.5并且样本数>=9我们则认为两个图形为同一个数字,获得正确的字体映射关系对加密字体进行替换得到正确内容

程序实现

import requests
import urllib.request as down
import json
from fontTools.ttLib import TTFont
import re
import MyPyClass

# 得到字体斜率列表(部分)
def font_Kdict(mapstype,maps=None):
 '''
 得到字体斜率字典(部分)
 参数:
 mapstype:str->maps类型,判断是是base/new
 maps:映射字典

 return kdict
 kdict字典关系:
 num:Klist 数字对应每条线段的斜率列表
 '''
 kdict={}
 # 遍历maps字典,找到对应的num和namecode
 for num, namecode in maps.items():
 # 跳过无用数据
 if namecode == 'x': continue
 # 判断类型,并从.coordinates得到对应num的所有坐标
 if mapstype=='base':coordinates = namecode.coordinates
 elif mapstype=='new':coordinates=glyf[namecode].coordinates
 # 得到坐标 X列表和坐标 Y列表
 x = [i[0] for i in coordinates]
 y = [i[1] for i in coordinates]
 Klist = []
 # 遍历X列表并切片为前10个数据进行斜率计算,即代表绘图的前10条线段的斜率
 for index, absx in enumerate(x[:10]):
  # 当斜率为0/1时,认为斜率为1计算
  if x[index + 1] == x[index] or y[index + 1] == y[index]:
  absxy = 1
  else:
  absxy = (y[index + 1] - y[index]) / (x[index + 1] - x[index])
  # 将斜率加入到列表
  Klist.append(-absxy if absxy < 0 else absxy)
 kdict[num]=Klist
 #print('base:', code, Klist, name)
 return kdict
# 对比斜率字典
def contrast_K(kbase,knew):
 '''
 对比斜率映射差距
 参数:
 kbase:基础字体映射表的斜率字典
 knew:当前链接的字体映射表的斜率字典

 return:dict
 fontMaps:根据对比得出正确的字体映射关系字典

 '''
 fontMaps = {}
 # 遍历kbase字典
 for base in kbase.items():
 n = 0 # 成功匹配的斜率个数
 # 遍历knew字典
 for new in knew.items():
  # 遍历kbase>knew>下的两组斜率,进行大小匹配,
  # 如果斜率k的差值小于0.5,并且样本数>=9时,认为两个坐标图形相识只是大小比例不同
  # 即k<=0.5 n>=9
  for (k1,k2) in zip(base[1],new[1]):
  # k取正数
  k=k1-k2 if k1>k2 else k2-k1
  if k<=0.5:
   n+=1
   continue
  else:
   break
  if n>=9:
  # 匹配正确则添加进字典中 此时的字典关系是:code:num 代码对应数字的关系
  fontMaps[str(hex(new[0]).replace('0x','&#x'))]=str(base[0])
  break
  n=0
 #print(fontMaps)
 return fontMaps

# 建立基础字体对象
baseFont=TTFont('maoyan.woff')
# 获取相应数字的namecode和形状坐标的关系,可用来获取坐标
glyf=baseFont['glyf']
#通过对一份字体样本分析得出的字体映射
baseNumberMaps={
 0:glyf['uniF632'],
 1:glyf['uniF2F1'],
 2:glyf['uniF0A4'],
 3:glyf['uniF7B7'],
 4:glyf['uniE82D'],
 5:glyf['uniF653'],
 6:glyf['uniE756'],
 7:glyf['uniF41A'],
 8:glyf['uniE79B'],
 9:glyf['uniE81E']
}
url='https://piaofang.maoyan.com/dashboard-ajax?orderType=0&uuid=1778ad877f8c8-0b23bf32a2bb26-c7d6957-1fa400-1778ad877f8c8&riskLevel=71&optimusCode=10'
ua=MyPyClass.GetUserAgent()#获得ua
# 爬取内容
with requests.get(url,headers={'user-agent':ua}) as response:
 # 获取存放字典的json字段,并提取字体url
 fontStyle=json.loads(response.content)['fontStyle']
 fontStyle=re.findall('\"([\s\S]*?)\"',fontStyle[::-1])
 fonturl='http:'+fontStyle[0][::-1]# 字体url链接
 # 将加载的字体下载保存到本地,并对其进行分析
 down.urlretrieve(fonturl,'newfont.woff')
 # 爬取的电影数据内容
 content = json.loads(response.content)['movieList']['data']['list']
# 信息字典
movieNum={}#综合票房数字典
movieDayOne= {}#上映首日数量
movieRate={}#票房占比
movieshowCount={}#排片场次
movieViewerAvg={}#场均人数
movieInfos={}
# 页面内容
for i in content:
 moviename=i['movieInfo']['movieName']
 movieNum[moviename]=i['boxSplitUnit']['num']
 movieDayOne[moviename]=i['sumBoxDesc']
 movieRate[moviename]=i['splitBoxRate']
 movieshowCount[moviename]=i['showCount']
 movieViewerAvg[moviename]=i['avgShowView']

# 新字体对象
fontnew=TTFont('newfont.woff')
# 得到当前字体的映射关系表
newNumberMaps=fontnew.getBestCmap()
# 获取字形
glyf=fontnew['glyf']
# 基础字体斜率字典
k_base_dict=font_Kdict(maps=baseNumberMaps,mapstype='base')
# 新字体斜率字典
k_new_dict=font_Kdict(maps=fontnew.getBestCmap(),mapstype='new')
# 得到字体映射字典
fontcodes=contrast_K(k_base_dict,k_new_dict)
# 对加密的字体遍历分组,并去除无用字符
for name,numbercode in movieNum.items():
 movieNum[name]=re.findall('([\S]*?);', numbercode)
# 根据得到的fontcodes映射对加密字体进行替换,得到正确数值
for index,(name,numbercodelist) in enumerate(movieNum.items()):
 num=[]
 # 替换操作
 for code in numbercodelist:
 if '.' in code:
  code=code.replace('.','')
  num.append('.'+fontcodes[code])
 else:
  num.append(fontcodes[code])
 infos=['排行:'+str(index+1),
 '片名',name,
 '上映首日',movieDayOne[name],
 '票房',''.join(num)+'万',
 '票房占比',movieRate[name],
 '场均人数',movieViewerAvg[name]+'人',
 '排片场次',movieshowCount[name]]
 print(infos)

实现效果如下

Python爬虫实例之2021猫眼票房字体加密反爬策略(粗略版)

到此这篇关于Python爬虫实例之2021猫眼票房字体加密反爬策略(粗略版)的文章就介绍到这了,更多相关Python爬虫猫眼票房字体反爬内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
python处理圆角图片、圆形图片的例子
Apr 25 Python
django 自定义用户user模型的三种方法
Nov 18 Python
python操作mongodb根据_id查询数据的实现方法
May 20 Python
python解决方案:WindowsError: [Error 2]
Aug 28 Python
Python 操作文件的基本方法总结
Aug 10 Python
Python 数据处理库 pandas 入门教程基本操作
Apr 19 Python
python实现傅里叶级数展开的实现
Jul 21 Python
Python判断对象是否相等及eq函数的讲解
Feb 25 Python
VPS CENTOS 上配置python,mysql,nginx,uwsgi,django的方法详解
Jul 01 Python
Python 离线工作环境搭建的方法步骤
Jul 29 Python
Opencv图像处理:如何判断图片里某个颜色值占的比例
Jun 03 Python
使用django自带的user做外键的方法
Nov 30 Python
python实现计算图形面积
Feb 22 #Python
python实现银行账户系统
Feb 22 #Python
Django实现简单的分页功能
Feb 22 #Python
Python爬虫+tkinter界面实现历史天气查询的思路详解
Feb 22 #Python
Python爬虫设置Cookie解决网站拦截并爬取蚂蚁短租的问题
Feb 22 #Python
Python爬虫爬取微博热搜保存为 Markdown 文件的源码
Feb 22 #Python
Python爬虫制作翻译程序的示例代码
Feb 22 #Python
You might like
php 面向对象的一个例子
2011/04/12 PHP
php UNIX时间戳用法详解
2017/02/16 PHP
jQery使网页在显示器上居中显示适用于任何分辨率
2014/06/09 Javascript
JQuery实现当鼠标停留在某区域3秒后自动执行
2014/09/09 Javascript
js实现温度计时间样式代码分享
2015/08/21 Javascript
微信小程序  modal详解及实例代码
2016/11/09 Javascript
Bootstrap风格的WPF样式
2016/12/07 Javascript
jQuery基本选择器和层次选择器学习使用
2017/02/27 Javascript
Bootstrap实现各种进度条样式详解
2017/04/13 Javascript
vue实现图书管理demo详解
2017/10/17 Javascript
详解微信小程序实现仿微信聊天界面(各种细节处理)
2019/02/17 Javascript
详解如何运行vue项目
2019/04/15 Javascript
vue 路由meta 设置导航隐藏与显示功能的示例代码
2020/09/04 Javascript
详解React路由传参方法汇总记录
2020/11/29 Javascript
JS创建自定义对象的六种方法总结
2020/12/15 Javascript
Python中的filter()函数的用法
2015/04/27 Python
详解Python中映射类型的内建函数和工厂函数
2015/08/19 Python
浅谈Python 集合(set)类型的操作——并交差
2016/06/30 Python
python基础学习之如何对元组各个元素进行命名详解
2018/07/12 Python
Django使用redis缓存服务器的实现代码示例
2019/04/28 Python
Python实现投影法分割图像示例(二)
2020/01/17 Python
PyQt5 如何让界面和逻辑分离的方法
2020/03/24 Python
Python HTMLTestRunner可视化报告实现过程解析
2020/04/10 Python
Python 图片处理库exifread详解
2021/02/25 Python
css3模拟jq点击事件的实例代码
2017/07/06 HTML / CSS
html5 video标签屏蔽右键视频另存为的js代码
2013/11/12 HTML / CSS
客户表扬信范文
2014/01/10 职场文书
迟到检讨书500字
2014/02/05 职场文书
数控技术学生的自我评价
2014/02/15 职场文书
机关中层领导干部群众路线教育实践活动个人对照检查材料
2014/09/24 职场文书
建议书范文
2015/02/05 职场文书
党校学习个人总结
2015/02/15 职场文书
2019公司管理制度
2019/04/19 职场文书
一波干货,会议主持词开场白范文
2019/05/06 职场文书
2019年年中职场激励人心语录30条
2019/08/07 职场文书
AI:如何训练机器学习的模型
2021/04/16 Python