爬虫逆向之字体反爬(一)、镀金的天空-字体反爬-1

news2025/1/16 15:00:38

题目地址:http://www.glidedsky.com/level/crawler-font-puzzle-1

写一下之前处理过的几个字体反爬实战,也是很常见的一种反爬类型,这是第一篇

先来看一下题目

image.png

源码拿到的数字,和实际显示在网页的数字,明显不一样的

image.png

注意到两个现象

  • 每一次刷新,源码中的数字就跟着变动,说明每请求一次页面,就使用了新的ttf字体文件
  • 数字看起来无序,其实是有映射关系的,比如 122 变成了 277226 变成了 773

所以这里的解题思路就是,解析ttf文件,得到数字之间的映射关系,然后结合网页源码提取到的数字,就能获取真实的数字了

作者已经提示,ttf文件内嵌在源码的base64中

image.png

复制那一大串字符,进行解码,然后保存成 ttf文件

content = base64.b64decode(b64_str)

with open("page-1.ttf", "wb") as f:
	f.write(content)

使用专门的字体查看工具打开文件,这里我使用的是 FontCreator 9.1

image.png

通过比对网页数字、源码数字,我们发现映射关系是一致的,比如:8 显示成 1,4 显示成 0

image.png

接下来就是要怎么拿到这些映射关系了?根据ttf文件提示,我们只要拿到上面那一栏小标题 four one eight ...,然后按顺序找到就能对应的真实数字,比如 four 对应 0, one 对应 1

那么怎么拿到解析 ttf文件拿到小标题呢?有两种方式,一种是解析xml,一种是使用专门的字体解析库 fontTools

这里使用 fontTools,后面其他的文章我会介绍xml的

参考:https://fonttools.readthedocs.io/en/latest/ttLib/ttFont.html

from fontTools.ttLib import TTFont

def parse_ttf():
    """
    return
        {
            源码数字:真实数字
        }
    """
    font = TTFont("page-1.ttf")
    # 获取节点名列表
    name_lst = font["cmap"].tables[0].ttFont.getGlyphOrder()
    en2num = {
        "nine": 9,
        "eight": 8,
        "two": 2,
        "six": 6,
        "three": 3,
        "four": 4,
        "seven": 7,
        "one": 1,
        "five": 5,
        "zero": 0,
    }
    # 生成映射表
    map_list = {
        str(en2num[word]): str(index) for index, word in enumerate(name_lst[1:])
    }
    return map_list

拿到映射表后,我们提取源码中的数字就能得到真实的数字了

代码整理

# -*- coding:utf-8 -*-

import base64
import requests

from io import BytesIO
from fontTools.ttLib import TTFont
from parsel import Selector


def glidedsky_login():
    """
    网站登录,才能看到题目
    注意题目域名也必须是 www.glidedsky.com
    """
    EMAIL = ""
    PASSWORD = ""
    LOGIN_URL = "http://www.glidedsky.com/login"

    session = requests.session()
    resp = session.get(LOGIN_URL)
    dom = Selector(resp.text)
    _token = dom.css("meta[name='csrf-token']::attr(content)").get()
    form_data = {
        "_token": _token,
        "email": EMAIL,
        "password": PASSWORD,
    }
    session.post(LOGIN_URL, data=form_data)
    return session


def parse_ttf(b64_str):
    """
    return
        {
            源码数字:真实数字
        }
    """
    content = base64.b64decode(b64_str)
    # 使用 BytesIO 构建一个临时文件对象
    font = TTFont(BytesIO(content))

    # 获取节点名列表
    name_lst = font["cmap"].tables[0].ttFont.getGlyphOrder()
    en2num = {
        "nine": 9,
        "eight": 8,
        "two": 2,
        "six": 6,
        "three": 3,
        "four": 4,
        "seven": 7,
        "one": 1,
        "five": 5,
        "zero": 0,
    }
    # 生成映射表
    map_list = {
        str(en2num[word]): str(index) for index, word in enumerate(name_lst[1:])
    }
    return map_list


