前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >反爬篇 | 手把手教你处理 JS 逆向之字体反爬(下)

反爬篇 | 手把手教你处理 JS 逆向之字体反爬(下)

作者头像
AirPython
发布2023-08-22 08:23:25
4100
发布2023-08-22 08:23:25
举报
文章被收录于专栏:Python 自动化Python 自动化
大家好,我是安果!

上一篇文章我们使用 Scrapy + Selenium 爬取了某个电影网站即将上映的影片

休闲时光:最近上映的电影与爬虫世界,带您彻底放松!

但是该网站针对一些比较敏感的数据(比如:票房、热度、评分等)做了字体反爬

本篇文章将以「 影片热度 」为例,讲解字体反爬的完整处理方案

1、安装依赖

代码语言:javascript
复制
# 依赖
# OCR
pip3 install ddddocr

# 字体管理
pip3 install fontTools 

# 图片管理
pip3 install Pillow

2、下载字体及格式转换

通过分析,我们发现关键数字与网页中中引入的字体样式有关,并且每次刷新页面,引用的字体地址是变化的

因此,我们需要获取网页源码,利用正则表达式解析出字体的下载地址

代码语言:javascript
复制
def download_font(url, font_path):
    headers = {
        "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-Encoding": "gzip, deflate, br",
        "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
        "Cache-Control": "max-age=0",
        "Connection": "keep-alive",
        "Host": "www.maoyan.com",
        "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/114.0.0.0 Safari/537.36",
        "sec-ch-ua": "\"Not.A/Brand\";v=\"8\", \"Chromium\";v=\"114\", \"Google Chrome\";v=\"114\"",
        "sec-ch-ua-mobile": "?0",
        "sec-ch-ua-platform": "\"Windows\""
    }

    # 获取网页源码
    resp_pre = requests.get(url, headers=headers)
    resp = resp_pre.text

    # 解析出字体文件(woff格式)的下载地址
    font_file = re.findall(r's3plus\.meituan\.net\/v1\/mss_73a511b8f91f43d0bdae92584ea6330b\/font\/(\w+\.woff)', resp)[
        0]
    font_url = 'https://s3plus.meituan.net/v1/mss_73a511b8f91f43d0bdae92584ea6330b/font/' + font_file

获取字体 URL 下载地址后,我们将字体文件下载到本地

需要注意的是,下载字体时设置请求头和上面请求头不一致,不然下载的字体可能受损

代码语言:javascript
复制
font_headers = {
        'authority': 's3plus.meituan.net',
        'accept': '*/*',
        'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8',
        'origin': 'https://www.**.com',
        'referer': 'https://www.**.com/',
        'sec-ch-ua': '"Not.A/Brand";v="8", "Chromium";v="114", "Google Chrome";v="114"',
        'sec-ch-ua-mobile': '?0',
        'sec-ch-ua-platform': '"Windows"',
        'sec-fetch-dest': 'font',
        'sec-fetch-mode': 'cors',
        'sec-fetch-site': 'cross-site',
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36',
    }

 # 下载字体文件到本地
 # 注意:这里下载字体必须使用特有的Header,不然下载的字体会受损
 font_content = requests.get(font_url, headers=font_headers)
 with open(f'./{font_file}', 'wb') as f:
     f.write(font_content.content)
     f.close()

最后,将 woff 字体文件转换为 ttf 格式

代码语言:javascript
复制
from fontTools.ttLib.woff2 import decompress

...
# 将 woff文件转成 ttf 文件
decompress(font_file, font_path)

3、字体映射关系

通过 FontCreator 工具打开字体文件,可以获取数字和字体编码的映射关系

通过对多个字体文件进行对比发现,上面的映射关系不是固定的

因此,我们需要借助字体图片绘制及 OCR,动态获取字体中的映射关系

代码语言:javascript
复制
from PIL import ImageFont, Image, ImageDraw
from io import BytesIO
from fontTools.ttLib import TTFont
from fontTools.ttLib.woff2 import decompress
import ddddocr

def get_font_keymap(font_path):
    ...

    # 映射字典
    font_dict = {}

    # 解析字体文件中的编码对应关系
    for cmap_code, glyph_name in font.getBestCmap().items():
        # print(cmap_code,glyph_name)

        # 实例化一个图片对象(给定的模式和大小创建一个新图像) 白色
        img = Image.new('1', (img_size, img_size), 255)
        # img.show()

        # 绘制图片
        draw = ImageDraw.Draw(img)

        x, y = draw.textsize(chr(cmap_code), font=font_img)

        draw.text(((img_size - x) // 2, (img_size - y) // 2), txt, font=font_img, fill=0)
        bytes_io = BytesIO()
        img.save(bytes_io, format="PNG")

        # 使用OCR识别字体
        content= ocr.classification(bytes_io.getvalue())

        # 加入到键值对中
        font_dict[glyph_name] = content
    return font_dict

4、网页内容还原

通过上面数字与字体编码的映射关系,我们将网页中做了字体反爬的内容替换为正确的数字

代码语言:javascript
复制
# 3、替换源码,将加密内容替换为明文
# .
for key in font_dict.keys():
    # print("key:", f'&#x{key[3:]};'.lower())
    # 去掉前面3个字符,将内容替换成对应的数字
    resp = resp.replace(f'&#x{key[3:]};'.lower(), font_dict[key])

5、爬虫

接下来,我们就可以对网页关键数据进行提取的

代码语言:javascript
复制
import re
from lxml import etree
import os

# 使用lxml解析HTML
root = etree.HTML(resp)
elements = root.xpath('//span[@class="stonefont"]/text()')

for element in elements:
    print(element)

我已经将文中所有源码上传到后台,回复关键字「 230710 」即可以获取完整源码

如果你觉得文章还不错,请大家 点赞、分享、留言 下,因为这将是我持续输出更多优质文章的最强动力!

推荐阅读

用 Python 远程控制 Windows 服务器,太好用了!

JavaScript 逆向爬虫中的浏览器调试常见技巧

JavaScript 逆向爬虫中的浏览器调试常见技巧(下)

反爬篇 | 手把手教你处理 JS 逆向之图片伪装

反爬篇 | 手把手教你处理 JS 逆向之字体反爬

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2023-07-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 AirPython 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
AI 应用产品
文字识别(Optical Character Recognition,OCR)基于腾讯优图实验室的深度学习技术,将图片上的文字内容,智能识别成为可编辑的文本。OCR 支持身份证、名片等卡证类和票据类的印刷体识别,也支持运单等手写体识别,支持提供定制化服务,可以有效地代替人工录入信息。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档