猫眼电影字体破解(图片转码方法)

问题

        随便拿一篇电影做样例。我们发现猫眼的页面数据在预览窗口中全是小方框。在当我们拿到源码以后,数据全是加密后的。所以我们需要想办法破解加密,拿到数据。

破解过程 

        1.源码获取问题与破解

        分析

        在我们刚刚请求url的时候是可以得到数据的,但是过了一段时间后就无法获得数据。虽然状态码为200,但是却没有返回页面源码

一般这种应该是和时间戳有关系,在查看请求负载的时候我们发送,浏览器向这个url不仅发送了时间戳还有一个signKey的密钥。时间戳可以很容易得到,主要问题是如何获得signKey。

        全局搜索signKey,我们发现一段js代码,它的返回值就是我们请求负载的内容。所以需要想办法还原这段js代码。

        分析后发现:

  • d:获取当前时间的函数
  • r:随机数取整
  • c:内容如下method=GET&timeStamp=1725264890773&User-Agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 Edg/128.0.0.0&index=8&channelId=40011&sVersion=1
    • 可以发现就是多个信息进行拼接(时间戳+User-Agent+index+channelId+sVersion)。
  • f:固定为&key=A013F70DB97834C0A5492378BD76C53A

        分析图片如下:

        同时我们还发现signKey是通过MD5加密(c+f)后得到的。因为1经过MD5加密后得到的内容就是c4ca4238a0b923820dcc509a6f75849b,所以我们可以猜测(0,a[i(_0x140e("0xe4"))])('c+f')就是一个MD5的加密。

         js编写与调用

        有了以上分析后,我们就可以拿页面原始的js代码进行适当的改动。修改后的js代码如下,我们直接返回网页负载需要的params。

        添加首页cookie

        在完成上面步骤后,我们调用js,虽然得到了params,但是还是无法获得到页面的源代码,这可能和cookie有关系,所以我们创建一个session,通过访问首页来保存首页的cookie,然后再来访问这个url看看结果。

        我们发现浏览器请求了两次https://www.maoyan.com/,且第一次存在302跳转,跳转到https://www.maoyan.com/,所以是请求了两次。在python代码中,我们只需要请求有302跳转的链接即可,因为程序会自动进行第二次跳转。

        添加cookie后,使用python程序调用js代码返回params,使用js生成的params去访问url地址运行结果如下:

        2.字体破解

        字体图片下载

        在拿到页面源码以后,我们需要对数字进行获取。直接在返回的源码中搜索,获取.woff文件。得到url://s3plus.meituan.net/v1/mss_73a511b8f91f43d0bdae92584ea6330b/font/e3dfe524.woff,因为每一次请求得到的源码中,woff文件的链接都不同,所以我们需要使用数据提取手段,提取每一次请求得到的woff文件链接并下载保存下来。

        下载并保存woff文件,使用python代码识别woff文件,并保存为图片,识别代码如下,之后会整合到源码中:

from fontTools.ttLib import TTFont
from reportlab.graphics.shapes import Drawing, Path, Group
from reportlab.graphics import renderPM
from reportlab.lib import colors
from reportlab.graphics.shapes import Path

class ReportLabPen(BasePen):
    def __init__(self, glyphSet, path=None):
        BasePen.__init__(self, glyphSet)
        if path is None:
            path = Path()
        self.path = path

    def _moveTo(self, p):
        (x, y) = p
        self.path.moveTo(x, y)

    def _lineTo(self, p):
        (x, y) = p
        self.path.lineTo(x, y)

    def _curveToOne(self, p1, p2, p3):
        (x1, y1) = p1
        (x2, y2) = p2
        (x3, y3) = p3
        self.path.curveTo(x1, y1, x2, y2, x3, y3)

    def closePath(self):
        self.path.closePath()

def ttfToImage(fontName, imagePath, fmt="png"):
    font = TTFont(fontName)  # 打开 WOFF 字体文件
    gs = font.getGlyphSet()
    glyphNames = font.getGlyphNames()[1:]  # 排除第一个 .notdef 字形

    for i in glyphNames:
        g = gs[i]  # 获取当前字形的 Glyph 对象
        pen = ReportLabPen(gs, Path(fillcolor=colors.red, strokeWidth=1))  # 创建 ReportLabPen 对象,并设置相关参数
        g.draw(pen)  # 将当前字形通过 pen 绘制到 path 对象上
        
        # 字形的宽度和高度
        w, h = g.width, g.width + 300  
        g = Group(pen.path)
        g.translate(0, 100)  # 将图形向下移动 100 个像素
        
        d = Drawing(w, h)  # 创建 Drawing 对象,设置宽度和高度
        d.add(g)  # 将 Group 对象添加到 Drawing 对象中
        
        # 定义输出图片路径和文件名
        imageFile = f"{imagePath}/{i}.{fmt}"
        
        # 将 Drawing 对象渲染成图像文件并保存
        renderPM.drawToFile(d, imageFile, fmt)

