猫眼爬虫-字体加密

引言

最近又爬了一次猫眼的票房数据,发现其字体加密手段又加强了,在此记录一下
在这里插入图片描述

分析字体源

  • 下载字体文件
    在这里插入图片描述
    ​ 从此处可以得到字体文件链接,下载下来

  • 分析字体文件

    不难发现每次请求,都会随机匹配一个字体文件

    先用fontEditor打开看看
    在这里插入图片描述
    对比两次请求的字体文件,并无规律可寻

    利用TTfont将字体文件转成xml

    font = TTFont(woff_file)
    font.saveXML('test.XML')
    

    以数字5举例,5的字形(根据这些坐标点可以画出数字)
    在这里插入图片描述
    哇靠,居然是不一样的(几月前都是一样的),没事没事,小问题,虽然说是不一样的,但是差距不会太大,截图部分一眼扫过去,感觉坐标点也没有差太多,可以设定一个阈值,差值在阈值内,便可判定是同一个数字,于是乎,先看看坐标点的差值

num = len(x1)
if num > len(x2):
     num = len(x2)
x_ = [x1[i] - x2[i] for i in range(num)]
y_ = [y1[i] - y2[i] for i in range(num)]

执行完后,居然报了链表越界的错误,于是查看坐标点的个数,妈个鸡,居然一个39,一个38,这咋整,也不能采用这种方法了。

想来想去,也只好进行图像识别了,先根据数字的坐标点将数字画出来,再通过tesseract去识别,需要注意的是,tesseract无法识别单个字符,所以将每个数字画了两遍。
在这里插入图片描述
这很明显是个5吧,虽然说tesseract准确率不是很高,但是这应该不难识别吧,一顿操作之后,tesseract给识别出来的是9,其他数字识别的几乎都不对,还有识别成字母、标点符号。

无奈呀,只好自己训练一个识别这些数字的数据集,查阅了一些训练的流程,折腾了一会,总算解决了,正好把如何用tesseract训练自己的数据集也做了一个总结,见另一篇博客

完整代码

# coding=utf-8
import os
import re
import time
import urllib.request

import pytesseract
from PIL import Image
from fontTools.ttLib import TTFont
import requests
from lxml import etree
from matplotlib import pyplot as plt
import numpy as np


def deal_font(font):

    font_name = font.getGlyphOrder()[2:]
    zb = [font['glyf'][i].coordinates for i in font_name]
    fig, ax = plt.subplots()
    for index, one in enumerate(zb):
        x, y = [i[0] for i in one], [i[1] for i in one]
        plt.plot(x, y)
        x_n = [i + np.max(x) + 100 for i in x]
        plt.plot(x_n, y)
        plt.fill(x, y, 'black')
        plt.fill(x_n, y, 'black')
        # 去边框
        ax.spines['top'].set_visible(False)
        ax.spines['right'].set_visible(False)
        ax.spines['bottom'].set_visible(False)
        ax.spines['left'].set_visible(False)
        # 去刻度
        plt.axis('off')
        plt.fill(x, y, 'black')
        plt.savefig('images/%s.jpg' % index)
        plt.close()
    path = 'images/'
    num = []
    # 灰度、二值化
    for one in os.listdir(path):
        img = Image.open(path + one)
        imgry = img.convert("L")
        threshold = 140
        table = []
        for i in range(256):
            if i < threshold:
                table.append(0)
            else:
                table.append(1)
        out = imgry.point(table, '1')
        out.save(path + one)
        text = pytesseract.image_to_string(out, lang="num")
        num.append(text[0])
    # 字名与数字
    name_num = {font_name[i]: num[i] for i in range(len(font_name))}
    return name_num

headers = {
    'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.120 Safari/537.36',
}
def parse(url):
    resp = requests.get(url, headers=headers)
    resp.encoding = 'utf-8'
    text = resp.text
    with open('main.html','w', encoding='utf-8') as fp:
        fp.write(text)
    woff = re.findall(r"url\('(.+?\.woff)'\)", text)[0]
    # 下载字体文件
    woff_file = os.path.join('fonts', os.path.basename(woff))
    if not os.path.isfile(woff_file):
        urllib.request.urlretrieve('http:'+woff, woff_file)
    # 当前页面字名与数字对应关系
    font = TTFont(woff_file)
    name_num = deal_font(font)
    trans_font = {'&#'+hex(k)[1:]+';': name_num[v] for k, v in font['cmap'].getBestCmap().items() if v != 'x'}
    resp.encoding = 'utf-8'
    text = resp.text
    for k,v in trans_font.items():
        if k in text:
            text = text.replace(k, v)
    html = etree.HTML(text)
    movie_name = html.xpath("//h3[@class='name']/text()")[0]
    pf = html.xpath("//div[@class='movie-index-content box']//text()")
    pf = ''.join(pf).strip()
    print(movie_name, pf)

def main():
    url = 'https://maoyan.com/board'
    resp = requests.get(url, headers=headers)
    html = etree.HTML(resp.text)
    next_url = html.xpath("//p[@class='name']/a/@href")
    for one in next_url:
        parse("https://maoyan.com"+one)
        time.sleep(5)


if __name__ == '__main__':
    main()
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值