1. 反爬篇 | 手把手教你處理 JS 逆向之字體反爬

        共 3649字,需瀏覽 8分鐘

         ·

        2022-05-24 12:08

        大家好,我是安果!

        上一篇文章我們講解了 JS 逆向中一種常見的反爬方案「 圖片偽裝 」

        反爬篇 | 手把手教你處理 JS 逆向之圖片偽裝

        本篇文章將聊聊另一種更加常見的反爬方案「 字體反爬

        它的實(shí)現(xiàn)原理為通過自定義的字體替換網(wǎng)頁元素中的部分內(nèi)容來實(shí)現(xiàn)的反爬策略

        常見的字體格式包含:ttf、eot、woff,我們一般在網(wǎng)頁中通過關(guān)鍵字「 @font-face 」定義字體樣式,然后再設(shè)置到元素控件樣式中去

        //定義字體樣式
        @font-face{
        ?font-family:"字體文件的名字,比如:gzfont";
        ?src:url('字體文件的鏈接');
        }

        //?給某個(gè)元素控件設(shè)置字體樣式
        .gzfont?{
        ????font-family:?gzfont;
        }

        目前有很多主流網(wǎng)站引入了字體反爬,比如:某 8 同城、某車之家等

        今天研究的目標(biāo)對象是:

        aHR0cHM6Ly93d3cuZ3VhemkuY29tL2J1eQ==

        1、分析一下

        打開目標(biāo)頁面及瀏覽器的開發(fā)者工具欄,我們發(fā)現(xiàn)汽車價(jià)格、首付金額、公里數(shù)中的部分內(nèi)容在源碼中顯示為亂碼,但在界面中展示正常

        元素的字體樣式名稱為「?gzfont

        我們在網(wǎng)頁源碼中通過關(guān)鍵字「?gzfont 」嘗試查找字體的實(shí)際 URL 地址

        但是源碼中并未出現(xiàn)字體定義的邏輯,因此我們可以推測字體實(shí)際加載地址是通過 Ajax 加載的

        我們在「 Sources 」面板下,通過上面的關(guān)鍵字全局搜索該關(guān)鍵字出現(xiàn)的所有代碼塊進(jìn)行逐一分析

        通過新增一個(gè)斷點(diǎn),找到?gzfont 字段生成的邏輯及字體 URL 地址

        在瀏覽器的新窗口中,通過字體 URL 下載字體文件,然后在 PC 上使用軟件?FontCreator 打開查看

        下載地址:

        https://www.pcsoft.com.cn/soft/21156.html

        我們發(fā)現(xiàn)字體映射關(guān)系很簡單,數(shù)目也很少,并且映射關(guān)系是固定的

        PS:每次重新加載頁面,字體 URL 地址、映射關(guān)系都是固定的

        所以,我們可以通過一個(gè)字典定義它們的映射關(guān)系

        #?字體映射關(guān)系
        # PS:由于字體數(shù)目很少,所以可以直接寫死字體的映射關(guān)系
        font_relation_map?=?{
        ????'uniE9CE':?0,
        ????'uniE41D':?1,
        ????'uniE630':?2,
        ????'uniEAF2':?3,
        ????'uniE325':?4,
        ????'uniE891':?5,
        ????'uniEC4C':?6,
        ????'uniE1D0':?7,
        ????'uniE76E':?8,
        ????'uniE52E':?9
        }

        最后,我們分析發(fā)現(xiàn)頁面數(shù)據(jù)都是通過下面的網(wǎng)絡(luò)請求獲取的

        我們只需要將里面的亂碼數(shù)據(jù)根據(jù)字體映射關(guān)系替換為正常的數(shù)據(jù)即可

        2、具體實(shí)現(xiàn)

        下面,我們聊聊爬取網(wǎng)頁內(nèi)容的步驟

        首先,我們需要安裝字體解析的依賴庫?fonttools

        #?安裝依賴
        pip3?install?fonttools

        然后,解析字體文件,根據(jù)上面響應(yīng)數(shù)據(jù)中的數(shù)據(jù)格式,重新組成一個(gè)新的字典數(shù)據(jù)

        def?get_font_map():
        ????"""
        ????獲取字體映射關(guān)系
        ????:return:
        ????"""

        ????font?=?TTFont(r'gzfont.woff2')

        ????#?字體文件轉(zhuǎn)為xml文件
        ????#?font.saveXML(r"font.xml")

        ????font_map?=?font.getBestCmap()
        ????font.close()

        ????#?print(font_map)

        ????new_font_map?=?{}

        ????#?遍歷字典,重新組成一個(gè)新的映射字典
        ????for?index,?key?in?enumerate(font_map):
        ????????value?=?font_map[key]

        ????????#?捕獲異常
        ????????try:
        ????????????temp?=?font_relation_map[value]
        ????????except:
        ????????????temp?=?''
        ????????if?temp?!=?'':
        ????????????#?根據(jù)響應(yīng)結(jié)果中字體反爬數(shù)據(jù)格式,將鍵值前面添加字符串&#,用于匹配
        ????????????new_font_map['&#'?+?str(key)?+?";"]?=?temp

        ????return?new_font_map

        接著,模擬上面的網(wǎng)絡(luò)請求獲取響應(yīng)數(shù)據(jù);遍歷上面的字典鍵值對,判斷鍵?key 是否包含在響應(yīng)結(jié)果

        如果包含,就將響應(yīng)結(jié)果中的鍵 key 全部替換該鍵對應(yīng)的值 value

        import?json
        import?time
        import?requests

        def?get_car_list(pagenum:?int,?new_font_map:?dict):
        ????"""
        ????獲取車列表數(shù)據(jù)
        ????:param?new_font_map:
        ????:return:
        ????"""

        ????url?=?f"https://mapi.**.com/car-source/carList/pcList?osv=IOS&minor=&sourceType=&ec_buy_car_list_ab=**"

        ????payload?=?{}
        ????headers?=?{
        ????????'authority':?'mapi.**.com',
        ????????'accept':?'application/json,?text/plain,?*/*',
        ????????'origin':?'https://www.**.com',
        ????????'platform':?'5',
        ????????'referer':?'https://www.**.com/',
        ????????'token':?'',
        ????????'user-agent':?'Mozilla/5.0?(Macintosh;?Intel?Mac?OS?X?10_15_7)?AppleWebKit/537.36?(KHTML,?like?Gecko)?Chrome/101.0.4951.64?Safari/537.36'
        ????}

        ????resp_str?=?requests.request("GET",?url,?headers=headers,?data=payload).text

        ????#?全局替換
        ????for?key,?value?in?new_font_map.items():
        ????????if?key?in?resp_str:
        ????????????resp_str?=?resp_str.replace(key,?str(value))

        最后就可以進(jìn)行數(shù)據(jù)提取了

        ...
        #?數(shù)據(jù)解析
        ????resp?=?json.loads(resp_str)
        ????postList?=?resp.get("data").get("postList")

        ????for?item?in?postList:
        ????????title?=?item.get("title")
        ????????road_haul?=?item.get("road_haul")??#?公里
        ????????license_date?=?item.get("license_date")??#?購買時(shí)間
        ????????price?=?item.get("price")??#?價(jià)格
        ????????first_pay?=?item.get("first_pay")??#?首付

        ????????print(f'車型:{title},公里數(shù):{road_haul},購買時(shí)間:{license_date},價(jià)格:{price},首付:{first_pay}')
        ...

        運(yùn)行爬蟲,我們發(fā)現(xiàn)爬取到的數(shù)據(jù)不存在亂碼,都正常顯示了

        3、總結(jié)一下

        在日常工作中,應(yīng)對字體反爬的常規(guī)步驟如下:

        • 檢查網(wǎng)頁控件的字體名稱

        • 通過網(wǎng)頁源碼、Network 面板(Font)、Source 面板(關(guān)鍵字搜索)及調(diào)試的方式獲取字體地址

        • 在 PC 端通過軟件查看字體的映射關(guān)系

        • 通過頁面刷新、下載查看字體,判斷字體文件是否動態(tài)生成

        • 使用依賴庫?fonttools 解析字體,根據(jù)元素內(nèi)容生成新的鍵值對

        • 對響應(yīng)結(jié)果根據(jù)鍵值對進(jìn)行內(nèi)容替換

        我已經(jīng)將文中所有源碼上傳到后臺,回復(fù)關(guān)鍵字「 字體反爬 」即可以獲取完整源碼

        如果你覺得文章還不錯(cuò),請大家?點(diǎn)贊、分享、留言?下,因?yàn)檫@將是我持續(xù)輸出更多優(yōu)質(zhì)文章的最強(qiáng)動力!


        推薦閱讀


        用 Python 遠(yuǎn)程控制 Windows 服務(wù)器,太好用了!

        JavaScript 逆向爬蟲中的瀏覽器調(diào)試常見技巧

        JavaScript 逆向爬蟲中的瀏覽器調(diào)試常見技巧(下)

        反爬篇 | 手把手教你處理 JS 逆向之圖片偽裝


        END


        好文和朋友一起看~
        瀏覽 100
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評論
        圖片
        表情
        推薦
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
          
          

            1. xxxxx亚洲 | 老师上课夹震蛋高潮了 | 囯产一级a一级a免费视频 | 无套内谢少妇高潮毛片 | 中文阴毛淫欲日逼 |