手把手教你处理 JS 逆向之 SVG 映射

这是「进击的Coder」的第 651 篇技术分享

作者:星安果

来源:AirPython

阅读本文大概需要 9 分钟。

本篇文章聊聊另外一种常见的反爬方案,即:「 SVG 映射 」

SVG 全称为 Scalable Vector Graphics,是一种基于 XML 并可以缩放的矢量图片文件格式

而 SVG 反爬是利用 CSS 样式及 SVG 图片,将 SVG 图片中提取字符内容,映射到网页元素中,由于不能直接通过网页元素直接提取数据,所以起到了反爬的目的

目标对象:

aHR0cDovL3d3dy5wb3J0ZXJzLnZpcC9jb25mdXNpb24vZm9vZC5odG1s

1、分析

打开目标页面,查看页面中电话号码的网页元素

我们发现,电话号码中的每一个数字都对应一个 d 标签,d 标签中的 class 属性值都是以「 vhk 」开头的

d249a23df82ee124ddd11e9453495644.png

查看右侧 Styles 样式标签后,发现上面匹配的 d 标签的背景图片「 background-image 」被设置为一张 SVG 图片,d 标签的宽度固定为 14px,高度为 30px

在样式「 vhkbvu 」中,通过定义 background_position 指定背景图片的移动方向,比如:图中相当于背景图片向左移动 386px,向上移动 97px

89f054cdab2b23275b2bc8d973cbac3b.png

