1、下载安装包

pip install fontTools

2、下载查看工具FontCreator

百度后一路傻瓜式安装即可

3、反爬虫机制

网页上看见的

后台源代码里面的

从上面可以看出,生这个字变成了乱码,请大家特别注意箭头所指的数字。

3、解决

1、确定反爬方法

在看了别人的解析文章之后,确定采取的是字体反爬机制,即网站定义了字体文件,然后进行相应的查找替换,在前端看起来,是没有任何差异的。其实从审查元素的也是可以看到的:

和大众点评的反爬差不多,都是通过css搞得。

2、寻找字体文件

以上面方框里的”customfont“为关键词搜了一下,发现就在源代码里面:

而且还有base64,直接进行解密,但是解密出来的其实是乱码,这个时候其实要做的很简单,把解密后的内容保存为.ttf格式即可。

ttf文件: *.ttf是字体文件格式。TTF(TrueTypeFont)是Apple公司和Microsoft公司共同推出的字体文件格式,随着windows的流行,已经变成最常用的一种字体文件表示方式。

@font-face 是CSS3中的一个模块,主要是实现将自定义的Web字体嵌入到指定网页中去。

因为我们要对字体进行研究,所以必须将它打开,这里我是用的是FontCreator,打开以后是这个样子(其实很多字,在这里为了看的清楚,所以只截了下面的图):

很明显,每个字可以看到字形和字形编码。

观察现在箭头指的地方和前面箭头指的地方的数字是不是一样啊,没错,就是通过这种方法进行映射的。

所以我们现在的思路似乎就是在源代码里找到箭头指的数字,然后再来字体里找到后替换就行了。

恭喜你,如果你也是这么想的,那你就掉坑里了。

因为每次访问,字体字形是不变的,但字符的编码确是变化的。因此,我们需要根据每次访问,动态解析字体文件。

字体1:

字体2:

所以想通过写死的方式也是行不通的。

这个时候我们就要对字体文件进行更深一步的研究了。

3、研究字体文件

刚刚的.ttf文件我们是看不到内部的东西的,所以这个时候我们要对字体文件进行转换格式,将其转换为xml格式,然后来查看:

具体操作如下:

 
 
1
2
3
from fontTools.ttLib import TTFont
font_1 = TTFont('58_font_1.ttf')
font_base.saveXML('font_1.xml')

xml的格式如下:

文件很长,我只截取了一部分。

仔细的观察一下,你会发现~这俩下面的x,y,on值都是一毛一样的。所以我们的思路就是以一个已知的字体文件为基本,然后将获取到的新的字体文件的每个文字对应的x,y,on值进行比较,如果相同,那么说明新的文字对就 可以在基础字体那里找到对应的文字,有点绕,下面举个小例子。

假设: “我” 在基本字体中的名为uni1,对应的x=1,y=1,n=1新的字体文件中,一个名为uni2对应的x,y, n分别于上面的相等,那么这个时候就可以确定uni2 对应的文字为”我”。

查资料的时候,发现在特殊情况下,有时候两个字体中的文字对应的x,y不相等,但是差距都是在某一个阈值之内,处理方法差不多,只不过上面是相等,这种情况下就是要比较一下。

其实,如果你用画图工具按照上面的x与y值把点给连起来,你会发现,就是汉字的字形~

所以,到此总结一下:

一、将某次请求获取到的字体文件保存到本地[基本字体];
二、用软件打开后,人工的找出每一个数字对应的编码[
一定要保证顺序的正确,要不然会出事];
三、我们以后访问网页时,需要保存新字体文件;
四、用Fonttools库对基本字体与新字体进行处理,找
到新的字体与基本字体之间的映射;
五、替换;