# 示例用法:将 `mao.woff` 字体文件的字形保存为图像
ttfToImage(fontName="mao.woff", imagePath='images')

        识别结果如下:

         识别图片

        识别代码如下,之后会整合到源码中:

import os
import ddddocr  # 导入 ddddocr 库

def orc():
    # 创建一个 ddddocr 的 OCR 对象
    ocr = ddddocr.DdddOcr()
    dicts = {}  # 初始化一个空字典,用于存储识别结果
    lists = os.listdir('./images')  # 获取 images 目录下的所有文件列表
    
    # 遍历每个图片文件
    for imgs in lists:
        # 以二进制模式读取图片文件
        with open('./images/' + imgs, 'rb') as f:
            img_bytes = f.read()
        
        # 使用 OCR 对象的 classification 方法识别图片内容
        res = ocr.classification(img_bytes)
        
        # 输出文件名中提取的 Unicode 代码
        print(222222222222222222, imgs[3:-4])
        
        try:
            # 将文件名中的 Unicode 代码转换为字符,并将识别结果存入字典
            dicts[eval('u\'\\u' + imgs[3:-4].lower() + '\'')] = res
        except:
            # 如果转换或存储过程中出错,则跳过
            pass

        # 打印当前的字典内容
        print(dicts)

# 调用 orc 函数
orc()

        字典输出结果如下:

字典替换

        拿到页面加密的源码,然后根据字典的key来替换掉对应的数字

        替换后的数字与原始页面一样

源码

        py文件

import requests
import execjs
import re
import shutil
import os
import ddddocr
from fontTools.pens.basePen import BasePen
from fontTools.ttLib import TTFont
from reportlab.graphics.shapes import Drawing, Path, Group
from reportlab.graphics import renderPM
from reportlab.lib import colors
from reportlab.graphics.shapes import Path


class ReportLabPen(BasePen):
    def __init__(self, glyphSet, path=None):
        BasePen.__init__(self, glyphSet)
        if path is None:
            path = Path()
        self.path = path

    def _moveTo(self, p):
        (x, y) = p
        self.path.moveTo(x, y)

    def _lineTo(self, p):
        (x, y) = p
        self.path.lineTo(x, y)

    def _curveToOne(self, p1, p2, p3):
        (x1, y1) = p1
        (x2, y2) = p2
        (x3, y3) = p3
        self.path.curveTo(x1, y1, x2, y2, x3, y3)

    def closePath(self):
        self.path.closePath()


def ttfToImage(fontName, imagePath, fmt="png"):
    font = TTFont(fontName)  # 打开 WOFF 字体文件
    gs = font.getGlyphSet()
    glyphNames = font.getGlyphNames()[1:]  # 排除第一个 .notdef 字形

    for i in glyphNames:
        g = gs[i]  # 获取当前字形的 Glyph 对象
        pen = ReportLabPen(gs, Path(fillcolor=colors.red, strokeWidth=1))  # 创建 ReportLabPen 对象,并设置相关参数
        g.draw(pen)  # 将当前字形通过 pen 绘制到 path 对象上

        # 字形的宽度和高度
        w, h = g.width, g.width + 300
        g = Group(pen.path)
        g.translate(0, 100)  # 将图形向下移动 100 个像素

        d = Drawing(w, h)  # 创建 Drawing 对象,设置宽度和高度
        d.add(g)  # 将 Group 对象添加到 Drawing 对象中

        # 定义输出图片路径和文件名
        imageFile = f"{imagePath}/{i}.{fmt}"

        # 将 Drawing 对象渲染成图像文件并保存
        renderPM.drawToFile(d, imageFile, fmt)