def parse_html(html_text):
    dom = Selector(text=html_text)
    b64_str = dom.css("style::text").re_first(r"base64,(.+?)\)")
    mappings = parse_ttf(b64_str)

    fake_nums = dom.css(".col-md-1::text").re(r"\d+")
    for num in fake_nums:
        real_num = "".join(mappings[n] for n in num)
        yield real_num


def main():
    session = glidedsky_login()

    for page in range(1, 11):
        url = "http://www.glidedsky.com/level/web/crawler-font-puzzle-1?page=" + str(page)
        resp = session.get(url)
        print(f"page {page}: ", [num for num in parse_html(resp.text)])


if __name__ == "__main__":
    main()

涉及到的知识点:

  • VScode 设置 black格式化
  • 使用 BytesIO 构建一个临时文件对象

运行结果

image.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/155932.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

相见恨晚的 IDEA 使用技巧,能让你的代码飞起来

Live Templates 是什么,听上去感觉挺玄乎的。有的同学用过之后觉得简直太好用了,不能说大大提高了开发效率吧,至少也是小小的提高一下,节省了很多敲重复代码的时间。有的同学用过之后说:没什么用,奇技淫巧罢…

C语言_程序环境和预处理

目录 1. 程序的翻译环境 2. 程序的执行环境 3. C语言程序的翻译链接 4. 预编译过程详解 4.1 预定义符号介绍 4.1.1 __FILE__ //进行编译的源文件 4.1.2 __LINE__//文件当前的行号 4.1.3 __DATE__//文件被编译的日期 4.1.4 __TIME__//文件被编译的时间 4.1.5 __STDC__…

基于python的学生信息管理系统

《学生信息管理系统》程序使用说明在IDLE中运行《学生信息管理系统》即可进入如图1所示的系统主界面。在该界面中可以选择要使用功能对应的菜单进行不同的操作。在选择功能菜单时,有两种方法,一种是输入1,另一种是按下键盘上的↑或↓方向键进…

【Javascript】高阶函数,JSON,forEach,map,filter,reduce函数

❤️ Author: 老九 ☕️ 个人博客:老九的CSDN博客 🙏 个人名言:不可控之事 乐观面对 😍 系列专栏: 文章目录高阶函数箭头函数apply函数JSONfilter函数map函数总结reduce函数find/findIndex函数every/some函…

线缆行业单绞机控制算法(详细图解)

在了解单绞机之前需要大家对收放卷以及排线控制有一定的了解,不清楚的可以参看下面几篇博客,这里不再赘述,受水平和能力所限,文中难免出现错误和不足之处,诚恳的欢迎大家批评和指正。 收放卷行业开环闭环控制算法 PLC张力控制(开环闭环算法分析)_RXXW_Dor的博客-CSDN博…

知识难懂到什么程度

爱因斯坦相对论,诺贝尔评委会都看不懂,到底说的是什么1905年,爱因斯坦发布狭义相对论;1916年,发布广义相对论;2年后,英国的汤姆逊教授通过实验验证了广义相对论的正确,同时也把爱因期…

容器适配器中stack queue priority_queue的介绍及模拟实现