4、代码

  1. # coding=utf-8
  2. import requests
  3. import re
  4. import time
  5. import lxml.html as H
  6. import base64
  7. from fontTools.ttLib import TTFont
  8. import requests
  9. from lxml import etree
  10. def get_data(url):
  11. headers = {
  12. 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36',
  13. }
  14. response = requests.get(url, headers=headers)
  15. font_data_origin = re.search(r'base64,(.*?)\)', response.text, re.S).group(1)
  16. font_data_after_decode = base64.b64decode(font_data_origin)
  17. new_font_name = "font_new.ttf"
  18. with open(new_font_name, 'wb') as f:
  19. f.write(font_data_after_decode)
  20. # font_base = TTFont('font_base.ttf').saveXML('font_base.xml')
  21. # font_base = TTFont('font_new.ttf').saveXML('font_new.xml')
  22. map_data = tff_parse(new_font_name)
  23. names = etree.HTML(response.text).xpath('//span[@class="infocardName fl stonefont resumeName"]/text()')
  24. # 有的时候会找不到,可以多执行几次;
  25. if names:
  26. for name in names:
  27. print('name in page source', name)
  28. for j in map_data.keys():
  29. name = name.replace(j, map_data[j])
  30. print('name actual', name)
  31.  
  32. def tff_parse(font_parse_name):
  33. # 我这里的字体的顺序,如果你的不同,一定要修改
  34. font_dict = [u'博', u'经', u'硕', u'届', u'大', u'刘', u'', u'', u'士', u'E', u'', u'', u'张',
  35. u'M', u'验', u'', u'本', u'赵', u'陈', u'吴', u'李', u'生', u'', u'校', u'以', u'应', u'黄',
  36. u'技', u'无', u'女', u'A', u'周', u'中', u'', u'王', u'', u'', u'', u'科', u'高', u'男',
  37. u'杨', u'专', u'下', u'B']
  38. font_base = TTFont('font_base.ttf')
  39. font_base_order = font_base.getGlyphOrder()[1:]
  40. # font_base.saveXML('font_base.xml') #调试用
  41.  
  42. font_parse = TTFont(font_parse_name)
  43. # font_parse.saveXML('font_parse_2.xml')调试用
  44. font_parse_order = font_parse.getGlyphOrder()[1:]
  45. f_base_flag = []
  46. for i in font_base_order:
  47. flags = font_base['glyf'][i].flags
  48. f_base_flag.append(list(flags))
  49. f_flag = []
  50. for i in font_parse_order:
  51. flags = font_parse['glyf'][i].flags
  52. f_flag.append(list(flags))
  53. result_dict = {}
  54. for a, i in enumerate(f_base_flag):
  55. for b, j in enumerate(f_flag):
  56. if comp(i, j):
  57. key = font_parse_order[b].replace('uni', '')
  58. key = eval(r'u"\u' + str(key) + '"').lower()
  59. result_dict[key] = font_dict[a]
  60. return result_dict
  61.  
  62. def comp(L1, L2):
  63. if len(L1) != len(L2):
  64. return 0
  65. for i in range(len(L2)):
  66. if L1[i] == L2[i]:
  67. pass
  68. else:
  69. return 0
  70. return 1
  71.  
  72. if __name__ == '__main__':
  73. url = "https://su.58.com/qztech/"
  74. get_data(url)

看一下成果

参考链接:

https://cuiqingcai.com/6431.html