def download_woff():
    with open('猫眼.js','r',encoding='utf-8') as f:
        ctx = execjs.compile(f.read())

    headers_home = {
        "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
        "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
        "Cache-Control": "max-age=0",
        "Connection": "keep-alive",
        "Sec-Fetch-Dest": "document",
        "Sec-Fetch-Mode": "navigate",
        "Sec-Fetch-Site": "none",
        "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/128.0.0.0 Safari/537.36 Edg/128.0.0.0",
        "sec-ch-ua": "\"Chromium\";v=\"128\", \"Not;A=Brand\";v=\"24\", \"Microsoft Edge\";v=\"128\"",
        "sec-ch-ua-mobile": "?0",
        "sec-ch-ua-platform": "\"Windows\""
    }

    cookies_home = {
        "_lxsdk_s": "191b2c23b90-602-526-0ba%7C%7C1"
    }

    url = "https://www.maoyan.com/"

    s = requests.session()

    # 访问首页,保存cookie
    r = s.get(url, headers=headers_home, cookies=cookies_home)

    headers = {
        "Accept": "*/*",
        "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
        "Connection": "keep-alive",
        "Referer": "https://www.maoyan.com/films/1464004",
        "Sec-Fetch-Dest": "empty",
        "Sec-Fetch-Mode": "cors",
        "Sec-Fetch-Site": "same-origin",
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 Edg/128.0.0.0",
        "X-Requested-With": "XMLHttpRequest",
        "sec-ch-ua": "\"Chromium\";v=\"128\", \"Not;A=Brand\";v=\"24\", \"Microsoft Edge\";v=\"128\"",
        "sec-ch-ua-mobile": "?0",
        "sec-ch-ua-platform": "\"Windows\""
    }

    url = "https://www.maoyan.com/ajax/films/1464004"

    params = ctx.call("get_params")

    response = s.get(url, headers=headers, params=params).text

    # 保存woff
    woff_url = "https:" + re.findall(r',url.*?woff', response)[0].split('"')[1]
    woff_res = s.get(woff_url).content
    with open('mao.woff', 'wb') as f:
        f.write(woff_res)
    f.close()

    result = re.findall('<span class="stonefont">(.*?)</span>', response)
    return result


def clear_folder(folder_path):
    # 确保指定路径是一个文件夹
    if os.path.isdir(folder_path):
        # 遍历文件夹中的所有文件和子文件夹
        for filename in os.listdir(folder_path):
            file_path = os.path.join(folder_path, filename)
            try:
                # 如果是文件则删除
                if os.path.isfile(file_path) or os.path.islink(file_path):
                    os.unlink(file_path)
                # 如果是文件夹则删除整个文件夹
                elif os.path.isdir(file_path):
                    shutil.rmtree(file_path)
            except Exception as e:
                print(f"删除 {file_path} 时出错: {e}")
    print("删除完成")


def orc():
    # 创建一个 ddddocr 的 OCR 对象
    ocr = ddddocr.DdddOcr()
    dicts = {}  # 初始化一个空字典,用于存储识别结果
    lists = os.listdir('./images')  # 获取 images 目录下的所有文件列表

    # 遍历每个图片文件
    for imgs in lists:
        # 以二进制模式读取图片文件
        with open('./images/' + imgs, 'rb') as f:
            img_bytes = f.read()

        # 使用 OCR 对象的 classification 方法识别图片内容
        res = ocr.classification(img_bytes)

        # 输出文件名中提取的 Unicode 代码
        print(222222222222222222, imgs[3:-4])

        try:
            # 将文件名中的 Unicode 代码转换为字符,并将识别结果存入字典
            dicts[eval('u\'\\u' + imgs[3:-4].lower() + '\'')] = res
        except:
            # 如果转换或存储过程中出错,则跳过
            pass

    # 返回字典内容
    return dicts


if __name__ == '__main__':
    data = download_woff()

    # 指定要清空的文件夹路径
    folder_path = './images'
    clear_folder(folder_path)

    # 转换 TTF 字体并将字形转换为 PNG 图片
    ttfToImage(fontName="mao.woff", imagePath='images')

    # 使用ocr识别图片,返回字典
    res = orc()

    print(data)
    print(res)
    # 遍历字典并将识别结果输出
    for i in data:
        # 首先去掉所有的 &#x 和 ;
        cleaned_str = i.replace('&#x', '').replace(';', '')

        # 然后进行字符替换
        for key, value in res.items():
            cleaned_str = cleaned_str.replace(key.encode('unicode_escape').decode('ascii').replace('\\u', ''), value)

        print(cleaned_str)


        js文件

const CryptoJS = require('crypto-js')


