文章目录

  • 一、什么是字体反爬
  • 二、编码原理
    • 2.1、ASCII编码对照表
    • 2.2、Unicode编号
    • 2.3、UTF-8编码方式
    • 2.4、字符矢量图
  • 三、案例:58同城反爬字体
    • 3.1、代码实现

一、什么是字体反爬

网页开发者自己创造一种字体,因为在字体中每个文字都有其代号,那么以后在网页中不会直接显示这个文字的最终的效果,而是显示他的代号,因此即使获取到了网页中的文本内容,也只是获取到文字的代号,而不是文字本身。

简单的说,字体反爬指的就是浏览器页面上的字符和调试窗口或者源码中的内容,显示的不一样,这就是字体反爬。


二、编码原理

bit(比特):是由0或1构成的二进制位
Byte(字节):1个字节由八个连续的二进制位,或二个16进制数表示
字符:是指计算机中使用的字母、数字、字和符号

2.1、ASCII编码对照表


ASCII码

ASCII 码使用指定的7位或8位二进制数组合来表示128或256种可能的字符。标准ASCII码也叫基础ASCII码,使用7位二进制数(剩下的1位二进制为0)来表示所有的大写和小写字母,数字0 到9、标点符号,以及在美式英语中使用的特殊控制字符。


2.2、Unicode编号

Unicode码

Unicode为世界上所有字符都分配了一个唯一的数字编号,这个编号范围从 0x000000 到 0x10FFFF(十六进制),有110多万,每个字符都有一个唯一的Unicode编号,这个编号一般写成16进制,在前面加上U+。例如:”爬“的Unicode是U+722C。它是一种规定,Unicode本身只规定了每个字符的数字编号是多少,并没有规定这个编号如何存储。

理论上可以直接把Unicode编号直接转换成二进制进行存储,而Unicode并不是这么操作,因为除了这种直接转换成二进制的方案外,还有其他方案,主要有UTF-8,UTF-16,UTF-32,gbk。(UTF-8、UTF-16、UTF-32……都是 Unicode编码 的一种实现。)


2.3、UTF-8编码方式

UTF-8 最大的一个特点,就是它是一种变长的编码方式。它可以使用1~4个字节表示一个符号,根据不同的符号而变化字节长度。

UTF-8 的编码规则很简单,只有两条:

  1. 对于单字节的符号,字节的第一位设为0,后面7位为这个符号的 Unicode 码。因此对于英语字母,UTF-8 编码和 ASCII 码是相同的。

  2. 对于n字节的符号(n > 1),第一个字节的前n位都设为1,第n + 1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的 Unicode 码。

汉字的UTF-8编码(n字节)表示

  1. 获取汉字unicode编号
  2. 转化为二进制数
  3. 根据UTF-8编码格式,将二进制数据填充到指定位置
  4. 将填充好的新二进制数据,转换成16进制

例:

1、获取汉字unicode编号
ord('爬')   =》29228
hex(29228)   =》'0x722c'2、转化为二进制数
bin(29228)   =》'0b111001000101100'3、根据UTF-8编码格式,将二进制数据填充到指定位置(29228>2048所以选3的: 1110xxxx 10xxxxxx 10xxxxxx)
11100111  10001000  101011004、将填充好的新二进制数据,转换成16进制
hex(int('11100111',2))   =》'0xe7'
hex(int('10001000',2))   =》'0x88'
hex(int('10101100',2))   =》'0xac'
"爬".encode('utf-8') =》b'\xe7\x88\xac'   #字节编码

编号与编码

一个字的Unicode编号是固定的,但是在计算机上的字节码,取决于编码方案的实现方式。一个汉字在Unicode中的编号的16进制数,跟utf8编码后的16进制数不是一回事。


2.4、字符矢量图

字体可以理解为通过unicode编号,对应的自定义图形。

字符对应关系

传递字符 5 ,有两种方案,
第一种是传递字符4的字节码:浏览器拿到字节码,转换成unicode编号,在没有指定字体文件的前提下,通过unicode编号在到系统自带字体中寻找字符矢量图,得到 ‘5’

第二种是,传递另一个繁体字的字节码,同时,传递一个自定义的字体。浏览器拿到繁体字的字节码,转换成unicode编码,到css指定的字体文件中查找,找到字符矢量图 ‘5’。

第二种情况下,浏览器后台和爬虫拿到的繁体字的字节码,只能在正常字体中查找字符矢量图,所以只能看到 一个其他字体(如:鱀)

正常对应关系:unicode编号 -->正常字符集 -->正常字符
使用自定义矢量图:①unicode编号 -->正常字符集 -->难懂的字
         ②nunicode编号 -->自定义字符集 -->正常字符