58 字体反爬攻略 python3的更多相关文章

  1. Python爬虫入门教程 63-100 Python字体反爬之一,没办法,这个必须写,反爬第3篇

    背景交代 在反爬圈子的一个大类,涉及的网站其实蛮多的,目前比较常被爬虫coder欺负的网站,猫眼影视,汽车之家,大众点评,58同城,天眼查......还是蛮多的,技术高手千千万,总有五花八门的反爬技术 ...

  2. k 近邻算法解决字体反爬手段|效果非常好

    字体反爬,是一种利用 CSS 特性和浏览器渲染规则实现的反爬虫手段.其高明之处在于,就算借助(Selenium 套件.Puppeteer 和 Splash)等渲染工具也无法拿到真实的文字内容. 这种反 ...

  3. python解析字体反爬

    爬取一些网站的信息时,偶尔会碰到这样一种情况:网页浏览显示是正常的,用python爬取下来是乱码,F12用开发者模式查看网页源代码也是乱码.这种一般是网站设置了字体反爬 一.58同城 用谷歌浏览器打开 ...

  4. 记一次css字体反爬

    前段时间在看css反爬的时候,发现很多网站都做了css反爬,比如,设置字体反爬的(58同城租房版块,实习僧招聘https://www.shixiseng.com/等)设置雪碧图反爬的(自如租房http ...

  5. python爬取实习僧招聘信息字体反爬

    参考博客:http://www.cnblogs.com/eastonliu/p/9925652.html 实习僧招聘的网站采用了字体反爬,在页面上显示正常,查看源码关键信息乱码,如下图所示: 查看网页 ...

  6. Python爬虫入门教程 64-100 反爬教科书级别的网站-汽车之家,字体反爬之二

    说说这个网站 汽车之家,反爬神一般的存在,字体反爬的鼻祖网站,这个网站的开发团队,一定擅长前端吧,2019年4月19日开始写这篇博客,不保证这个代码可以存活到月底,希望后来爬虫coder,继续和汽车之 ...

  7. Python爬虫实例:爬取猫眼电影——破解字体反爬

    字体反爬 字体反爬也就是自定义字体反爬,通过调用自定义的字体文件来渲染网页中的文字,而网页中的文字不再是文字,而是相应的字体编码,通过复制或者简单的采集是无法采集到编码后的文字内容的. 现在貌似不少网 ...

  8. Python爬虫-字体反爬-猫眼国内票房榜

    偶然间知道到了字体反爬这个东西, 所以决定了解一下. 目标:  https://maoyan.com/board/1 问题: 类似下图中的票房数字无法获取, 直接复制粘贴的话会显示 □ 等无法识别的字 ...

  9. Spider-天眼查字体反爬

    字体反爬也就是自定义字体反爬,通过调用自定义的woff文件来渲染网页中的文字,而网页中的文字不再是文字,而是相应的字体编码,通过复制或者简单的采集是无法采集到编码后的文字内容! 1.思路 近期在爬取天 ...

随机推荐

  1. 如何为Windows XP / Windows7-32bit / Windows7-64bit安装capicom.dll

    原文: http://164.100.181.16/ssdgsap/RegisterDLL.htm 1.根据操作系统的要求下载相应的文件夹安装capicom.dll for Windows XP的步骤 ...

  2. php删除文件夹

    function deldir($dir) { $dh=opendir($dir); while ($file=readdir($dh)) { if($file!="." & ...

  3. [Day23]IO(字节流、字符流)

    1.字节流 1.1 字节输出流OutputStream-抽象类,表示输出字节流的所有类的超类 (1)void close() 关闭此输出流并释放与此流相关的所有系统资源 (2)void flush() ...

  4. Autofac之类型注册

    本次主要学习一下Autofac中实现类型注册的几种方式,这里并不打算一开始就从基于接口开发的服务关联切入,而是先从一个简单的类型注册来学起,虽然实际开发中可能不会这么做,但是个人感觉从这里学起理解能能 ...

  5. MS17-010 漏洞研究——免考课题 20155104 赵文昊

    免考实验与研究--MS17-010漏洞研究 研究内容 ·MS17-010漏洞的来源 ·MS17-010漏洞的攻击实例 ·MS17-010漏洞原理分析 ·MS17-010代码分析 写在前面:这次对一个漏 ...

  6. [vue开发记录]全局loading组件

    上图不上种,菊花万人捅: loading.js: import './loading.css' let Loading = {} // 避免重复install,设立flag Loading.insta ...

  7. Linux环境下虚拟环境virtualenv安装和使用

    virtualenv用于创建独立的Python环境,多个Python相互独立,互不影响,它能够: 1. 在没有权限的情况下安装新套件 2. 不同应用可以使用不同的套件版本 3. 套件升级不影响其他应用 ...

  8. Android系统裁剪:手把手教你如何进行系统裁剪

    前言:android系统裁剪优化一直是各个厂商定制产品的关键步骤,包括浅层次的去除不必要的apk(android apk裁剪定制 )和深层次的裁剪整个编译系统和框架层.   android作为开源系统 ...

  9. 20190423 PowerDesigner 数据库模型快速建立

    后面我在做一个视频的讲解记录吧! 那种讲解记录,只是为了演示按钮功能在什么地方,这个功能的作用是什么 这个软件相对比较简单的使用步骤,主要有三步 第一. 选择好你针对的数据库版本和类型创建数据库名称基 ...

  10. python借助ADB工具实现自动化操作手机

    核心工具——ADB工具 adb工具用于连接Android手机和PC端,我们借助adb工具,就可以通过命令行对手机进行相应的操作 注意:若要通过adb操作手机,需打开手机的开发者模式,并打开USB调试功 ...