在爬取网站抓取数据的过程中,有时会遇到这样一种情况:网页浏览正常,开发者模式(F12)查看原来没之后发现关键数据乱码,当然爬取下来的结果也是乱码。这种反爬策略一般称之为字体反爬

以58同城为例:

用浏览器随便打开58同城的一个页面,F12调出开发者调试窗口:

网页显示正常,调试窗口出现的内容与页面显示不符。

回到网页上,右键查看网页源代码,搜索base64关键字,可以看到一大串用base64加密的字符,复制逗号之后单引号之前的字符串:

编写Python代码,用base64把复制下来的加密字符串进行解码并保存为58.ttf

import base64font_face = "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"b = base64.b64decode(font_face)
with open('58.ttf', 'wb') as f:f.write(b)

用Python第三方库fontTools来获取字体映射表。

安装fontTools

pip install fontTools

先来看下ttf文件中有哪些信息,直接打开ttf文件那当然看不了,把它转换成xml文件就可以查看了:

from fontTools.ttLib import TTFontfont = TTFont('58.ttf')  # 打开刚才保存在本地的58.ttf文件
font.saveXML('58.xml')  # 转换并保存为xml

打开58.xml文件,可以看到类似html标签的文件结构:

点开GlyphOrder标签,可以看到id和name:

点开cmap标签,是code和name的对应关系:

用代码来获取编码和name的对应关系:

from fontTools.ttLib import TTFontfont = TTFont('58.ttf')  # 打开本地的ttf文件
bestcmap = font['cmap'].getBestCmap()
print(bestcmap)

输出如下:

{38006: 'glyph00007', 38287: 'glyph00005', 39228: 'glyph00009', 39499: 'glyph00004', 40506: 'glyph00008', 40611: 'glyph00003', 40804: 'glyph00006', 40850: 'glyph00002', 40868: 'glyph00001', 40869: 'glyph00010'}

输出的是一个字典,key是编码的int型(十进制)

我们把这个字典转一下,变成编码和正常字体的映射关系:

import re
from fontTools.ttLib import TTFontfont = TTFont('58.ttf')  # 打开本地的ttf文件
bestcmap = font['cmap'].getBestCmap()
newmap = dict()
for key in bestcmap.keys():value = int(re.search(r'(\d+)', bestcmap[key]).group(1)) - 1key = hex(key)newmap[key] = value
print(newmap)

输出如下:

{'0x9476': 6, '0x958f': 4, '0x993c': 8, '0x9a4b': 3, '0x9e3a': 7, '0x9ea3': 2, '0x9f64': 5, '0x9f92': 1, '0x9fa4': 0, '0x9fa5': 9}

现在就可以把页面上的自定义字体替换成正常字体,再解析需要的字段,Scrapy实现的全部代码如下:

import scrapy
from items import Com58FanLoder
from items import FanInfoItem
import re, base64, io
from scrapy.selector import Selector
from fontTools.ttLib import TTFont
class Com58Spider(scrapy.Spider):# 只列出parse函数def parse_fan(self, response):# 获取加密字符串base64_str = re.search(r"base64,(.*?)'\)", response.text).group(1)b = base64.b64decode(base64_str)font = TTFont(io.BytesIO(b))bestcmap = font['cmap'].getBestCmap()newmap = dict()for key in bestcmap.keys():value = int(re.search(r'(\d+)', bestcmap[key]).group(1)) - 1key = hex(key)newmap[key] = value# 把页面上自定义字体替换成正常字体__response = response.textfor key, value in newmap.items():key = key.replace('0x', '&#x') + ';'if key in __response:__response = __response.replace(key, str(value))selector = Selector(text=__response)# 与上面分开,上面解析字体反爬item_loader = Com58FanLoder(item=FanInfoItem(), response=response)item_loader.add_xpath('house_title', '//div[@class="house-title"]/h1/text()')item_loader.add_value('house_price', selector.xpath('//p[@class="house-basic-item1"]/span[1]').extract_first())item_loader.add_value('unit_price', selector.xpath('//p[@class="house-basic-item1"]/span[2]/text()').extract_first().replace('\xa0', ''))  # replace('\xa0', '')的原因是因为有一个空格,导致显示不正常,直接剔除即可

解析结果,圈出的部分就是上述代码的提取结果:

当然,给出用requests解析的代码,感谢python解析字体反爬博主:

import requests
import re, base64, io
from lxml import etree
from fontTools.ttLib import TTFont# 待解析的url
url = r'https://sz.58.com/chuzu/'headers = {'User-Agent':'Mozilla/5.0 (compatible; Baiduspider/2.0; +http://www.baidu.com/search/spider.html)'
}
response = requests.get(url=url, headers=headers)
# 获取加密字符串
base64_str = re.search("base64,(.*?)'\)", response.text).group(1)
b = base64.b64decode(base64_str)
font = TTFont(io.BytesIO(b))
bestcmap = font['cmap'].getBestCmap()
newmap = dict()
for key in bestcmap.keys():value = int(re.search(r'(\d+)', bestcmap[key]).group(1)) - 1key = hex(key)newmap[key] = value
# 把页面上自定义字体替换成正常字体
response_ = response.text
for key,value in newmap.items():key_ = key.replace('0x','&#x') + ';'if key_ in response_:response_ = response_.replace(key_,str(value))
# 获取标题
rec = etree.HTML(response_)
lis = rec.xpath('//ul[@class="listUl"]/li')
for li in lis:title = li.xpath('./div[@class="des"]/h2/a/text()')if title:title = title[0]print(title)