工具:

  1. FontCreator 下载exe文件,安装(下载链接:https://pan.baidu.com/s/15Bd9786YB_KcySPh2s4bXQ ,提取码:cgnb)

  2. fontTools包:pip install fontTools

字体文件存储的是unicode编号和字符矢量图的对应关系


三、案例:58同城反爬字体

首先我们先观察字体的位置:

字体样式

接下来就是查找自定义字符文件

自定义字符文件

或者也可以在‘network’处找到

自定义字符文件

然后我们就可以找出它们的对应关系了

base64_content = re.findall("charset=utf-8;base64,(.*?)'",res.text)
byte_content = base64.b64decode(base64_content)
with open('58car.ttf','wb') as f:f.write(byte_content)
font = TTFont('58car.ttf')
font.saveXML('58car.xml')
print(font.getBestCmap())
print(font.getGlyphID())
{37: 'uni0025', 43: 'uni002B', 45: 'uni002D', 47: 'uni002F', 165: 'uni00A5', 19975: 'uni4E07', 20803: 'uni5143', 25240: 'uni6298', 26102: 'uni65F6', 36215: 'uni8D77'}
{'.notdef': 0, 'uni5143': 1, 'uni002B': 2, 'uni65F6': 3, 'uni8D77': 4, 'uni002F': 5, 'uni00A5': 6, 'uni6298': 7, 'uni4E07': 8, 'uni0025': 9, 'uni002D': 10}

3.1、代码实现

import base64
import requests
import re
from lxml import etree
from fontTools.ttLib import TTFonturl = 'https://xm.58.com/ershouche/?PGTID=0d100000-0025-e7c0-f349-f6fb99ec299a&ClickID=2'
#58反爬比较强,所以我们头全写
headers = {'authority': 'xm.58.com',
'method': 'GET',
'path': '/ershouche/?PGTID=0d100000-0025-e7c0-f349-f6fb99ec299a&ClickID=2',
'scheme': 'https',
'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
'accept-encoding': 'gzip, deflate, br',
'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
'cache-control': 'no-cache',
'cookie': 'f=n; userid360_xml=DF790A407DD312F8230CF109530AC2BD; time_create=1631538931202; commontopbar_ipcity=zhangpu%7C%E6%BC%B3%E6%B5%A6%7C0; myLat=""; myLon=""; id58=r5k1JWEXmnttPtncoqH9+g==; mcity=zhangpu; 58tj_uuid=c72abed3-2489-4e7c-a321-691932bae8d3; wmda_uuid=d82a91d7f9f65ac837bb5b625c7b1068; wmda_new_uuid=1; als=0; xxzl_deviceid=0yvDkPJsU54k1%2BmeRC6Jp43aVt%2Bi7XJ7nI3mjoAoEaBaTbTRjvzYN%2FRqpRUawEXq; sessionid=36b1e461-0f5c-4f3b-ba5b-4eb4c7abd190; fzq_h=9db1bd518df2c5ff11e98c3775bb3bab_1628936871311_d7d3355fc4ca42a7bdb1d0a21f39d5c4_2363523693; f=n; city=xm; 58home=xm; wmda_visited_projects=%3B11187958619315%3B1731916484865%3B1732038237441%3B2385390625025; 58_ctid=606; is_58_pc=1; commontopbar_new_city_info=46%7C%E5%8E%A6%E9%97%A8%7Cxm; ctid=46; aQQ_ajkguid=7A6CE0F2-01D0-978C-9DB3-SX0814211431; sessid=7D16F3E3-652C-5EFB-AD5C-SX0814211431; __xsptplus8=8.1.1628946873.1628946873.1%234%7C%7C%7C%7C%7C%23%23t6AyIlY5mNYqNbQWgTNdey7ludWc_Aq_%23; xxzl_cid=c2bd9243c2614a22a6e811404337c8b6; xzuid=261dd2fa-dd63-49e9-b293-84c4afe5498b; wmda_session_id_1732038237441=1628961854128-e660d3fe-4be8-496b; new_uv=3; utm_source=; spm=; init_refer=https%253A%252F%252Fxm.58.com%252F%253Ffrom%253Dpc_topbar_home%2526PGTID%253D0d3090a7-0025-e161-980b-bb07e2053409%2526ClickID%253D3; new_session=0; fzq_js_usdt_infolist_car=4078e6bf9869aa309438c21d8a1fca5d_1628962005226_2',
'pragma': 'no-cache',
'referer': 'https://xm.58.com/?from=pc_topbar_home&PGTID=0d3090a7-0025-e161-980b-bb07e2053409&ClickID=3',
'sec-ch-ua': '"Chromium";v="92", " Not A;Brand";v="99", "Microsoft Edge";v="92"',
'sec-ch-ua-mobile': '?0',
'sec-fetch-dest': 'document',
'sec-fetch-mode': 'navigate',
'sec-fetch-site': 'same-origin',
'sec-fetch-user': '?1',
'upgrade-insecure-requests': '1',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36 Edg/92.0.902.67'
}
res = requests.get(url=url,headers=headers)
print(res.text)base64_content = re.findall("charset=utf-8;base64,(.*?)'",res.text)[0]
byte_content = base64.b64decode(base64_content)
with open('58car.ttf','wb') as f:f.write(byte_content)
font = TTFont('58car.ttf')
font.saveXML('58car.xml')
#打印字符对应关系
print(font.getBestCmap())
print(font.getReverseGlyphMap())#通过自定义字符文件,获取对应字体
def get_car_price(string, font):unicode_glyph = font.getBestCmap()glyph_price = font.getReverseGlyphMap()new_str = ''for char in string:char_unicode = ord(char)if char_unicode in unicode_glyph:glyph_code = unicode_glyph[char_unicode]price = glyph_price[glyph_code]new_str += str(price)return new_strhtml = etree.HTML(res.text)
car_list = html.xpath('//li[@class="info"]')
for car in car_list:#获取汽车名(无字体反爬)car_name = car.xpath('./div/a/div/h2/span/text()')[0].strip()#获取汽车价格(有字体反爬)car_price = car.xpath('./div/a/div/b/text()')[0].strip()car_price = get_car_price(car_price,font)print('汽车:%s, 价格:%s'%(car_name,car_price))

结果演示:

爬虫学习笔记(二十)—— 字体反爬相关推荐

  1. Mr.J-- jQuery学习笔记(二十八)--DOM操作方法(添加方法总结)

    Table of Contents appendTo appendTo(source, target) 源代码 append prependTo ​ ​ ​ ​ prependTo源码 prepend ...

  2. 嵌入式系统设计师学习笔记二十八:嵌入式程序设计③——高级程序设计语言

    嵌入式系统设计师学习笔记二十八:嵌入式程序设计③--高级程序设计语言 解释程序和编译程序 编译器的工作阶段示意图 语法错误:非法字符,关键字或标识符拼写错误 语法错误:语法结构出错,if--endif ...

  3. uniapp 学习笔记二十二 购物车页面结构搭建

    uniapp 学习笔记二十二 购物车页面结构搭建 cart.vue <template><view><view class="flex padding" ...

  4. Polyworks脚本开发学习笔记(二十)-补充几个常见操作指令的使用

    Polyworks脚本开发学习笔记(二十)-补充几个常见操作指令的使用 大概要写到结尾了,最后几篇就将手册的各常用命令再看一遍,组合一下,并列举出常见的一些有用的操作. DATA_COLOR_MAP数 ...

  5. 爬虫学习笔记(十二)—— scrapy-redis(一):基本使用、介绍

    文章目录 一.分布式概念和作用 二.Scrapy-redis 2.1.redis的安装与使用 2.2.Redis Desktop Manager下载 2.3.特点和架构 2.4.安装和使用 2.5.r ...

  6. 爬虫学习笔记(十)—— Scrapy框架(五):下载中间件、用户/IP代理池、settings文件

    一.下载中间件 下载中间件是一个用来hooks进Scrapy的request/response处理过程的框架. 它是一个轻量级的底层系统,用来全局修改scrapy的request和response. ...

  7. 前端电子表数字字体_爬虫:如何优雅应对字体反爬

    目录 THE BEGIN 一 什么是字体反爬 二 如何解密 1.人工解密 2.工具解密 三 建立映射关系 四 解密 THE BEGIN 网页数据爬取可以简单分为三步:抓取页面,分析页面,存储数据.其中 ...

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

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

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

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

  10. Python3 爬虫学习笔记 C03 【Ajax 数据爬取】

    Python3 爬虫学习笔记第三章 -- [Ajax 数据爬取] 文章目录 [3.1]Ajax 简介 [3.2]解析真实地址提取 [3.1]Ajax 简介 Ajax - Asynchronous Ja ...

最新文章

  1. 如何写一个通用的README规范
  2. MyBatis 实际使用案例-核心配置解读
  3. linux常用命令(用户篇)
  4. Java中hashCode()方法以及HashMap()中hash()方法
  5. 精品资源:40个实用的 PSD 贴纸模板《下篇》
  6. 中央企业经营管理一体化总体框架
  7. php日记源码,留言日记 - PHP源码 - 源码下载
  8. pyserial模块读取串口数据
  9. 使用计算机录制声音10,win10系统电脑中如何解决录屏时无法录制声音的问题
  10. 影响因素分析论文用什么模型好?
  11. MC开服教程2:材质包法自定义唱片音乐
  12. 达梦数据库基础篇--数据库管理工具
  13. Rokid webhook 五步应用指南 手把手教你做个懒人
  14. jsoup模拟登陆合肥工业大学信息门户
  15. ElementUI 的 el-select 设置值后显示value而不是label
  16. 组合数有关的公式及常用求和【数学--排列组合】
  17. php预加载图片,图片预加载的一个简明例子
  18. 混合颜色带的应用(一)
  19. Ubuntu 下大文件夹分卷压缩
  20. Docker-Zerotier

热门文章

  1. php 从根目录 开始创建,php创建多级目录的方法
  2. vpwm的控制变频_变频V/F和矢量控制你知道区别吗?据说这四种控制没有几人能说清...
  3. 162. Leetcode 45. 跳跃游戏 II (贪心算法-贪心区间)
  4. tkinter 笔记: radiobutton 选择按钮(莫烦python笔记)
  5. python 笔记:装饰器
  6. Flink从入门到精通100篇(二十二)- Flink应用实战案例:如何实现网络流控与反压机制
  7. 运筹学(最优化理论)学习笔记 | 分支定界法
  8. “加班文化“到底是如何流行起来的
  9. Tableau系列之与R语言结合
  10. ZooKeeper编程