<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          爬蟲高級內(nèi)容,Python如何應對字體反爬

          共 4770字,需瀏覽 10分鐘

           ·

          2022-03-04 19:30

          前言

          在編寫網(wǎng)頁爬蟲的時候,我們經(jīng)常會遇到各種反爬,比如js加密、css位置偏移、字體反爬等。最近在學習過程中,我碰到幾個網(wǎng)站,都是使用的字體反爬,其大致上可以分為兩類:一類是字體文件是靜態(tài)的,另一類字體文件是動態(tài)的變化的。今天,我們探究一下,在爬蟲中如何破解字體反爬。

          一、如何尋找字體文件

          字體文件大致上分兩種,一種是以.ttf結(jié)尾的,一種是以.woff結(jié)尾的,兩者相差不大,現(xiàn)在的網(wǎng)站運用的大多是woff文件。如何尋找網(wǎng)頁使用的字體文件,可以分兩類:

          1.第一類 字體URL在網(wǎng)頁源代碼中

          以aHR0cHM6Ly93d3cucmVucmVuY2hlLmNvbS9iai9lcnNob3VjaGUvP3Bsb2dfaWQ9NWI5NzA3MWI1YjVhNWZkYWRkOWZhZDEzMGE0MmJiMDM=網(wǎng)站為例:

          打開網(wǎng)站后,明顯能看到,8被替換成了6。這種情況,我們可以嘗試在網(wǎng)頁源代碼中搜索“font-face”,查看字體URL。

          2.第二類 字體URL不在網(wǎng)頁源代碼中,由服務器加載

          以aHR0cHM6Ly93d3cuZ3VhemkuY29tL2J1eQ==網(wǎng)站為例:

          這里可以看到車輛的行使里程數(shù)和首付均是字體反爬,按照第一種情況,我們直接在網(wǎng)頁源代碼中搜索“font-face”

          可以看到,也是有woff文件和ttf文件,但這兩個文件都是“element-icons”的鏈接,打開(軟件:FontCreator)后也就是一堆圖標。

          遇到這種的,可以打開瀏覽器Network,刷新后抓包。

          可以看到這個請求返回的結(jié)果中有一個woff文件,打開后觀察:

          這個正是我們要找的字體文件,當然這個網(wǎng)站要拿到字體URL需要js逆向verify-token這個參數(shù),這里不展開說。

          二、如何應對靜態(tài)字體反爬

          還是以aHR0cHM6Ly93d3cucmVucmVuY2hlLmNvbS9iai9lcnNob3VjaGUvP3Bsb2dfaWQ9NWI5NzA3MWI1YjVhNWZkYWRkOWZhZDEzMGE0MmJiMDM=網(wǎng)站為例,經(jīng)過觀察,他的字體是每天更換一次,暫且當作是靜態(tài)。

          1.在網(wǎng)頁源代碼中搜索字體文件的URL,復制到瀏覽器中打開,下載字體文件。

          2.用FontCreator打開文件,查看字體對應關(guān)系,手動建立對應關(guān)系字典。

          #?字體對應關(guān)系
          relation_table?=?{"zero":?"0",?"one":?"2",?"two":?"1",?"four":?"3",?"three":?"4",?"five":?"8",?"seven":?"7","nine":?"9",?"six":?"6",?"eight":?"5"}

          這是我學習過程中自己手動建立的對應關(guān)系。

          3.請求字體鏈接,獲取字體code和name的對應關(guān)系,然后遍歷,獲取網(wǎng)頁中反爬文字的真實文字。

          def?woff_font(font_url):
          ????'''獲取字體真實對應關(guān)系'''
          ????newmap?
          =?{}
          ????resp?=?session.get(font_url)??#?請求字體鏈接
          ????woff_data?=?BytesIO(resp.content)
          ????font?=?TTFont(woff_data)??#?讀取woff數(shù)據(jù)
          ????cmap?=?font.getBestCmap()??#?獲取字體對應關(guān)系
          ????font.close()
          ????for?k,?v?in?cmap.items():
          ????????value?=?v
          ????????key?=?str(k?-?48)??#?獲取真實的key
          ????????try:
          ????????????get_real_data?=?relation_table[value]
          ????????except:
          ????????????get_real_data?=?''
          ????????if?get_real_data?!=?'':
          ????????????newmap[key]?=?get_real_data??#?將字體真實結(jié)果對應
          ????return?newmap

          4.替換網(wǎng)頁中的反爬文字

          如果反爬字體是10進制或16進制的建議直接替換網(wǎng)頁代碼中的字體,如果是數(shù)字的,建議逐項替換。替換的方式有用正則表達式的(這里不說,因為我正則寫的也不好),也有用列表推導式的,比如:

          title?=?"".join(html.xpath('//*[@id="zhimaicar-detail-header-right"]/div[1]/h1/text()')).strip()??#?獲取原始標題
          trans_title?=?"".join([i?if?not?i.isdigit()?else?font[i]?for?i?in?title])??#?替換錯誤字體,獲取真實標題

          具體的用法,可以百度。

          三、如何應對動態(tài)字體反爬

          動態(tài)字體反爬,就是每請求一次(或一段時間后),字體的映射關(guān)系也會改變,因為第二個網(wǎng)站比較麻煩,這個還是以這個網(wǎng)站為例,將時間節(jié)點放大,把他看做是動態(tài)反爬的。

          1.先下載字體文件

          2.安裝fontTools

          安裝后用

          from?fontTools.ttLib?import?TTFont
          font?=?TTFont(下載的字體文件)
          font.saveXML(文件名.xml)

          將字體文件另存為xml文件,打開文件后會看到:

          ‘cmap’里存放的是字體code和name的關(guān)系

          ‘glyf’里存放的是字體形狀和name的關(guān)系

          3.手動建立字體形狀和name的關(guān)系

          只需手動建立一次。

          f_font?=?TTFont("rrcttf3d6e374d48fb2cd14247257d4ae76674.woff")??#?讀取分析的字體文件
          f_font_glyf?=?f_font['glyf']??#?獲取分析文件中的字體關(guān)系
          #?建立基礎的字體和字體形狀的對應關(guān)系
          base_font_map?=?{
          ????0:?f_font_glyf['zero'],
          ????1:?f_font_glyf['two'],
          ????2:?f_font_glyf['one'],
          ????3:?f_font_glyf['four'],
          ????4:?f_font_glyf['three'],
          ????5:?f_font_glyf['eight'],
          ????6:?f_font_glyf['six'],
          ????7:?f_font_glyf['seven'],
          ????8:?f_font_glyf['five'],
          ????9:?f_font_glyf['nine'],
          }

          4.請求網(wǎng)頁中的字體URL,獲取code和name,形狀和name的關(guān)系

          resp?=?session.get(font_url)??#?請求字體鏈接
          woff_data?=?BytesIO(resp.content)??#?保存字體數(shù)據(jù)
          font?=?TTFont(woff_data)??#?讀取woff數(shù)據(jù)
          glyf?=?font['glyf']??#?獲取請求到的字體形狀
          code_name_map?=?font.getBestCmap()??#?獲取請求到的字體code和name的對應關(guān)系
          font.close()

          5.根據(jù)形狀相同,肯定字體相同的原則,獲取真實對應關(guān)系

          for?code,?name?in?code_name_map.items():
          ????codestr?=?str(code?-?48)??#?根據(jù)分析結(jié)果需要減去48
          ????current_shape?=?glyf[name]??#?根據(jù)name獲取字體形狀
          ????for?number,?shape?in?base_font_map.items():??#?遍歷基礎字體形狀對應關(guān)系
          ????????if?shape?==?current_shape:??#?判斷,如果兩個字體形狀相等
          ????????????newmap[codestr]?=?str(number)??#?將字體編碼和字體添加到字典

          6.完整代碼

          def?woff_font(font_url):
          ????newmap?
          =?{}
          ????f_font?=?TTFont("rrcttf3d6e374d48fb2cd14247257d4ae76674.woff")??#?讀取分析的字體文件
          ????f_font_glyf?=?f_font['glyf']??#?獲取分析文件中的字體關(guān)系
          ????#?建立基礎的字體和字體形狀的對應關(guān)系
          ????base_font_map?=?{
          ????????0:?f_font_glyf['zero'],
          ????????1:?f_font_glyf['two'],
          ????????2:?f_font_glyf['one'],
          ????????3:?f_font_glyf['four'],
          ????????4:?f_font_glyf['three'],
          ????????5:?f_font_glyf['eight'],
          ????????6:?f_font_glyf['six'],
          ????????7:?f_font_glyf['seven'],
          ????????8:?f_font_glyf['five'],
          ????????9:?f_font_glyf['nine'],
          ????}
          ????resp?=?session.get(font_url)??#?請求字體鏈接
          ????woff_data?=?BytesIO(resp.content)??#?保存字體數(shù)據(jù)
          ????font?=?TTFont(woff_data)??#?讀取woff數(shù)據(jù)
          ????glyf?=?font['glyf']??#?獲取請求到的字體形狀
          ????code_name_map?=?font.getBestCmap()??#?獲取請求到的字體code和name的對應關(guān)系
          ????font.close()
          ????for?code,?name?in?code_name_map.items():
          ????????codestr?=?str(code?-?48)??#?根據(jù)分析結(jié)果需要減去48
          ????????current_shape?=?glyf[name]??#?根據(jù)name獲取字體形狀
          ????????for?number,?shape?in?base_font_map.items():??#?遍歷基礎字體形狀對應關(guān)系
          ????????????if?shape?==?current_shape:??#?判斷,如果兩個字體形狀相等
          ????????????????newmap[codestr]?=?str(number)??#?將字體編碼和字體添加到字典
          ????return?newmap

          7.結(jié)果驗證

          當我在寫這篇分享的時候,該網(wǎng)站的字體早已經(jīng)換了,但是建立關(guān)系的時候我還用的是之前的文件,可見返回的結(jié)果也是沒有問題的。

          四、總結(jié)

          靜態(tài)字體反爬不用多說,面對動態(tài)反爬,一開始我也有點懵,后來在翻閱了一些資料和別人的啟發(fā)后才弄明白,其實就是利用形狀一樣,字體肯定也一樣的對應關(guān)系去破解。這是我學習過程中的一點經(jīng)驗總結(jié),有不足之處還請各位指正,謝謝。


          最后,推薦螞蟻老師的視頻套餐課程,包含爬蟲部分,給我很大的幫助:


          瀏覽 161
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  黄色一级片视频 | 午夜精品在线观看 | 操骚女| 狠狠插综合| 久久久久久久性 |