https://blog.csdn.net/qq_31032181/article/details/79153578

一、背景

字体反爬应用还是很普遍。这两天有朋友咨询如何实现猫眼票房数据的爬取,这里其实与上面的文章核心思想是一致的,但是操作更复杂一些,本文做一个更详细的破解实践。

有对字体反爬还比较陌生的,请参考前文。

二、查找字体源

猫眼电影是美团旗下的一家集媒体内容、在线购票、用户互动社交、电影衍生品销售等服务的一站式电影互联网平台。2015年6月,猫眼电影覆盖影院超过4000家,这些影院的票房贡献占比超过90%。目前,猫眼占网络购票70%的市场份额,每三张电影票就有一张出自猫眼电影,是影迷下载量较多、使用率较高的电影应用软件。同时,猫眼电影为合作影院和电影制片发行方提供覆盖海量电影消费者的精准营销方案,助力影片票房。

我们使用Chrome浏览页面,并查看源码,发现售票中涉及数字的,在页面显示正常,在源码中显示一段span包裹的不可见文本。

上面其实就是自定义字体搞的鬼。根据网页源码中,

<span class="stonefont">.</span>

使用了自定义的stonefont字体,我们在网页中查找stonefont,很快有了发现,这就是标准的@font-face定义方法。且每次访问,字体文件访问地址都会随机变化。

我们访问其中woff文件的地址,可将woff字体文件下载到本地。前文中fonttools并不能直接解析woff字体,我们需要将woff字体转换成otf字体。百度可以直接转换字体 ,地址:http://fontstore.baidu.com/static/editor/index.html

三、字体解析

otf就是我们常用的字体文件,可以使用系统自带的字体查看器查看,但是难以看到更多有效的信息,我们使用一个专用工具Font Creator查看。

可以看到,这个字体里有12个字(含一个空白字),每个字显示其字形和其字形编码。这里比之前字体解析更复杂的是,这里不仅字体编码每次都会变,字体顺序每次也会变,很难直接通过编码和顺序获取实际的数字。

因此,我们需要预先下载一个字体文件,人工识别其对应数值和字体,然后针对每次获取的新的字体文件,通过比对字体字形数据,得到其真实的数字值。

下面是使用fontTools.ttLib获取的单个字符的字形数据。

  1. <TTGlyph name="uniE183" xMin="0" yMin="-12" xMax="516" yMax="706">

  2. <contour>

  3. <pt x="134" y="195" on="1"/>

  4. <pt x="144" y="126" on="0"/>

  5. <pt x="217" y="60" on="0"/>

  6. <pt x="271" y="60" on="1"/>

  7. <pt x="335" y="60" on="0"/>

  8. <pt x="423" y="158" on="0"/>

  9. <pt x="423" y="311" on="0"/>

  10. <pt x="337" y="397" on="0"/>

  11. <pt x="270" y="397" on="1"/>

  12. <pt x="227" y="397" on="0"/>

  13. <pt x="160" y="359" on="0"/>

  14. <pt x="140" y="328" on="1"/>

  15. <pt x="57" y="338" on="1"/>

  16. <pt x="126" y="706" on="1"/>

  17. <pt x="482" y="706" on="1"/>

  18. <pt x="482" y="622" on="1"/>

  19. <pt x="197" y="622" on="1"/>

  20. <pt x="158" y="430" on="1"/>

  21. <pt x="190" y="452" on="0"/>

  22. <pt x="258" y="475" on="0"/>

  23. <pt x="293" y="475" on="1"/>

  24. <pt x="387" y="475" on="0"/>

  25. <pt x="516" y="346" on="0"/>

  26. <pt x="516" y="243" on="1"/>

  27. <pt x="516" y="147" on="0"/>

  28. <pt x="459" y="75" on="1"/>

  29. <pt x="390" y="-12" on="0"/>

  30. <pt x="271" y="-12" on="1"/>

  31. <pt x="173" y="-12" on="0"/>

  32. <pt x="112" y="42" on="1"/>

  33. <pt x="50" y="98" on="0"/>

  34. <pt x="42" y="188" on="1"/>

  35. </contour>

  36. <instructions/>

  37. </TTGlyph>

使用下面语句可以获取顺序的字符编码值,

  1. # 解析字体库font文件

  2. baseFont = TTFont('base.otf')

  3. maoyanFont = TTFont('maoyan.otf')

  4. uniList = maoyanFont['cmap'].tables[0].ttFont.getGlyphOrder()

  5. numList = []

  6. baseNumList = ['.', '3', '5', '1', '2', '7', '0', '6', '9', '8', '4']

  7. baseUniCode = ['x', 'uniE64B', 'uniE183', 'uniED06', 'uniE1AC', 'uniEA2D', 'uniEBF8',

  8. 'uniE831', 'uniF654', 'uniF25B', 'uniE3EB']

  9. for i in range(1, 12):

  10. maoyanGlyph = maoyanFont['glyf'][uniList[i]]

  11. for j in range(11):

  12. baseGlyph = baseFont['glyf'][baseUniCode[j]]

  13. if maoyanGlyph == baseGlyph:

  14. numList.append(baseNumList[j])

  15. break