参考:
python解析字体反爬 https://www.cnblogs.com/eastonliu/p/9925652.html

推荐阅读:

Python爬虫六:字体反爬处理(猫眼+汽车之家)-2018.10 https://blog.csdn.net/xing851483876/article/details/82928607?tdsourcetag=s_pctim_aiomsg

爬虫遇见诡异字体-反反爬(58同城字体) https://www.jianshu.com/p/487bb2f20641

字体反爬解析和处理——Python相关推荐

  1. 汽车之家 css自定义字体反爬解析

    本文主要是通过哦爬取汽车之家论坛一些用户热门精华帖子,介绍利用前端页面自定义字体的方式来实现反爬的技术手段,来实践破解它. 自定义字体:@font-face是CSS3中的一个模块,主要是实现将自定义的 ...

  2. python爬虫进阶-汽车之家贴吧信息(字体反爬-动态映射)

    目的 获取汽车之家贴吧的内容信息 详细需求 汽车之家贴吧 思路解析 一.F12获取目标信息-进行分析 二.字体反爬解析-根据上一篇的文章,直接搜索关键词就好 三 根据其后的链接,保存为ttf在本地,查 ...

  3. python爬虫进阶-大众点评店铺信息(字体反爬-静态映射)

    目的 获取大众点评店铺信息 详细需求 http://www.dianping.com/shenzhen/ch10 思路解析 一 通过F12查找目标信息位置,进行分析 同理进行其他信息的解析,分析汇总 ...

  4. python读取ttf_python解析字体反爬

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

  5. python爬取猫眼遇到动态字体反爬

    前一段时间,爬取了58同城,发现当时的网页对数字有字体反爬虫,然后废了九牛二虎之力找到了规律,终于破解了反爬虫,后来发现猫眼的这个网页虽然使用了字体反爬,但是和原来的58同城还是有很大的差别,后来了解 ...

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

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

  7. Python爬虫 | 以滑雪为例演示大众点评商铺信息采集(字体反爬)

    文章目录 1.简述 2.字体反爬处理 2.1.获取字体文件链接 2.2.创建三类字体与实际字符映射关系 3.单页店铺信息解析 4.全部页数据获取 4.1.获取数据页数 4.2.采集全部数据 5.总结 ...

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

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

  9. python爬虫进阶-每日一学(字体反爬-移花接木)

    目的 分析与学习更多的字体反爬套路 详细需求 url:http://glidedsky.com/level/web/crawler-font-puzzle-2 思路解析 一.审查 二.分析 impor ...

最新文章

  1. 自动驾驶汽车“定位”技术
  2. django template语法
  3. Ubuntu返回到Gnome经典桌面!
  4. 2013年第四届蓝桥杯C/C++ A组国赛 —— 第四题:约数倍数选卡片
  5. 如何避免Puppeteer被前端JS检测
  6. html转pdf后 框会消失,html或其它文件转pdf弹出打开保存框
  7. Linux 命令简单介绍第二课笔记
  8. 静态路由(实验讲解+配置)
  9. nlp基础—9.条件随机场模型(CRF算法)
  10. iOS底层探索之类的加载(二): realizeClassWithoutSwift分析
  11. FPGA之SDRAM控制器设计(二)
  12. 计算机应用基础精品课程申报表,“大学计算机基础”校级精品课程组积极申报2020年山西省精品共享课程...
  13. 瀚高数据库php连接,HighGo瀚高数据库4.3版本安装说明
  14. 数据库查询时报错com.mysql.jdbc.exceptions.jdbc4.MySQLDataException: ‘1.7725000000E10‘ in column ‘17‘ is outs
  15. NET 模拟Htpp请求
  16. EKL-日志收集系统安装
  17. python毕业设计项目源码选题(5)校园网站系统毕业设计毕设作品开题报告开题答辩PPT
  18. windows怎样连接到linux桌面,Windows远程桌面连接Ubuntu 14.04
  19. 【技术美术图形部分】2.2 模型与材质基础
  20. 利用Nginxcp为cPanel/WHM服务器开启nginx支持

热门文章

  1. 使用CRM系统前四个准备步骤
  2. 考研进度记录表(2021.6-2021.11)
  3. 微信公众平台开发(94) 违章查询
  4. (AS笔记)Android全透明沉浸式主题样式——代码篇
  5. 写给大家看的设计书总结
  6. stm32F4 AES256加解密
  7. Linux 文件系统与权限(学习记录)
  8. HMI-52-【多媒体】音乐播放器 1
  9. c#控件弹幕效果_Android 弹幕效果开发案例
  10. RationalDMIS Baces3D 关节臂测量使用说明