当前位置:博客首页 > Python > 正文

【真实案例】python破解网站base64字体加密

作者: Jarvan 分类: Python 发布时间: 2020-06-23 17:41 百度已收录

前言:

写这篇文章的起因是想写个python脚本抓一个食品类网站的电话号码,发现该网站进行了字体加密,抓取到的是看不懂的十六进制编码,如下图:


正文:

用chrome查看相应的加密代码,发现是写在css文件里,css地址在这直接贴出来: https://wap.21food.cn/resources/css/layout.css

找到相应位置,发现是用base64编码进行的加密

对这个之前没接触过,就开始查资料,主要是查看了以下两篇文章,其中更多参考的是第2篇文章的第四种方法,具体执行步骤及我自己编写的脚本我会列出来:

将base64格式的字体信息解码成可用的字体文件

反反爬虫技术:解决网站字体加密


第1步:

提取网站字体在CSS文件中对应的代码,并自动保存为字体文件base.woff,下面代码直接复制就能用

# -*- coding:utf-8 -*-
import requests,base64

def downfont(url):
    response = requests.get(url)
    base64_string = response.text.split("base64,")[1].split("'")[0].strip()
    bin_data = base64.decodebytes(base64_string.encode())
    with open("base.woff", r"wb") as f:
        f.write(bin_data)

if __name__ == "__main__":
    url = 'https://wap.21food.cn/resources/css/layout.css'
    downfont(url)
    print('done.')

第2步:

下载FontCreator软件,下载地址:
https://www.7down.com/soft/31699.html

打开第一步中生成的”base.woff”字体库,软件会自动生成字体库的对应关系,如下图:

记得要选好captions,找到我们要抓取的网站加密字体对应的16进制编码,手动写成字典,这样我们抓取到的号码就可以与其一一对应: key = {‘10010′:’0′,’1000D’:’1′,’10011′:’2′,’1000F’:’3′,’10017′:’4′,’1000E’:’5′,’10015′:’6′,’10014′:’7′,’10012′:’8′,’10013′:’9′,’10016′:’-‘}

第3步:

编写爬虫程序,抓取我们想要抓取的页面上的电话号码吉加密过的密文,我使用正则进行匹配的,以https://wap.21food.cn/product/detail7028737.html 这个网址为例,我们需要抓取的是下图中框选区域

然后根据我们之前得到的字典,自动转为对应的真实数字,就可以拿到该网页上的号码了,具体代码如下:

# -*- coding: utf-8 -*-
import requests
import cchardet
import traceback
from lxml import html
import re
import cchardet

def downloader(url, timeout=10, headers=None, debug=False, binary=False):
    _headers = {
        'User-Agent': ('Mozilla/5.0 (compatible; MSIE 9.0; '
                       'Windows NT 6.1; Win64; x64; Trident/5.0)'),
    }
    redirected_url = url
    if headers:
        _headers = headers
    try:
        r = requests.get(url, headers=_headers, timeout=timeout)
        if binary:
            html = r.content
        else:
            encoding = cchardet.detect(r.content)['encoding']
            html = r.content.decode(encoding)
        status = r.status_code
        redirected_url = r.url
    except:
        if debug:
            traceback.print_exc()
        msg = 'failed download: {}'.format(url)
        print(msg)
        if binary:
            html = b''
        else:
            html = ''
        status = 0
    return status, html, redirected_url

def extract(source):
    p = re.findall(r'(&#x[^<]*?)<',source)[0] # 利用正则匹配加密的十六进制电话号码
    return p

def crack(key, secret):
    uncrack_phone = secret.replace(r'&#x','').split(';')[:-1]
    phonenum = ''
    for num in uncrack_phone:
        phonenum += key[num.upper()]
    return phonenum

if __name__ == '__main__':
    url = 'https://wap.21food.cn/product/detail7028737.html'
    key = {'10010':'0','1000D':'1','10011':'2','1000F':'3','10017':'4','1000E':'5','10015':'6','10014':'7','10012':'8','10013':'9','10016':'-'}
    s, html, real_url = downloader(url)
    p = extract(html) # 正则提取解密前的电话号码
    phonenum = crack(key,p)  # 根据字典解密电话号码

    print(phonenum)

放一个破解成功的截图:

撒花,庆祝一下~


扩展

编写的脚本只是针对单页面的,完全可以扩展成对整个网站页面的抓取(我没写,可能后面会写),让爬虫自动抓取整个网站的加密号码,需要注意用IP池,本文的案例网站有IP访问限制