手把手教你處理 JS 逆向之 SVG 映射
大家好,我是安果!
前面三篇文章分別從圖片僞裝、字體反爬、CSS 偏移這 3 個方面,講解了應對這類反爬網站時的解決方案
本篇文章聊聊另外一種常見的反爬方案,即:「 SVG 映射 」
SVG 全稱爲 Scalable Vector Graphics,是一種基於 XML 並可以縮放的矢量圖片文件格式
而 SVG 反爬是利用 CSS 樣式及 SVG 圖片,將 SVG 圖片中提取字符內容,映射到網頁元素中,由於不能直接通過網頁元素直接提取數據,所以起到了反爬的目的
目標對象:
aHR0cDovL3d3dy5wb3J0ZXJzLnZpcC9jb25mdXNpb24vZm9vZC5odG1s
1、分析
打開目標頁面,查看頁面中電話號碼的網頁元素
我們發現,電話號碼中的每一個數字都對應一個 d 標籤,d 標籤中的 class 屬性值都是以「 vhk 」開頭的
查看右側 Styles 樣式標籤後,發現上面匹配的 d 標籤的背景圖片「 background-image 」被設置爲一張 SVG 圖片,d 標籤的寬度固定爲 14px,高度爲 30px
在樣式「 vhkbvu 」中,通過定義 background_position 指定背景圖片的移動方向,比如:圖中相當於背景圖片向左移動 386px,向上移動 97px
然後,我們查看 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 」即可以獲取完整的源碼
如果你覺得文章還不錯,請大家 點贊、分享、留言 下,因爲這將是我持續輸出更多優質文章的最強動力!
AirPython 專注於 Python 爬蟲 / 自動化 / Web 原創技術乾貨!
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/cI6XqyaQdX4Q1a5FRCMd3A