一.問題
可以看到,貓眼網電影評分,票房等的數據在響應的html中并不是直接提供給你的。這里的xefcf,xef87等數據,是以‘特殊符號’的形式顯示出來的。
可以發現這里請求了一個woff字體文件,而xefcf,xef87等數據的規則就是在這其中的。所以我們只需要在請求這個網頁的同時,截去這部分style,然后獲得woff地址,將它下載到本地,進行解析,就可以實現對評分的解密了。
但是再來看下面,當同一部電影的頁面刷新時。
這里的評分編碼改變了,下面請求的woff的url也改變了。所以每次請求電影頁面使用的woff都不是同一個。
在這種情況下,如何才可以實現評分的爬取呢?
二.分步實現
1.頁面爬取
第一步我們需要先將整個html頁面獲取,其中重要的數據就是評分所在的那個span,還有woff的url所在的那個style.
這里使用requests獲取網頁內容,用BeautifulSoup進行關鍵內容解析.
'''
遇到不懂的問題?Python學習交流群:821460695滿足你的需求,資料都已經上傳群文件,可以自行下載!
'''
# 請求頭設置
header = {
'Accept': '*/*;',
'Connection': 'keep-alive',
'Accept-Language': 'zh-CN,zh;q=0.9',
'Accept-Encoding': 'gzip, deflate, br',
'Host': 'maoyan.com',
'Referer': 'http://maoyan.com/',
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36'
}
def web(url):
db_data = requests.get(url, headers=header)
# 這里直接將其編碼之前部分替換掉,防止之后使用轉義
soup = BeautifulSoup(db_data.text.replace("&#x",""), 'lxml')
titles = soup.select(
'body > div.banner > div > div.celeInfo-right.clearfix > div.movie-stats-container > div > div > span > span')
wotfs = soup.select('head > style')
wotflist = str(wotfs[0]).split('\n')
maoyanwotf就是當前頁面所使用的woff地址了。
= wotflist[5].replace(' ','').replace('url(\'//','').replace('format(\'woff\');','').replace('\')','')
此時titles就是一個獲取了評分span的list,當然它只有一個元素。
maoyanwotf就是當前頁面所使用的woff地址了。
2.woff下載
上一步我們得到了maoyanwotf,其中是當前頁面所使用的woff地址,所以接下來就要對這個url進行下載,保存到本地。
# 下載請求電影頁面的woff字體到本地
def downfont(maoyanwotf):
r = requests.get('http://'+maoyanwotf)
with open("demo.woff", "wb") as code:
code.write(r.content)
font = TTFont("demo.woff")
font.saveXML('to.xml')
這樣就下載到了這次請求頁面所用的woff了,保存為demo.woff。
3.字體解析規則
那么這個to.xml有什么用呢?
這就是我們在每次刷新都會改變woff的情況下,實現爬取的關鍵所在了。
font.saveXML(‘to.xml’)就是將TTFont打開的woff轉換為xml的形式,在xml中我們可以直接找到字體的相關數據,比如一個字符的筆畫信息等。
來看一個字體xml文件的重要內容。完整內容參考:to.xml
....
...
...
...
...
GlyphOrder 這個標簽中就是這個字體xml包含的字符種類了,glyph00000和x這兩個不用考慮。
glyf 這個標簽中是這些字體的具體坐標畫法,一個TTGlyph對應一個字體,而其中contour標簽的坐標數據,就是唯一確定這個字體是什么的最好的確定方法。
所以可以得出結論,不管每次請求的woff怎么變,它里面的字符的contour標簽內的坐標畫法是不會改變的。
既然如此,我們只需要一個模板,在這個模板中,我們先手動解碼一個充當模板的woff。
如何制作這樣一個模板呢?
我們先來找一個woff和woff生成的xml,woff可以用字體查看器High-Logic FontCreator打開。效果如下。
之后我們將模板xml里面的glyf中TTGlyph標簽的name屬性與打開的woff對應比較,得到這個數值列表(我這里woff和xml用的不是同一個,所以不要用這個比較!!!)
之后我們就可以根據glyf中TTGlyph的順序得到解碼數值的順序,之所以要一一對應,是為了方便之后用下標索引。
num = [8,6,2,1,4,3,0,9,5,7] #這個值是直接硬編碼進去的。
data = []
# 此處以解析xml的方式得到這個模板xml里面contour標簽的內容。
xmlfilepath_temp = os.path.abspath("temp.xml")
domobj_temp = xmldom.parse(xmlfilepath_temp)
elementobj_temp = domobj_temp.documentElement
subElementObj = elementobj_temp.getElementsByTagName("TTGlyph")
for i in range(len(subElementObj)):
rereobj = re.compile(r"name=\"(.*)\"")
find_list = rereobj.findall(str(subElementObj[i].toprettyxml()))
data.append(str(subElementObj[i].toprettyxml()).replace(find_list[0],'').replace("\n",''))
最后data里面是glyf中TTGlyph按順序的內容,其中當然就是contour了,而它的下表與num中一一對應,也就是說,這時候給你一個contour的坐標內容,那就可以在data中查找它的對應下標,根據這個下標找到num中下標的元素,這個元素就是解碼后的值了!!!
‘
獲得了模板,我們接下來就可以將請求這次頁面時獲得的woff轉化為xml進行對應了。
font = TTFont("demo.woff")
font.saveXML('to.xml')
#本次請求下載的字體的contour
new_font = []
xmlfilepath_find = os.path.abspath("to.xml")
domobj_find = xmldom.parse(xmlfilepath_find)
elementobj_find = domobj_find.documentElement
tunicode = elementobj_find.getElementsByTagName("TTGlyph")
for i in range(len(tunicode)):
th = tunicode[i].toprettyxml()
report = re.compile(r"name=\"(.*)\"")
find_this = report.findall(th)
get_code = th.replace(find_this[0], '').replace("\n", '')
for j in range(len(data)):
if not cmp(get_code,data[j]):
new_font.append(num[j])
其中get_code就是這次頁面時獲得的字體數據的list元素之一了,通過循環遍歷,最終得到了一個本次xml的對應數字的list : new_font 。
接下來獲得一個編碼與具體數字對應的font_list
font = TTFont("demo.woff")
font_list = font.getGlyphNames()
font_list.remove('glyph00000')
font_list.remove('x')
此時,有了new_font中的具體數字和font_list中的編碼值就可以完全解碼這個頁面中因為woff編碼反爬蟲的評分了。
# 匹配
star_woff = re.findall(re.compile(r">(.*)<"), str(titles[0]))[0].replace(';','').split('.') ;titles[0]是在第一步網頁解析時獲得的評分所在span
for i in star_woff:
getthis = i.upper()
for j in range(len(font_list)):
if not cmp(getthis,font_list[j].replace("uni","")):
print(new_font[j])
這樣就會輸出評分的整數部分和小數部分了。雖然這里只是輸出了這兩個數字,但是反爬蟲評分,票房,人數等數據均可以使用前一步的new_font和font_list進行處理,就不再加以闡述了。
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
