一、頁面分析
首先打開貓眼電影,然后點擊一個正在熱播的電影(比如:毒液)。打開開發者工具,點擊左上角的箭頭,然后用鼠標點擊網頁上的票價,可以看到源碼中顯示的不是數字,而是某些根本看不懂的字符,這是因為使用了font-face定義字符集,並通過unicode去映射展示,所以我們在網頁上看到的是數字,但是在源碼中看到的卻是別的字符。
碰到這些根本看不懂的字符怎么辦呢?不慌,右鍵選擇查看網頁源代碼,然后找到相應的位置(如下圖)。那么是不是“”映射出來就是28呢?
通過查看源碼,可以找到如下內容, 而當我們訪問這里面的鏈接的時候,就可以下載相應的字體文件,關於font-face可以點擊這里查看了解:
當我下載好字體文件后,滿心歡喜的雙擊想要點開的時候,卻發現無法打開(T_T)。查閱資料之后知道了一個叫做FontCreator的軟件,用這個軟件可以打開我們下載的字體文件,沒有安裝這個軟件的可以進入官網https://www.high-logic.com/下載安裝,如果下載得很慢的可以用百度雲下載(鏈接:https://pan.baidu.com/s/1ImxwPhKdzZo2g4bIjiGCZw ,提取碼:m0yf )。下載好之后打開軟件,看到如下界面,選擇Use Evaluation Version,這個軟件我們可以免費使用三十天。
打開軟件后,再打開我們下載的字體文件,可以看到數字2和8分別對應的是uniE83B和uniE375,和前面看到的編碼是一致的。
那么我們下載好字符集之后,只要將其中的字符編碼和數字對應的信息提取出來,再把網頁源碼中的字符編碼替換掉,就能得到我們想要的數據了。這里要用到一個三方庫fontTools,利用fontTools可以獲取每一個字符對象,這個對象你可以簡單的理解為保存着這個字符的形狀信息,而且編碼可以作為這個對象的id,具有一一對應的關系。不過這里還有一個問題,就是網頁每次使用的字符集是隨機變化的,我們也就無法使用一個固定的字符集去做到反爬。
解決思路如下:先保存一個字體文件(比如base.woff),然后解析其數字和編碼的對應關系,然后爬取的時候把新的字體文件下載下來(比如online.woff),網頁中的一個數字的編碼(比如ABCD),我們先通過編碼ABCD找到這個字符在online.woff中的對象,並且把它和base.woff中的對象逐個對比,直到找到相同的對象,然后獲取這個對象在base.woff中的編碼,再通過編碼確認是哪個數字。
二、主要代碼
解析下載的字體文件,由於字體文件中有多余的字符,需要舍棄掉。
1 # 解析字體庫 2 def parse_ttf(font_name): 3 """ 4 :param font_name: 字體文件名 5 :return: 字符-數字字典 6 """ 7 base_nums = ['3', '0', '1', '6', '4', '2', '5', '8', '9', '7'] 8 base_fonts = ['uniEB84', 'uniF8CA', 'uniEB66', 'uniE9DB', 'uniE03C', 9 'uniF778', 'uniE590', 'uniED12', 'uniEA5E', 'uniE172'] 10 font1 = TTFont('base.woff') # 本地保存的字體文件 11 font2 = TTFont(font_name) # 網上下載的字體文件 12 13 uni_list = font2.getGlyphNames()[1:-1] # 去掉頭尾的多余字符 14 temp = {} 15 # 解析字體庫 16 for i in range(10): 17 uni2 = font2['glyf'][uni_list[i]] 18 for j in range(10): 19 uni1 = font1['glyf'][base_fonts[j]] 20 if uni2 == uni1: 21 temp["&#x" + uni_list[i][3:].lower() + ";"] = base_nums[j] 22 return temp
解析網頁源碼,把其中的編碼替換成數字,這里選擇把網頁源碼保存下來,這樣的話編碼就不會改變,也就能正確的解析。
1 # 解析網頁得到數字信息 2 def get_nums(font_dict): 3 """ 4 :param font_dict: 字符-數字字典 5 :return: 由評分、評分人數、票房和票價組成的列表 6 """ 7 num_list = [] 8 with open('html', 'r', encoding='utf-8') as f: 9 for line in f.readlines(): 10 lst = re.findall('(&#x.*?)<', line) 11 if lst: 12 num = lst[0] 13 for i in font_dict.keys(): 14 if i in num: 15 num = num.replace(i, font_dict[i]) 16 num_list.append(num) 17 return num_list
三、運行結果
完整代碼已上傳到GitHub!