四、内容替换

关键点攻破了,整个工作就好做了。先访问需要爬取的页面,获取字体文件的动态访问地址并下载字体,读取用户帖子文本内容,替换其中的自定义字体编码为实际文本编码,就可复原网页为页面所见内容了。

完整代码如下:

 
 
  1. # -*- coding:utf-8 -*-

  2. import requests

  3. from lxml import html

  4. import re

  5. import woff2otf

  6. from fontTools.ttLib import TTFont

  7. from bs4 import BeautifulSoup as bs

  8. #抓取maoyan票房

  9. class MaoyanSpider:

  10. #页面初始化

  11. def __init__(self):

  12. self.headers = {

  13. "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",

  14. "Accept-Encoding": "gzip, deflate, br",

  15. "Accept-Language": "zh-CN,zh;q=0.8",

  16. "Cache-Control": "max-age=0",

  17. "Connection": "keep-alive",

  18. "Upgrade-Insecure-Requests": "1",

  19. "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",

  20. "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.86 Safari/537.36"

  21. }

  22. # 获取票房

  23. def getNote(self):

  24. url = "http://maoyan.com/cinema/15887?poi=91871213"

  25. host = {'host':'maoyan.com',

  26. 'refer':'http://maoyan.com/news',}

  27. headers = dict(self.headers.items() + host.items())

  28. # 获取页面内容

  29. r = requests.get(url, headers=headers)

  30. #print r.text

  31. response = html.fromstring(r.text)

  32. u = r.text

  33. # 匹配ttf font

  34. cmp = re.compile(",\n url\('(//.*.woff)'\) format\('woff'\)")

  35. rst = cmp.findall(r.text)

  36. ttf = requests.get("http:" + rst[0], stream=True)

  37. with open("maoyan.woff", "wb") as pdf:

  38. for chunk in ttf.iter_content(chunk_size=1024):

  39. if chunk:

  40. pdf.write(chunk)

  41. # 转换woff字体为otf字体

  42. woff2otf.convert('maoyan.woff', 'maoyan.otf')

  43. # 解析字体库font文件

  44. baseFont = TTFont('base.otf')

  45. maoyanFont = TTFont('maoyan.otf')

  46. uniList = maoyanFont['cmap'].tables[0].ttFont.getGlyphOrder()

  47. numList = []

  48. baseNumList = ['.', '3', '5', '1', '2', '7', '0', '6', '9', '8', '4']

  49. baseUniCode = ['x', 'uniE64B', 'uniE183', 'uniED06', 'uniE1AC', 'uniEA2D', 'uniEBF8',

  50. 'uniE831', 'uniF654', 'uniF25B', 'uniE3EB']

  51. for i in range(1, 12):

  52. maoyanGlyph = maoyanFont['glyf'][uniList[i]]

  53. for j in range(11):

  54. baseGlyph = baseFont['glyf'][baseUniCode[j]]

  55. if maoyanGlyph == baseGlyph:

  56. numList.append(baseNumList[j])

  57. break

  58. uniList[1] = 'uni0078'

  59. utf8List = [eval("u'\u" + uni[3:] + "'").encode("utf-8") for uni in uniList[1:]]

  60. # 获取发帖内容

  61. soup = bs(u,"html.parser")

  62. index=soup.find_all('div', {'class': 'show-list'})

  63. print '---------------Prices-----------------'

  64. for n in range(len(index)):

  65. mn=soup.find_all('h3', {'class': 'movie-name'})

  66. ting=soup.find_all('span', {'class': 'hall'})

  67. mt=soup.find_all('span', {'class': 'begin-time'})

  68. mw=soup.find_all('span', {'class': 'stonefont'})

  69. for i in range(len(mt)):

  70. moviename=mn[i].get_text()

  71. film_ting = ting[i].get_text()

  72. movietime=mt[i].get_text()

  73. moviewish=mw[i].get_text().encode('utf-8')

  74. for i in range(len(utf8List)):

  75. moviewish = moviewish.replace(utf8List[i], numList[i])

  76. print moviename,film_ting,movietime,moviewish

  77. spider = MaoyanSpider()

  78. spider.getNote()

解析访问,获取数据(最后一列是加密破解后的数据)。

Python爬虫杂记 - 字体文件反爬(二)

https://www.jianshu.com/p/0e2e1aa6d270

在线字体转化工具

https://www.fontke.com/tool/convfont/