然后,我们查看 svg 图片的源文件

  • 字体大小为 14px,颜色值为 #666

  • 4 个 text 标签代表 4 行数字

  • 4 行数字对应的 y 轴坐标值固定为 38、83、120、164

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" width="650px" height="230.0px">
<style>text {font-family:PingFangSC-Regular,Microsoft YaHei,'Hiragino Sans GB',Helvetica;font-size:14px;fill:#666;}</style>
    <text x="14 28 42 56 70 84 98 112 126 140 154 168 182 196 210 224 238 252 266 280 294 308 322 336 350 364 378 392 406 420 434 448 462 476 490 504 518 532 546 560 574 588 602 616 630 644 658 672 686 700 714 728 742 756 770 784 798 812 826 840 854 868 882 896 910 924 938 952 966 980 994 1008 1022 1036 1050 1064 1078 1092 1106 1120 1134 1148 1162 1176 1190 1204 1218 1232 1246 1260 1274 1288 1302 1316 1330 1344 1358 1372 1386 1400 1414 1428 1442 1456 1470 1484 1498 1512 1526 1540 1554 1568 1582 1596 1610 1624 1638 1652 1666 1680 1694 1708 1722 1736 1750 1764 1778 1792 1806 1820 1834 1848 1862 1876 1890 1904 1918 1932 1946 1960 1974 1988 2002 2016 2030 2044 2058 2072 2086 2100 " y="38">154669136497975167479825383996313925720573</text>
    <text x="14 28 42 56 70 84 98 112 126 140 154 168 182 196 210 224 238 252 266 280 294 308 322 336 350 364 378 392 406 420 434 448 462 476 490 504 518 532 546 560 574 588 602 616 630 644 658 672 686 700 714 728 742 756 770 784 798 812 826 840 854 868 882 896 910 924 938 952 966 980 994 1008 1022 1036 1050 1064 1078 1092 1106 1120 1134 1148 1162 1176 1190 1204 1218 1232 1246 1260 1274 1288 1302 1316 1330 1344 1358 1372 1386 1400 1414 1428 1442 1456 1470 1484 1498 1512 1526 1540 1554 1568 1582 1596 1610 1624 1638 1652 1666 1680 1694 1708 1722 1736 1750 1764 1778 1792 1806 1820 1834 1848 1862 1876 1890 1904 1918 1932 1946 1960 1974 1988 2002 2016 2030 2044 2058 2072 2086 2100 " y="83">560862462805204755437571121437458524985017</text>
    <text x="14 28 42 56 70 84 98 112 126 140 154 168 182 196 210 224 238 252 266 280 294 308 322 336 350 364 378 392 406 420 434 448 462 476 490 504 518 532 546 560 574 588 602 616 630 644 658 672 686 700 714 728 742 756 770 784 798 812 826 840 854 868 882 896 910 924 938 952 966 980 994 1008 1022 1036 1050 1064 1078 1092 1106 1120 1134 1148 1162 1176 1190 1204 1218 1232 1246 1260 1274 1288 1302 1316 1330 1344 1358 1372 1386 1400 1414 1428 1442 1456 1470 1484 1498 1512 1526 1540 1554 1568 1582 1596 1610 1624 1638 1652 1666 1680 1694 1708 1722 1736 1750 1764 1778 1792 1806 1820 1834 1848 1862 1876 1890 1904 1918 1932 1946 1960 1974 1988 2002 2016 2030 2044 2058 2072 2086 2100 " y="120">671260781104096663000892328440489239185923</text>
    <text x="14 28 42 56 70 84 98 112 126 140 154 168 182 196 210 224 238 252 266 280 294 308 322 336 350 364 378 392 406 420 434 448 462 476 490 504 518 532 546 560 574 588 602 616 630 644 658 672 686 700 714 728 742 756 770 784 798 812 826 840 854 868 882 896 910 924 938 952 966 980 994 1008 1022 1036 1050 1064 1078 1092 1106 1120 1134 1148 1162 1176 1190 1204 1218 1232 1246 1260 1274 1288 1302 1316 1330 1344 1358 1372 1386 1400 1414 1428 1442 1456 1470 1484 1498 1512 1526 1540 1554 1568 1582 1596 1610 1624 1638 1652 1666 1680 1694 1708 1722 1736 1750 1764 1778 1792 1806 1820 1834 1848 1862 1876 1890 1904 1918 1932 1946 1960 1974 1988 2002 2016 2030 2044 2058 2072 2086 2100 " y="164">684431081139502796807382</text>
</svg>

因此,我们能得出一个结论,即:d 标签通过 SVG 背景图片,结合一定的偏移量 + 宽高度,从 SVG 图片中固定一个数字展示在页面上

2、实现

首先,我们获取 SVG 图片、CSS 样式文件的源文件

PS:为了方便后面样式的解析,需要将 CSS 样式源码的换行符和空格全部删除掉

import requests

...
def start(self):
        # 1、svg源文件
        self.svg_source = requests.get("http://www.porters.vip/confusion/font/food.svg").text

        # 2、css文件源文件
        # 注意:将换行符、空格清除,方便下一步匹配
        self.css_source = requests.get("http://www.porters.vip/confusion/css/food.css").text.replace('\n', '').replace(
            ' ', '')
...

然后,使用正则表达式解析 SVG 图片源文件,提取所有的 y 轴坐标及行数据列表

import re

...
    def parse_svg(self):
        """
        解析svg文件
        :return:
        """
        # 获取y轴值及数据
        text_content = re.findall('y="(.*?)">(.*?)</text>', self.svg_source, re.S)

        # print(text_content)

        # y轴值及行数据
        return [item[0] for item in text_content], [item[1] for item in text_content]
...

数据格式如下:

# y轴值列表及行数据值如下
# y轴值列表
['38', '83', '120', '164']

# 对应的行数据值列表
['154669136497975167479825383996313925720573', '560862462805204755437571121437458524985017', '671260781104096663000892328440489239185923', '684431081139502796807382']

最后,遍历要解析的样式名,从 SVG 图片中提取对应的数值

需要注意的是,SVG 图片的文字大小固定为 14px,根据行内容提取值时,只需要利用偏移量获取索引值,最后拿到实际指向的数值即可

...
    def get_number_from_svg(self, style_name, y_nums, datas):
        """
        获取svg中实际的数据
        :param y_nums: y轴坐标列表
        :param datas: 数据值列表
        :return:
        """
        # 使用正则表达式从样式内容中匹配x轴、y轴的偏移量(去除了换行符、空格),匹配正数字,\d+
        deviation_x, deviation_y = \
            re.compile('.%s{background:-(\d+)px-(\d+)px;}' % style_name).findall(self.css_source)[0]

        # 获取svg图片中的y轴坐标
        # 注意:这里取首次大于偏移量的y轴坐标,作为截取数据真实的y轴坐标
        position_y = [y for y in y_nums if int(deviation_y) <= int(y)][0]

        # 获取y轴坐标的索引值,然后获取该行的内容
        content = datas[y_nums.index(position_y)]

        # svg字体大小为14px,因此可以通过【偏移量/字体大小】拿到x轴的索引
        x_index = int(int(deviation_x) / 14)

        # 通过内容及索引,获取实际截取的数字
        return str(content[x_index])
...

以上就完成了对页面中「 电话号码 」的解析,我们只需要提取页面元素中的样式名,获取映射的数值进行替换即可

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

1d9b3d412b9540d4975c0ba51e77998e.png

End

崔庆才的新书《Python3网络爬虫开发实战(第二版)》已经正式上市了!书中详细介绍了零基础用 Python 开发爬虫的各方面知识,同时相比第一版新增了 JavaScript 逆向、Android 逆向、异步爬虫、深度学习、Kubernetes 相关内容,‍同时本书已经获得 Python 之父 Guido 的推荐,目前本书正在七折促销中!

内容介绍:《Python3网络爬虫开发实战(第二版)》内容介绍

f5bf32a976312e997ae443afe3684040.png

扫码购买

f32397ec5e56786dcd1e344f84d0922c.png

好文和朋友一起看~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值