[爬虫]爬取猫眼电影票房信息(信息字体加密)

猫眼电影里面的实时票房, 票房占比等信息是字体加密的, 所以要爬取这些信息需要解决字体加密这个问题. 下面介绍一种解密字体的办法.
图片1
在橙色方块标注的地方我们可以看出字体是加密的, 我们就以这部分字体为例进行解析.

首先我面要找到加密的字体, 查看网页源代码, 搜索font-family, 找到base64后面的字体字符串, 下图中方框中的部分.图片2
创建一个font_cat.py的文件, 并将这部分字符串粘贴出来, 用来生成字体文件,.

from io import BytesIO
from fontTools.ttLib import TTFont
import base64


def make_font_file(base64_string: str):
    # 将base64编码的字体字符串解码成二进制流
    bin_data = base64.decodebytes(base64_string.encode())
    with open("maoyan.woff", "wb") as fp:
        fp.write(bin_data)
    return bin_data


def convert_font_to_xml(bin_data):
    # BytesIO把一个二进制内存块当成文件来操作
    font = TTFont(BytesIO(bin_data))
    # 将解码字体保存为xml
    font.saveXML("maoyan.xml")


base_str = """d09GRgABAAAAAAgoAAsAAAAAC7......j0DFdI30hPSPXol6k5vTV2iIps1a3Wi+KmnPqxVhjCxeBfasZUUiSrs+XY82sjqpbp46yGPTFpKr2ak0RkhazwtlR86i42RVfGn93nCip5t5gh/gPYnXLBAHicbYs7DoAgFATf4gdFvIsIorQo3MXGzsTjGx+t00yykyVBBUX/aAhUqNGghUSHHgoDNEbCI+/rTMlNn7NdEnvyG+8uW7Y3B+9+Lt25WHow7LjP5R9WohcavReI"""

convert_font_to_xml(make_font_file(base_str))

这段代码会会生成两个文件maoyan.woff和maoyan.xml, 将woff的文件用FontCreator软件打开(当然如果嫌下载软件麻烦你也可以用百度在线的FontEditor), 可以得到加密字体之间的对应关系表.图片3
准备工作差不多了, 下面就可以开始具体的解析了

import requests
import lxml.html
import re
from io import BytesIO
from fontTools.ttLib import TTFont
import base64


def make_font_file(base64_string: str):
    bin_data = base64.decodebytes(base64_string.encode())
    return bin_data


base_str = """d09GRgABAAAAAAgoAAsAAAAAC7......j0DFdI30hPSPXol6k5vTV2iIps1a3Wi+KmnPqxVhjCxeBfasZUUiSrs+XY82sjqpbp46yGPTFpKr2ak0RkhazwtlR86i42RVfGn93nCip5t5gh/gPYnXLBAHicbYs7DoAgFATf4gdFvIsIorQo3MXGzsTjGx+t00yykyVBBUX/aAhUqNGghUSHHgoDNEbCI+/rTMlNn7NdEnvyG+8uW7Y3B+9+Lt25WHow7LjP5R9WohcavReI"""


url = "http://piaofang.maoyan.com/?ver=normal"
headers = {
    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36'
}

result = requests.get(url=url, headers=headers)
tree = lxml.html.fromstring(result.content.decode("utf8"))
# 抓取当前页面的具体字体
text = tree.xpath('//*[@id="ticket_tbody"]/ul[1]/li[2]/b/i/text()')[0]
# 因为页面刷新字体会发生变化, 在这里动态获取当前的字体。
font_str = re.findall(r'base64,(.*?)\)', result.text)[0]
# 得到基础字体绘制的点阵关系
baseFont = TTFont(BytesIO(make_font_file(base_str)))
# print(baseFont["cmap"].tables[0].ttFont.getGlyphOrder())


def decode_font_advance(font_str):
    match_font = TTFont(BytesIO(make_font_file(font_str)))
    # 准备一个字典用于存放新的对应关系
    numDic = {}
    uniList = match_font["cmap"].tables[0].ttFont.getGlyphOrder()
    # 手动写一个基础字体之间的对应关系(就是之前用FontCreator软件打开的字体对照关系)
    base_num_list = [".", "9", "2", "4", "8", "6", "3", "1", "5", "0", "7"]
    base_unicode = ["x", "uniEE40", "uniF35E", "uniF068", "uniE4F3", "uniE61D", "uniF62E", "uniF44B", "uniE491",
                    "uniEBC2", "uniF397"]
    for i in range(1, 12):
        # 找到新字体的绘制点阵
        matchGlyph = match_font["glyf"][uniList[i]]
        for j in range(11):
            # 取出基础字体的绘制点阵, 与新的点阵依次进行对比, 如果绘制点阵相同说明是同一个字
            baseGlyph = baseFont["glyf"][base_unicode[j]]
            if matchGlyph == baseGlyph:
                # 将新的对应关系存入字典
                numDic[uniList[i]] = base_num_list[j]
                break
    return numDic


# 解析页面具体的文字
def decode_encrypt_text(text, font_str):
    # font1 = TTFont(BytesIO(make_font_file(font_str)))
    # c = font1.getBestCmap()
    result = ""
    for i in range(len(text)):
        if text[i] == ".":
            key_str = "x"
        elif text[i] == '%':
            key_str = "%"
        else:
            key_str = "uni" + (text[i].encode("unicode-escape")[-4:].decode()).upper()
        if key_str == "%":
            real_data_cat = "%"
        else:
            real_data_cat = decode_font_advance(font_str)[key_str]
        result += real_data_cat
    return result


print(decode_encrypt_text(text, font_str))

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值