網址:http://www.porters.vip/confusion/food.html
開啟開發者工具後
頁面原始碼並不是真實的數字,隨便點一個d標籤檢視其樣式
我們需要找到兩個檔案,food.css和food.svg檔案,點開第一個紅框會在Sources皮膚開啟該檔案,滑鼠放到food.css檔名上,顯示的就是food.css的地址
滑鼠放到第二個紅框的url上面,得到的就是food.svg的地址,也可以右鍵Copy link address獲取地址
svg_url = 'http://www.porters.vip/confusion/font/food.svg' css_url = 'http://www.porters.vip/confusion/css/food.css'
這裡我們開啟svg的地址後是這樣的
我們會看到四行毫無規律的數字,檢視原始碼發現又是一堆看著像加密的程式碼(其實不是,這裡是svg-font的座標)
然後開啟css檔案
這裡的background的css渲染數字的座標
到此,需要解釋一下為什麼會有兩個座標,及字元定位的問題:
瀏覽器根據css樣式中設定的座標和元素寬高來確定svg中對應的數字。
接下來我們就只獲取下面圖中的電話號碼
因為獲取d標籤的class屬性比較容易,這裡就簡單構造一個電話號SVG列表
獲取svg檔案和css檔案,以及構造電話號svg列表(這裡比較簡單,沒什麼解釋的)
def get_file(url): resp = requests.get(url=url) content = resp.text return content svg_url = 'http://www.porters.vip/confusion/font/food.svg' css_url = 'http://www.porters.vip/confusion/css/food.css' css_content = get_file(css_url) svg_content = get_file(svg_url) # 獲取原始碼中電話號的SVG列表 svg_list = ['vhkbvu', 'vhk08k', 'vhk08k', 'vhk84t', 'vhk6zl', 'vhkqsc', 'vhkqsc', 'vhk6zl']
for svg_name in svg_list:
print(svg_name)
...
在上一步,我們已經可以通過迴圈拿到每一個svg_name,接下來就是通過正則獲取css文字中,對應的svg_name的樣式(座標)
def get_css_coordinates(css_content, svg_name): res = re.findall('\.%s\s{\s+background:\s-(\d+)px\s-(\d+)px;\s}' % svg_name, css_content) if bool(res): x, y = res[0]
return (int(x), int(y))
得到css_x和css_y座標後,拿著css_y座標去定位上面svg檔案中四行數字,獲取css_x,css_y座標對應的數字
from parsel import Selector
def get_svg_text_content(svg_content, css_y): # 獲取svg中字元的font-size屬性,後面會用到 font_size = svg_content.split('font-size:')[1].split('px;')[0] svg_data = Selector(svg_content) # 獲取svg檔案 text元素的y屬性列表 svg_y_list = svg_data.xpath('//text/@y').getall() # 取到大於css_y且最近的一個 new_svg_y_list = [svg_y for svg_y in svg_y_list if css_y <= int(svg_y)] # print(new_svg_y_list[0]) # 獲取目標svg_y在原svg_y_list中的下標 index = svg_y_list.index(new_svg_y_list[0]) # print(svg_data.xpath('//text/text()').getall()) text_content = svg_data.xpath('//text/text()').getall()[index] return text_content, font_size
解釋一下,在上面所示程式碼中,在電話號svg列表中第一個元素vhkbvu,對應的css_y的值為97,而我們獲得的svg_y_list為 ['38', '83', '120', '164'],在此列表大於97且最近接的就是120,
因此我們確定svg_y的值為120,同時也確定了我們需要的是第三行資料,通過svg_y,也就是縱座標的值已經確定
現在我們獲取到了text_content為:671260781104096663000892328440489239185923,也就是上圖中的第三個text標籤中的文字,而font-size為14px
font-size也可以開啟svg檔案後找到style,檢視裡面font-size的值
下面我們來確定橫座標,橫座標確定後,我們就可以找到具體的數字值,從而完成破解
def get_char(text_content, css_x, font_size): text_chars = list(text_content) # 利用x軸的座標確定是第幾個元素 n = css_x // int(font_size) print(text_chars[n]) return text_chars[n]
至此,我們的svg反爬破解完成,下面是完整程式碼
import requests import re from parsel import Selector def get_file(url): resp = requests.get(url=url) # print(resp.text) content = resp.text return content def get_css_coordinates(css_content, svg_name): res = re.findall('\.%s\s{\s+background:\s-(\d+)px\s-(\d+)px;\s}' % svg_name, css_content) if bool(res): x, y = res[0] return (int(x), int(y)) def get_svg_text_content(svg_content, css_y): # 獲取svg中字元的font-size屬性,後面會用到 font_size = svg_content.split('font-size:')[1].split('px;')[0] svg_data = Selector(svg_content) # 獲取svg檔案 text元素的y屬性列表 svg_y_list = svg_data.xpath('//text/@y').getall() # 取到大於css_y且最近的一個 new_svg_y_list = [svg_y for svg_y in svg_y_list if css_y <= int(svg_y)] # print(new_svg_y_list[0]) # 獲取目標svg_y在原svg_y_list中的下標 index = svg_y_list.index(new_svg_y_list[0]) # print(svg_data.xpath('//text/text()').getall()) text_content = svg_data.xpath('//text/text()').getall()[index] return text_content, font_size def get_char(text_content, css_x, font_size): text_chars = list(text_content) # 利用x軸的座標確定是第幾個元素 n = css_x // int(font_size) print(text_chars[n]) return text_chars[n] def get_phone(): result = '' svg_url = 'http://www.porters.vip/confusion/font/food.svg' css_url = 'http://www.porters.vip/confusion/css/food.css' css_content = get_file(css_url) svg_content = get_file(svg_url) # 獲取原始碼中電話號的SVG列表 svg_list = ['vhkbvu', 'vhk08k', 'vhk08k', 'vhk84t', 'vhk6zl', 'vhkqsc', 'vhkqsc', 'vhk6zl'] for svg_name in svg_list: coordinate = get_css_coordinates(css_content, svg_name) if coordinate is not None: css_x, css_y = coordinate print(css_x, css_y) text_content, font_size = get_svg_text_content(svg_content, css_y) num = get_char(text_content, css_x, font_size) result += num print(result) if __name__ == '__main__': get_phone()
最後說明:此案例只是我在學習《Python3反爬蟲原理與繞過實戰》裡面svg反爬的學習心得以及實踐,供參考,不喜勿噴