var r = Math["ceil"](10 * Math["random"]())
var d = (new Date)["getTime"]()
var c = "method=GET&timeStamp="+d+'&User-Agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 Edg/128.0.0.0&index='+r+'&channelId=40011&sVersion=1'
var f = "&key=A013F70DB97834C0A5492378BD76C53A"


function get_params(){
    return{
        "timeStamp": d,
        "index": r,
        "signKey": CryptoJS.MD5(c+f).toString(),
        "channelId": "40011",
        "sVersion": "1",
        "webdriver": "false"
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

杀毒软件 | Malware Hunter v1.189.0.816 绿色版

软件简介 Malware Hunter是由Glarysoft开发的一款专业安全防护软件。该软件的主要目的是保护用户的计算机免受恶意软件、病毒和其他网络威胁的侵害。它通过采用高效的云引擎和小红伞引擎&#xff0c;能够快速且全面地扫描电脑中的恶意软件&#xff0c;并进行强力清除&#xff…

Definition and Detection of Defects in NFT Smart Contracts论文解读、复现

背景知识\定义 NFT 是数字或物理资产所有权的区块链表示。不仅限于数字图片&#xff0c;视频和画作等艺术品也可以转化为 NFT 进行交易。近年来受到广泛关注&#xff0c;2021 年 NFT 交易额达到约 410 亿美元。 智能合约 是在区块链上运行的图灵完备程序。支持各种去中心化…

第 1 章:原生 AJAX

原生AJAX 1. AJAX 简介 AJAX 全称为 Asynchronous JavaScript And XML&#xff0c;就是异步的 JS 和 XML。通过 AJAX 可以在浏览器中向服务器发送异步请求&#xff0c;最大的优势&#xff1a;无刷新获取数据。AJAX 不是新的编程语言&#xff0c;而是一种将现有的标准组合在一…

C# Windows Forms实现绘制画板

目录 C# Windows Forms上绘制画板&#xff1a; 详细解释&#xff1a; TempData临时数据&#xff0c;用来保存画笔相关的信息&#xff0c;如&#xff1a;颜色&#xff0c;大小&#xff0c;坐标等 类声明和成员变量 构造函数 文件菜单项点击事件 保存菜单项点击事件 画笔大…

等待唤醒机制和阻塞队列

1. 等待唤醒机制 由于线程的随机调度&#xff0c;可能会出现“线程饿死”的问题&#xff1a;也就是一个线程加锁执行&#xff0c;然后解锁&#xff0c;其他线程抢不到&#xff0c;一直是这个线程在重复操作 void wait() 当前线程等待&#xff0c;直到被其他线程唤醒 void no…

网络安全(sql注入)

这里写目录标题 一. information_schema.tables 和 information_schema.schemata是information_schema数据库中的两张表1. information_schema.schemata2. information_schema.tables 二. 判断注入类型1. 判断数字型还是字符型注入2. 判断注入闭合是""还是 三. 判断表…

Keras深度学习中文文本分类

一.文本分类概述 文本分类旨在对文本集按照一定的分类体系或标准进行自动分类标记&#xff0c;属于一种基于分类体系的自动分类。文本分类最早可以追溯到上世纪50年代&#xff0c;那时主要通过专家定义规则来进行文本分类&#xff1b;80年代出现了利用知识工程建立的专家系统&…

电动机制造5G智能工厂工业物联数字孪生平台,推进制造业数字化转型

电动机制造5G智能工厂工业物联数字孪生平台&#xff0c;推进制造业数字化转型。5G智能工厂与物联数字孪生平台的融合应用&#xff0c;为电动机制造业的数字化转型铺设了一条高速通道。这一创新模式不仅极大地提升了生产效率&#xff0c;还深刻改变了产品的设计、生产、管理及运…

音视频入门基础:WAV专题(9)——FFmpeg源码中计算WAV音频文件每个packet的duration和duration_time的实现

音视频入门基础&#xff1a;WAV专题系列文章&#xff1a; 音视频入门基础&#xff1a;WAV专题&#xff08;1&#xff09;——使用FFmpeg命令生成WAV音频文件 音视频入门基础&#xff1a;WAV专题&#xff08;2&#xff09;——WAV格式简介 音视频入门基础&#xff1a;WAV专题…

深入理解Java虚拟机:Jvm总结-虚拟机字节码执行引擎

第八章 虚拟机字节码执行引擎 8.1 意义 不受物理条件制约地定制指令集与执行引擎的结构体系&#xff0c;能够执行那些不被硬件直接支持的指令集格式。输入的是字节码二进制流&#xff0c;处理过程是字节码解析执行的等效过程&#xff0c;输出的是执行结果 8.2 运行时栈帧结构…

一文读懂在线学习凸优化技术

一文读懂在线学习凸优化技术 在当今的数据驱动时代&#xff0c;机器学习算法已成为解决复杂问题的关键工具。在线学习凸优化作为机器学习中的一项核心技术&#xff0c;不仅在理论研究上具有重要意义&#xff0c;还在实际应用中展现出巨大的潜力。本文将深入浅出地介绍在线学习…

编程新纪元:AI如何成为你的编程伙伴

随着人工智能技术的不断进步&#xff0c;我们正步入一个编程的新纪元。在这个时代&#xff0c;AI不仅仅是一个工具&#xff0c;更是程序员的伙伴。它通过提供智能辅助、自动化编码和增强开发效率&#xff0c;正在改变我们编写和理解代码的方式。本文将探讨AI如何成为程序员的得…

精品PPT | 离散制造行业智能工厂总体解决方案

一、建设背景 离散制造业&#xff0c;包括机械制造业、汽车制造业和家电制造业等&#xff0c;其生产过程涉及多个不连续的工序&#xff0c;产品通常由多个零件装配而成。这类行业面临的挑战包括品种多、批量小、订单变化快、临时插单频繁以及外协件管理困难等问题&#xff0c;…

2025年第八届计算机图形和虚拟国际会议(ICCGV 2025)即将召开!

2025年第八届计算机图形和虚拟国际会议&#xff08;ICCGV 2025&#xff09;将于2025年2月21-23日在中国成都举行。随着信息技术的飞速发展&#xff0c;计算机图形学与虚拟现实技术正以前所未有的速度重塑着我们的认知世界与交互体验。从沉浸式游戏到精准医疗模拟&#xff0c;从…

如何将镜像推送到docker hub

前言 这一篇应该是最近最后一篇关于docker的博客了&#xff0c;咱来个有始有终&#xff0c;将最后一步——上传镜像给他写完&#xff0c;废话不多说&#xff0c;直接进入正题。 登录 首先需要确保登录才能推送到你的仓库中去&#xff0c;在终端输入docker login,输入用户名和…

AutosarMCAL开发——基于EB Gpt驱动

目录 1.Gpt原理2.EB配置以及接口应用2.1 EB配置2.2 接口应用 3.总结 1.Gpt原理 autosar GPT模块&#xff08;General Purpose Timer&#xff0c;通用定时器&#xff09;主要用于汽车ECU中的时间测量、计数和产生定时中断。它支持单次性和周期性定时器&#xff0c;可以在达到预…

阿里云机房火灾?盘点五大机房火灾现场

号主&#xff1a;老杨丨11年资深网络工程师&#xff0c;更多网工提升干货&#xff0c;请关注公众号&#xff1a;网络工程师俱乐部 下午好&#xff0c;我的网工朋友。 不知道大家有没有看到今天有关阿里云的新闻&#xff0c;没错就是阿里云新加坡的网络节点出现了异常&#xff…

【828华为云征文|如何使用华为云Flexus X实例搭建私人博客:从配置到发布全指南】

文章目录 华为云Flexus X实例介绍搭建专属私人博客准备工作具体操作指南服务器环境确认宝塔软件商店操作一键部署WordPress私人博客域名解析WordPress安装初始页数据库信息配置运行安装程序配置博客信息博客管理后台&#xff08;默认为wp-login.php页面&#xff09;博客前台页面…

让AI成为打光工具人(Stable Diffusion进阶篇:Imposing Consistent Light)

前言 正巧我之前一直在学习的B站up也恢复了关于Stable Diffusion的教程&#xff0c;今天就一起来学习一下IC-Light&#xff0c;这样一项可以帮助喜欢拍照的同学们打光布景的插件。 IC-Light IC-Light的全称是Imposing Consistent Light&#xff0c;翻译过来就是给物体施加一…

Git 修改Push后的Commit Message

向远程仓库push代码之后&#xff0c;在IDEA中无法直接修改Commit Message&#xff0c;需要在终端或控制台中输入以下命令&#xff08;HEAD~1中的1表示只对最后一个提交进行修改&#xff0c;因此1可以自定义&#xff09; git rebase -i HEAD~1执行完rebase指令后&#xff0c;会…