文章目录容器适配器的概念deque的介绍及底层结构stack的介绍 stack的模拟实现 queue的介绍 queue的模拟实现 priority_queue的介绍 priority_queue的模拟实现 容器适配器的概念 适配器是一种设计模式(设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验…

清华大佬超全超详细讲解——C++STL看这份教程就够了

2022 年年度编程语言揭榜啦!在上个月预想的 C、C、Python 三种候选语言中,C 脱颖而出,成为 TIOBE 2022 年度编程语言的最终获得者!新的一波学习热潮要来了。TIOBE 编程语言社区排行榜是编程语言流行趋势的一个指标,每月…

数据分析思维(三)|测试/对比思维

测试/对比思维 1、概念 测试/对比思维可以说在数据分析的工作中随处可见。当我们通过各种手段得到一些结果数据后,如何评价结果的好坏呢?这个时候你可能会想到和标准结果进行比较、和之前的数据进行对照等等方法,这些方法归根结底就是一种测…

ubuntu 安装 Gitkraken 8.1.1 Pro 版本

GitKraken 是一个非常好用的 Git 图形界面客户端, 自 6.5.1 版本以后, GitKraken 对私有仓库不再免费开放使用 本文介绍一个 ubuntu 安装 GitKraken 8.1.1 Pro 版本的方法 环境准备 安装 yarn 测试过 node 18.12.1 版本, 没能升级到 Pro 版, 可能是因为 GitCracken 仓库太久…

springboot+sa-token-quick-login实现快速登录

当你的项目需要一个登录认证功能,这个登录界面可以不华丽、可以烂,但是一定要有,同时你又不想花费太多的时间浪费在登录页面上, 那么你便可以尝试一下Sa-Token-Quick-Login。 1、Sa-Token-Quick-Login Sa-Token-Quick-Login 可以…

5.4、TCP 流量控制(滑动窗口机制)

一般来说,我们总是希望数据传输得更快一些。 但如果发送方把数据发送得过快,接收方就可能来不及接收,这就会造成数据的丢失。 所谓流量控制(flow control)就是让发送方的发送速率不要太快,要让接收方来得及接收\color{red}让发送…

基于微信小程序的个人健康数据管理系统小程序

文末联系获取源码 开发语言:Java 框架:ssm JDK版本:JDK1.8 服务器:tomcat7 数据库:mysql 5.7/8.0 数据库工具:Navicat11 开发软件:eclipse/myeclipse/idea Maven包:Maven3.3.9 浏览器…

第一章.机器学习的前期准备—jupyter 更换文件路径的方法,jupyter使用方法,训练/验证/测试数据集的概念,学习方式,常见应用

第一章.机器学习的前期准备 1.1 第一章.机器学习的前期准备 1.jupyter软件的安装 说明:可以使用Anaconda软件中的jupyter软件 1).jupyter 更换文件路径的方法: ①.查找电脑中是否存在 jupyter_notebook_config.py 文件,若不存在,通过命令提…

前端最基础面试题:说说JavaScript中如何判断数据类型?

1. 基本数据类型的判定:typeof [变量名] typeof 1 // number typeof string呀 // string typeof true // boolean typeof Symbol(abc) // symbol控制台验证: 2. 引用类型 object 的判断: ① constructor ② instanceof ③ Object.prototy…

Redux与前端表格施展“组合拳”,实现大屏展示应用的交互增强

Redux 是 JavaScript 状态容器,提供可预测化的状态管理。它可以用在 react、angular、vue 等项目中, 但与 react 配合使用更加方便一些。 Redux 原理图如下,可以看到store仓库是Redux的核心,通过维护一个store仓库管理 state。state 是只读的…

JS严格模式(use strict)

javascript语法不够严谨,例如我们在项目中不用关键字去定义了一个变量a,控制台一切正常。b123;console.log(b)但是,如果开启了严格模式呢?"use strict" b123; console.log(b)此时将会报错Uncaught ReferenceError: b is…

开关电源中功率电感均方根电流是如何推导的?来自《开关电源宝典》

3.2.8 功率电感的有效电流参考“1.7.3 功率电感”章节内容,我们知道,功率电感具有温升电流、RMS电流、饱和电流、额定电流等电流参数。在后续“第5章 降压电路的应用方法”应用实例中进行功率电感选型时,需要保证所选电感的额定电流参数大于实…

自定义类型:结构体,枚举,联合(1)

tips 1. 2. 结构基础知识复习 1. 结构是一些值的集合,这些值被称为成员变量,结构的每个成员可以是不同类型的变量。 2. 结构体类型,结构体成员,结构体变量,结构体指针的创建方式 3. 初始化结构体变量的时候&…

华为开源自研AI框架昇思MindSpore应用实践:FGSM网络对抗攻击

目录一、环境准备1.进入ModelArts官网2.使用CodeLab体验Notebook实例二、对抗样本定义三、攻击方法快速梯度符号攻击(FGSM)四、数据处理五、训练LeNet网络六、实现FGSM七、运行攻击近年来随着数据、计算能力、理论的不断发展演进,深度学习在图…