起點中文網,在“數字”上設置了文字反爬,使用了自定義的文字文件ttf
通過瀏覽器的“檢查”顯示的是“□”,但是可以在網頁源代碼中找到映射后的數字
正則爬的是網頁源代碼,xpath是默認utf-8解析網頁數據,用xpath爬出來的也是方框,因此只能使用正則匹配爬取關鍵數字信息
本例以小說《斗羅大陸》為例 https://book.qidian.com/info/1115277,爬取閱讀量等數字信息
爬取思路:
1. 使用正則匹配爬取出網頁源代碼中的被設置反爬的數字信息(這里只能使用正則匹配)
2. 尋找數字的映射關系
2.1 爬取出網頁中的字體文件地址,並下載這個文件
2.2 使用軟件FontCreator(請度娘自行下載)打開文件,可以看到英文和數字的對應關系,寫入字典
在本例中是按照習慣對應的(有可能有的文件自定義是打亂的)
#在fontcreator中查看此ttf文件中英文單詞與阿拉伯數字的映射關系,寫入字典 python_font_relation = { 'one':1, 'two':2, 'three':3, 'four':4, 'five':5, 'six':6, 'seven':7, 'eight':8, 'nine':9, 'zero':0, 'period':'.' }
2.3 在python中安裝fontTools包,網頁源代碼中的數字與英文單詞的對應關系
def get_font(url): """ 獲取源代碼中數字信息與英文單詞之間的映射關系 :param url: <str> 網頁源代碼中的字體地址 :return: <dict> 網頁字體映射關系 """ time.sleep(1) response = requests.get(url) font = TTFont(BytesIO(response.content)) web_font_relation = font.getBestCmap() font.close() return web_font_relation
結果是:
3. 通過2.2與2.3 可以看出來解碼需要兩步:
第一步:將正則匹配出來的6位數字先轉換成英文單詞
第二步:將英文單詞轉換成阿拉伯數字
然后就ok啦
源代碼:
1. 正則匹配沒有展開講,自行度娘吧
2. 有一些簡單的數據處理工作,細心點一步一步來,實在不行就每次都輸出看一下
1 """ 2 起點中文網,在“數字”上設置了文字反爬,使用了自定義的文字文件ttf 3 瀏覽器渲染不出來,但是可以在網頁源代碼中找到映射后的數字 4 正則爬的是網頁源代碼 xpath是默認utf-8解析網頁數據;網頁源代碼有數據,使用瀏覽器"檢查"是方框,用xpath爬出來的也是方框 5 以小說《斗羅大陸》為例 https://book.qidian.com/info/1115277 6 """ 7 import requests, time, re, pprint 8 from fontTools.ttLib import TTFont 9 from io import BytesIO 10 from lxml import etree 11 12 #此代碼使用bs和xpath均無法爬出,需使用正則匹配 13 #selector = etree.HTML(html_data.text) 14 #word1 = selector.xpath('//div[2]/div[6]/div[1]/div[2]/p[3]/em[1]/span/text()') 15 16 def get_font(url): 17 """ 18 獲取源代碼中數字信息與英文單詞之間的映射關系 19 :param url: <str> 網頁源代碼中的字體地址 20 :return: <dict> 網頁字體映射關系 21 """ 22 time.sleep(1) 23 response = requests.get(url) 24 font = TTFont(BytesIO(response.content)) 25 web_font_relation = font.getBestCmap() 26 font.close() 27 return web_font_relation 28 29 30 #在fontcreator中查看此ttf文件中英文單詞與阿拉伯數字的映射關系,寫入字典 31 python_font_relation = { 32 'one':1, 33 'two':2, 34 'three':3, 35 'four':4, 36 'five':5, 37 'six':6, 38 'seven':7, 39 'eight':8, 40 'nine':9, 41 'zero':0, 42 'period':'.' 43 } 44 45 def get_html_info(url): 46 """ 47 解析網頁,獲取文字文件的地址和需要解碼的數字信息 48 :param url: <str> 需要解析的網頁地址 49 :return: <str> 文字文件ttf的地址 50 <list> 反爬的數字,一維列表 51 """ 52 headers = { 53 'User-Agent': 'User-Agent:Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36' 54 } 55 html_data = requests.get(url, headers=headers) 56 # 獲取網頁的文字ttf文件的地址 57 url_ttf_pattern = re.compile('<style>(.*?)\s*</style>',re.S) 58 fonturl = re.findall(url_ttf_pattern,html_data.text)[0] 59 url_ttf = re.search('woff.*?url.*?\'(.+?)\'.*?truetype', fonturl).group(1) 60 61 # 獲取所有反爬的數字 62 word_pattern = re.compile('</style><span.*?>(.*?)</span>', re.S)#制定正則匹配規則,匹配所有<span>標簽中的內容 63 numberlist = re.findall(word_pattern, html_data.text) 64 65 return url_ttf,numberlist 66 67 68 def get_encode_font(numberlist): 69 """ 70 把源代碼中的數字信息進行2次解碼 71 :param numberlist: <list> 需要解碼的一維數字信息 72 :return: 73 """ 74 data = [] 75 for i in numberlist: 76 fanpa_data = '' 77 index_i = numberlist.index(i) 78 words = i.split(';') 79 #print('words:',words) 80 for k in range(0,len(words)-1): 81 words[k] = words[k].strip('&#') 82 #print(words[k]) 83 words[k] = str(python_font_relation[web_font_relation[int(words[k])]]) 84 #print(words[k]) 85 fanpa_data += words[k] 86 #print(fanpa_data) 87 data.append(fanpa_data) 88 print(data[0],'萬字') 89 print(data[1], '萬閱文總點擊') 90 print(data[2], '萬會員周點擊') 91 print(data[3], '萬總推薦') 92 print(data[4], '萬周推薦') 93 # return data 94 95 """程序主入口""" 96 if __name__=='__main__': 97 url = 'https://book.qidian.com/info/1115277' # 選取某一小說 98 get_html_info(url) 99 web_font_relation = get_font(get_html_info(url)[0]) 100 pprint.pprint(web_font_relation)#格式化打印網頁文字映射關系 101 get_encode_font(get_html_info(url)[1])