1. 程式人生 > >爬蟲文字的顯示問題(反 反爬蟲)

爬蟲文字的顯示問題(反 反爬蟲)

轉自litang199612https://blog.csdn.net/litang199612/article/details/83413002

爬蟲遇到的問題

最近在用爬蟲程式爬一些網站的時候發現爬到的資料出現亂碼,不能正常顯示:在這裡插入圖片描述
如上圖我們可以發現有些資料的數字變成了加密字型,我就去查看了一下網站的程式碼,結果發現網站的程式碼顯示是這樣的:
在這裡插入圖片描述
原來有些網站上使用了字型加密技術,為了解決這個問題,我找了大量的資料,可是網上的很多方法由於網站反爬技術的進步或者網站更新了字型加密規則已經不能使用了,於是我就開始了破解字型加密的艱辛歷程。

解決方法

方法一:

程式碼如下:

from selenium import webdriver
from selenium.webdriver.firefox.options import Options
import pytesseract
from PIL import Image
from fontTools.ttLib import TTFont

def font_parse(url, font_str1, font_str2, font_str3):
“”"
解析亂碼的數字
:param rental:
:param house_type:
:param toward_floor:
:return:
“”"


response = requests.get(url)
base64_string = response.text.split(“base64,”)[1].split("’")[0].strip()
bin_data = base64.decodebytes(base64_string.encode())
with open(“base.woff”, r"wb") as f:
f.write(bin_data)
html = ‘’’<!DOCTYPE html>
<html lang=“en”>
<head>
<meta charset=“UTF-8”>
<title>Title</title>
<style type=“text/css”>
@font-face {
font-family: myFirstFont;
src: url(base64.woff);
}

        div {
            font-family: myFirstFont;
            font-size: 32px;
            text-align: center;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;div&gt;%s&lt;/div&gt;
    &lt;div&gt;%s&lt;/div&gt;
    &lt;div&gt;%s&lt;/div&gt;
&lt;/body&gt;
&lt;/html&gt;
        '''</span> <span class="token operator">%</span> <span class="token punctuation">(</span>font_str1<span class="token punctuation">,</span> font_str2<span class="token punctuation">,</span> font_str3<span class="token punctuation">)</span>

<span class="token comment"># 將生成的HTML字串寫入html檔案中</span>
<span class="token keyword">with</span> <span class="token builtin">open</span><span class="token punctuation">(</span><span class="token string">"font_parse.html"</span><span class="token punctuation">,</span> r<span class="token string">"wb"</span><span class="token punctuation">)</span> <span class="token keyword">as</span> f<span class="token punctuation">:</span>
    f<span class="token punctuation">.</span>write<span class="token punctuation">(</span><span class="token builtin">bytes</span><span class="token punctuation">(</span>html<span class="token punctuation">,</span> encoding<span class="token operator">=</span><span class="token string">"utf-8"</span><span class="token punctuation">)</span><span class="token punctuation">)</span>

<span class="token comment"># 使用selenium在瀏覽器中載入html檔案</span>
options <span class="token operator">=</span> Options<span class="token punctuation">(</span><span class="token punctuation">)</span>
options<span class="token punctuation">.</span>add_argument<span class="token punctuation">(</span><span class="token string">"-headless"</span><span class="token punctuation">)</span>
browser <span class="token operator">=</span> webdriver<span class="token punctuation">.</span>Firefox<span class="token punctuation">(</span>executable_path<span class="token operator">=</span><span class="token string">"E:/python/geckodriver"</span><span class="token punctuation">,</span> firefox_options<span class="token operator">=</span>options<span class="token punctuation">)</span>
browser<span class="token punctuation">.</span>get<span class="token punctuation">(</span>r<span class="token string">"file:///E:\python\practice\practice06\font_parse\font_parse.html"</span><span class="token punctuation">)</span>
<span class="token comment"># 最大化視窗,因為每一次爬取只能看到視窗內的圖片</span>
browser<span class="token punctuation">.</span>maximize_window<span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token comment"># 將網頁儲存為圖片格式</span>
browser<span class="token punctuation">.</span>save_screenshot<span class="token punctuation">(</span><span class="token string">"font_parse.png"</span><span class="token punctuation">)</span>
browser<span class="token punctuation">.</span>close<span class="token punctuation">(</span><span class="token punctuation">)</span>

image <span class="token operator">=</span> Image<span class="token punctuation">.</span><span class="token builtin">open</span><span class="token punctuation">(</span><span class="token string">'font_parse.png'</span><span class="token punctuation">)</span>
<span class="token comment"># 利用tesseract-OCR識別庫識別圖片中的文字,chi_sim是簡體中文語言庫</span>
result <span class="token operator">=</span> pytesseract<span class="token punctuation">.</span>image_to_string<span class="token punctuation">(</span>image<span class="token punctuation">,</span> lang<span class="token operator">=</span><span class="token string">"chi_sim"</span><span class="token punctuation">)</span>
result_list <span class="token operator">=</span> result<span class="token punctuation">.</span>splitlines<span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token keyword">return</span> result_list
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66

1.url是你要爬取網站的網址,font_str是需要解析的加密字元,可以根據需求定義font_str(1, 2, …n)的個數,在html字串裡面修改div的個數並在‘%()’裡面寫入對應的引數
2.executable_path=“E:/python/geckodriver"裡面的路徑換成自己電腦上‘geckodriver’所在的位置
3.browser.get(r"file:///E:\python\practice\practice06\font_parse\font_parse.html”)裡面的路徑換成html檔案儲存的路徑
4.tesseract識別英文和數字比較簡單,識別中文需要下載中文語言庫,放在“Tesseract-OCR\tessdata”資料夾裡面。有一點需要說明一下:tesseract對於單個字元的識別不太好,我試了幾次識別單個數字字元發現識別的結果為空,大家使用tesseract時儘量避免這個問題

這個方法可以解決目前大部分網站的字型加密,不過這個方法比較麻煩,而且使用selenium模擬開啟瀏覽器會造成程式執行速度非常慢,爬取得資料較少時可以使用,當爬取大量資料時這個方法就不太實用了,於是就有了下面的進階方法。

方法二:

程式碼如下:

text = "鑶驋龒龒"
im = Image.new("RGB", (60, 25), (255, 255, 255))
dr = ImageDraw.Draw(im)
font = ImageFont.truetype('base.woff', 18)
dr.text((10, 5), text, font=font, fill="#000000")
#im.show()
im.save("t.png")

  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

利用此程式碼替換方法一程式碼中selenium模擬開啟網頁並儲存網頁為圖片的部分,可以節約大量的程式碼執行所需的時間

方法三:

import base64
from fontTools.ttLib import TTFont
import re
from PIL import Image, ImageDraw, ImageFont

html = open(“test.html”, ‘r’, encoding=“utf-8”).read()
base64_string = html.split(“base64,”)[1].split("’")[0]
bin_data = base64.decodebytes(base64_string.encode())
with open(“base.woff”, r"wb") as f:
f.write(bin_data)

font_list = re.findall(’&#x(\w+)’, html)
for font_secret in font_list:
one_font = int(font_secret, 16)
font = TTFont(‘base.woff’)
# font.saveXML(‘test.xml’)
c = font[‘cmap’].tables[2].ttFont.tables[‘cmap’].tables[1].cmap
# print(“c::::::”, c)
gly_font = c[one_font]
b = font[‘cmap’].tables[2].ttFont.getReverseGlyphMap()
# print(“b:::::::”, b)
print(b[gly_font] - 1)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

1.提取加密字型的十六進位制格式除了可以使用正則直接提取出來,有些也可以把加密的字型用“unicode_escape”編碼格式解析一下生成字型對應的十六進位制,但是不同網站的編碼格式可能不同,需要大家自己驗證。
2.最後一行的程式碼對(從“b”字典裡取出對應的數字字元再減一)是我根據58網站上的資訊與解析之後的資訊進行比對後發現的規則,我並不確定其他網站是不是也是這樣。
3.這個方法是別人告訴我的,程式碼比較簡單,但是原理比較複雜,我對於這個程式碼的執行原理也不是太瞭解,不過並不影響使用。我驗證了一下這個程式碼,也成功解決了文字加密問題,大家有興趣的可以去深入瞭解一下。

關於b和c列印之後是結果如下圖:
在這裡插入圖片描述
大家最好能夠自己列印看一下。生成的xml檔案這裡不太好貼上,大家也最好能夠生成之後看一下,加深對程式碼的理解。

利用“unicode_escape”編碼格式解析的程式碼如下:

from fontTools.ttLib import TTFont

def font_parse(text):
“”"
解析亂碼的數字
:param rental:
:param house_type:
:param toward_floor:
:return:
“”"

decryption_text = “”
for alpha in text:
hex_alpha = alpha.encode(‘unicode_escape’).decode()[2:]
if len(hex_alpha) == 4:
one_font = int(hex_alpha, 16)
font = TTFont(‘base.woff’)
font_dict = font[‘cmap’].tables[2].ttFont.tables[‘cmap’].tables[1].cmap
b = font[‘cmap’].tables[2].ttFont.getReverseGlyphMap()
if one_font in font_dict.keys():
gly_font = font_dict[one_font]
item_text = str(b[gly_font] - 1)
else:
item_text = alpha

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

在這裡插入圖片描述
上圖是測試加密字型解析之後的結果。

方法四:

response = requests.get(url)
base64_string = response.text.split("base64,")[1].split("'")[0].strip()
bin_data = base64.decodebytes(base64_string.encode())
with open("base.woff", r"wb") as f:
    f.write(bin_data)

  
  
  • 1
  • 2
  • 3
  • 4
  • 5

這個程式碼在前面幾個方法中都會用到,用於生成網站上的加密字型所用的字型庫

下載FontCreator軟體,開啟生成的"base.woff"字型庫,軟體會自動生成字型庫的對應關係,如下圖:
在這裡插入圖片描述
在這裡插入圖片描述
根據此軟體解析出來的字型庫對應關係,可以建立一個字型查詢字典,如:{“9f92”: “0”, “EC3A”: “上”, …},然後根據“方法三”介紹的利用正則或者“unicode_escape”編碼格式解析將加密字型轉換為十六進位制格式並利用此十六進位制數字在字型查詢字典裡面查詢加密字型對應的真實字型。

這個方法很簡單,但是字型查詢字典需要手動建立而不能自動生成,如果爬取的網站的字型對應關係不變的話可以使用。然而對於如58同城之類的網站每次重新整理之後網頁的字型對應關係都會變化,這個方法就不適用了。

結尾:

以上就是我解決網站字型加密的方法,至於如何把這些方法應用到爬蟲程式裡面,相信大家只要好好研究一下,應該都是沒有問題的,我就不再贅述了。大神們如果有其他解決方法可以在評論裡留言,最好能夠在評論裡留下連結,希望能和大家一起進步。

        </div>
					<link href="https://csdnimg.cn/release/phoenix/mdeditor/markdown_views-7f770a53f2.css" rel="stylesheet">
            </div>

爬蟲遇到的問題

最近在用爬蟲程式爬一些網站的時候發現爬到的資料出現亂碼,不能正常顯示:在這裡插入圖片描述
如上圖我們可以發現有些資料的數字變成了加密字型,我就去查看了一下網站的程式碼,結果發現網站的程式碼顯示是這樣的:
在這裡插入圖片描述
原來有些網站上使用了字型加密技術,為了解決這個問題,我找了大量的資料,可是網上的很多方法由於網站反爬技術的進步或者網站更新了字型加密規則已經不能使用了,於是我就開始了破解字型加密的艱辛歷程。

解決方法

方法一:

程式碼如下:

from selenium import webdriver
from selenium.webdriver.firefox.options import Options
import pytesseract
from PIL import Image
from fontTools.ttLib import TTFont