Python爬蟲 樂居字體反爬分析 (含源碼)

嚴重聲明:本文僅用於學習交流,不得用於商業用途,同時希望大家遵循網絡協議,維護網絡和諧。

  • 上一篇文章我們分析了一下人人車的字體反爬,但是好像python進行逆向分析沒有很全,那麼今天我們來看一下樂居的字體反爬是怎麼做的,然後講一下這個代碼是怎麼走的,還是先看網站(樂居
    ):
    1. 因爲我們需要的重要信息都在詳情頁裏面,所以,點開一個新房的詳情頁。按F12觀察網頁源碼裏面和正文的異同。如下圖所示,我們可以看到,和人人車一樣,都是利用css樣式渲染,讓源碼裏面的數字進行變換,讓我們看到真實數據。在源碼搜索new_font這個樣式一共有三個,兩個就是圖片裏裏面的,將指導價和開盤時間字體轉換。另一個,不是寫在樣式裏面,但是,我們也有用,後面說:
      在這裏插入圖片描述

    2. 我們打開在F12的控制檯裏面選Network查看後臺給我們發的數據包,選擇font直接就能看到一堆字體文件(.woff結尾的),然後打開,最下面一行都是數字,但是,有個名字含有truetype的一看就不一樣,果然,裏面的數字順序是打亂的,別的文件數字順序都是1234567890。這裏面肯定存在着什麼貓膩,所以我們根據這個文件名字裏面有true認爲這個順序是正常順序,那麼源碼中的順序數字就按別的文件中的順序轉換,得到下圖中的這個對應關係,紅色數字表示源碼中的數字:
      在這裏插入圖片描述

    3. 我們運用上面的對應看看主頁,按照上圖的規則剛好能得到我們看到的數據,可以看到,對應的上。那麼,再將這個套路運用到別的網頁,我自己看了十幾頁都對的上,我認爲的話應該就是這麼實現的反爬了:
      在這裏插入圖片描述

  • 那麼怎麼用代碼去實現這種反推呢,下面介紹:
    1. 用到python的第三方庫:fontTools,清華鏡像,我安裝的源碼是(你們可能是pip3):
      pip install -i https://tuna.tsinghua.edu.cn/simple fontTools

    2. 請求頁面,獲取字體變換的源數據,這裏我就只獲取了指導價格,裏面用到的scrapy.Selector()對象,和lxml差不多,但是我覺得會好一點,這段就是爲了獲取到指導價格那串迷惑文字:

      	# get response
          detail_url = 'https://house.leju.com/dl149612/'
          resp = requests.get(detail_url)
          
          # get  guide price
          from scrapy import Selector
          html = Selector(text=resp.text)
          guide_price = html.xpath("normalize-space(//span[@class='t_l'])").extract_first()
          print(guide_price)  # result: 指導價格: 約52777-59777 元/㎡
      
    3. 利用fontTools對字體文件進行解析,這裏我們不需要獲取字體文件,因爲,樂居將字體文件的base64編碼的數據直接放在網頁源碼裏面了,就是我剛開始說的new_font,這裏還有個原因就是字體文件其實應用的是哪一個是不固定的,在下面你們會看到,字體文件變了三四次,所以,我不推薦大家直接將字體文件下載下來就不變了,另外,多請求一次浪費資源:
      在這裏插入圖片描述
      所以,我們就不用再請求一次字體文件了,這裏直接利用python的字符串切割獲得,獲取的是base64字符串,直接編碼爲字節流,爲了之後用:

      	# get font_file_bytes by split html source
          b64_str = resp.text.split("src: url(data:font/truetype;charset=utf-8;base64,")[1].split(") format('woff');")[0]
          font_file_io = base64.b64decode(b64_str)
          print(type(font_file_io))  # result: <class 'bytes'>
      
    4. 利用fonttools獲取字體文件,同時保存轉換的字體文件關係:

      	# parse font file by fontTools.TTFont
          from fontTools.ttLib import TTFont
          font = TTFont(io.BytesIO(font_file_io))  # this param also can be a path txt
          font.saveXML('leju.xml')  # save the conversion map to the path you want
      

      正常情況下,我們需要找GlyphOrder和cmap這兩種對應xml的,我也想解釋下對應關係的,但是,好像,他們的coder直接給我們打了註釋了,打開這個xml文件,第一個cmap有後臺程序員對我們深深的愛意:
      在這裏插入圖片描述

    5. 在字體文件中獲取剛剛看到的第一個對應關係(cmap):

      	# get base conversion map
          font_map = font['cmap'].getBestCmap()
          print(type(font_map))  # result: <class 'dict'>
      

      在這裏插入圖片描述

    6. 在cmap中獲取英文數字列表,同時構造真實對應關係字典,就是將正常順序的數字做鍵,上面的那個英文數字列表轉成阿拉伯數字後做值,組裝成一個字典:

      	# get conversion dict: key: html source num, value: true num
          base_eng_list = {'zero': '0', 'one': '1', 'two': '2', 'three': '3', 'four': '4', 'five': '5',
                           'six': '6', 'seven': '7', 'eight': '8', 'nine': '9'}
          mapping_list = [base_eng_list[_] for _ in list(font_map.values())[:10]]
          base_num_list = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
          font_dict = dict(zip(base_num_list, mapping_list))
      
    7. 利用映射字典轉換網頁源碼中的數字:

      	# use the map dict converter the html source txt
          true_guide_price = ''.join([_ if not _.isdigit() else font_dict[_] for _ in guide_price])
          font.close()
      
          print(true_guide_price)  # 指導價格: 約15000-16000 元/㎡
      

      最後,也希望大家的技術水平蒸蒸日上,如果喜歡,不妨關注啥的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章