如何爬取猫眼网电影票房数据相关推荐

  1. 爬取猫眼十万条评论数据

    爬取猫眼十万条评论数据 写在之前 我之前看了一些关于抓包的文章,还以为猫眼的接口都要通过fiddler去抓包,但是我错了,fiddler出了点问题,后来用夜神模拟器去模拟手机,但是一直抓不到想要的包, ...

  2. 爬取东方财富网股票行情数据和资讯

    爬取东方财富网股票行情数据和资讯 这个需求源于我的一个练手项目 本篇博客参考:https://zhuanlan.zhihu.com/p/50099084 该博客介绍的东西本博客不做论述 使用技术: 语 ...

  3. python爬取火车票网的时刻表数据

    python爬取火车票网的时刻表数据 导包 import re,requests,datetime,time,json from prettytable import PrettyTable from ...

  4. python二手房价格预测_Python爬取赶集网北京二手房数据R对爬取的二手房房价做线性回归分析...

    前言:本文主要分为两部分:Python爬取赶集网北京二手房数据&R对爬取的二手房房价做线性回归分析.文章思路清晰,代码详细,特别适合刚刚接触Python&R的同学学习参考. Part1 ...

  5. 2021年挖掘猫眼专业版电影票房数据

    概述 自己看着玩玩,如有侵权,请联系我,立刻删除 爬取关键点 1.猫眼票房字体动态加密,需要破解 2.截止今日20210101-20211214,有350天左右,需要ip代理池,Proxypool,代 ...

  6. windows 利用R定时抓取猫眼专业版电影票房

    1.在mysql创建数据库,表 2.网址 猫眼专业版:http://piaofang.maoyan.com/dashboard 电影票房数据链接:https://box.maoyan.com/prom ...

  7. python爬取流浪地球_Scrapy爬取猫眼流浪地球影评2----- 获取数据

    本帖最后由 py看考场 于 2019-3-25 20:16 编辑 上一篇帖子中介绍了scrapy的安装,以及scrapy的基本配置,本篇介绍流浪地球影评的获取. 上一篇帖子传输门scrapy的安装配置 ...

  8. 使用python爬取东方财富网机构调研数据

    最近有一个需求,需要爬取东方财富网的机构调研数据.数据所在的网页地址为: 机构调研 网页如下所示: 可见数据共有8464页,此处不能直接使用scrapy爬虫进行爬取,因为点击下一页时,浏览器只是发起了 ...

  9. python爬取历史天气数据并保存_Python爬取天气网历史天气数据

    我的第一篇博客,哈哈哈,记录一下我的Python进阶之路! 今天写了一个简单的爬虫. 使用python的requests 和BeautifulSoup模块,Python 2.7.12可在命令行中直接使 ...

  10. Python爬取天气网历史天气数据

    我的第一篇博客,哈哈哈,记录一下我的Python进阶之路! 今天写了一个简单的爬虫. 使用Python的requests 和BeautifulSoup模块,Python 2.7.12可在命令行中直接使 ...

最新文章

  1. week6 10 后端backend server和mongoDB通信
  2. app uniapp 获取位置_uniApp 地图使用
  3. Linux 下监控系统几个重要组件
  4. VTP (vlan trunking protocol)
  5. Python Day 21 面向对象 (面向对象的三大特性(二)继承,多态,封装,几个装饰器函数)...
  6. 回顾:我们从2次主要API中断中汲取的经验教训
  7. C# error CS1729: 'XXClass' does not contain a constructor that takes 0 arguments的解决方案
  8. 服务器变量:$_SERVER
  9. mpu9250摘抄笔记及心得
  10. 笔记本电脑连接无线局域网怎么设置?
  11. Python每日一记179文氏图绘制
  12. linux怎么定时备份文件,linux自动定时备份文件
  13. 全开源iApp后台带PHP文件源码
  14. glog --- C++日志库
  15. 69 Three.js 导入Collada(.dae)格式的模型
  16. 如何看懂HijackThis扫描日志------学习帖
  17. cocos2d-x入门学习(五)跨版本代码移植实例之【梦幻连连看】
  18. Vue,图片编辑功能实现
  19. springboot+mybatisplus+达梦数据库
  20. 关于计算机的猜谜游戏,元宵灯谜猜谜语

热门文章

  1. BottomNavigationView的基本使用
  2. 【题解】洛谷P1661扩散(同LibreOJ10015) 曼哈顿距离最小生成树
  3. 详解百度大脑EdgeBoard出色的视频处理技术
  4. 15家企业入选2020年中国最佳雇主榜单;《新形势下国企数字化转型之路》白皮书发布 | 美通企业日报...
  5. c语言个人所得税,C语言编写一个计算个人所得税的程序,要求输入收入金额,能够输...
  6. 路由器计算机无法上网,连接路由器无法上网怎么回事_电脑连接路由器不能上网如何处理-win7之家...
  7. 机器学习方面的参考论文
  8. 从定时任务-到任务调度系统xxl-job
  9. 穷爸爸富爸爸的作者破产了,这本书是垃圾还是宝藏?
  10. 迅雷前副总裁李金波:我的创业感悟