從現(xiàn)在開始连舍,會(huì)隨機(jī)對(duì)各大網(wǎng)站的一些信息進(jìn)行分析采集
1.目標(biāo)
今天采集大眾點(diǎn)評(píng)碘橘。先從簡單點(diǎn)的開始:采集大眾點(diǎn)評(píng)的美食類商家店鋪信息。其中包括類別驳糯、店名涛漂、圖片赏表、星級(jí)、點(diǎn)評(píng)數(shù)匈仗、人均消費(fèi)瓢剿、口味評(píng)分、環(huán)境評(píng)分悠轩、服務(wù)評(píng)分间狂、地址、推薦菜火架。
2.請求分析
首先先看一下鏈接跟頁面:
http://www.dianping.com/guangzhou/ch10/g103
這里不同的類別下均有很多店鋪鉴象,由于看其他頁信息需登錄忙菠,所以這里我們先采集第一頁。
再看該頁的請求頭信息:
這是一個(gè)
get
請求纺弊,而且沒有傳遞參數(shù),比較簡單到這里基本的請求分析已經(jīng)完成了只搁,下面我們開始采集。
3.采集
首先俭尖,通過請求起始url,我們拿到所有類別的地址
def get_response(self, req_url):
"""
請求
:param req_url:
:return:
"""
response = requests.get(f'{req_url}', headers=self._headers)
if response.status_code == 200:
return response.content.decode('utf-8')
return None
def run(self):
# 1. 獲取所有類別地址
response = self.get_response(self._start_url)
content = etree.HTML(response)
url_list = content.xpath('//div[@id="classfy"]//a/@href')
然后洞翩,通過請求這些地址稽犁,逐個(gè)去解析頁面,在這里問題來了骚亿,我們先看一下其中一個(gè)商家的相關(guān)信息:
從這里已經(jīng)找到了我們所有需要采集的信息了已亥,但是除了
店鋪圖片
、名稱
来屠、星級(jí)
虑椎、推薦菜
之外,其他的信息都是通過不同的符號(hào)來表示的俱笛,沒有顯示出真正的信息出來捆姜。到這里,我們可能就想到了反爬迎膜,其中的主要信息都被加密處理了泥技,那這種是怎樣加密的呢?這里就牽扯到了一種加密方法:CSS字體加密磕仅,先來簡單了解下珊豹。
CSS字體加密
css字體加密是一種自定義字體映射加密,簡單來說就是通過自定義的字體文件來渲染網(wǎng)頁中的文字榕订,網(wǎng)頁上看到的文字店茶,在網(wǎng)頁源碼中不再用文字表示,而是用相應(yīng)的字體編碼來表示劫恒。我們從頁面上復(fù)制也復(fù)制不出來贩幻,以此達(dá)到了反爬的效果。
那這種反爬怎樣去解決呢兼贸,接下來我們通過大眾點(diǎn)評(píng)的小例子來分析一下段直。
首先要解決css字體反爬,要先找到他在哪溶诞,我們來看一下:
通過上面我們可以看出加密的標(biāo)簽
svgmtsi
對(duì)應(yīng)有個(gè)class
屬性鸯檬,點(diǎn)擊這個(gè)標(biāo)簽,可以看到對(duì)應(yīng)的css樣式螺垢,最上面有個(gè)字體類型的屬性也就是font-family
喧务,我們進(jìn)入相應(yīng)的css文件中看到后面有個(gè).woff
的文件url地址赖歌,.woff
后綴的文件就是一種開放字體格式文件,同時(shí)功茴,我們也看到前面有.eot
后綴的文件庐冯,這也是一種字體格式文件,不過他是支持ie的坎穿,我們這里用的google展父,所以使用后面一種。那么玲昧,找到這個(gè)文件后栖茉,我們將它下載下來,同時(shí)用
FontCreator
這個(gè)軟件可以打開此類文件孵延,打開后就是這樣子的吕漂,通過對(duì)比發(fā)現(xiàn),跟網(wǎng)頁上的編碼是對(duì)應(yīng)的尘应。上面初步認(rèn)識(shí)了一下css字體加密惶凝,接下來繼續(xù)我們采集的代碼:
前面我們到了信息提取這一部分,又通過css字體加密的分析犬钢,可以以以下步驟來完成解析(以點(diǎn)評(píng)數(shù)為例,附核心操作代碼):
- 1.找到加密標(biāo)簽對(duì)應(yīng)的css文件苍鲜,文件中找到對(duì)應(yīng)的字體文件,下載
response = self.get_response(url)
content = etree.HTML(response)
# 找到相關(guān)css文件
css_path = content.xpath('//link[contains(@href, "svgtextcss")]/@href')[0]
time.sleep(3)
css_content = self.get_response(f'http:{css_path}')
# 點(diǎn)評(píng)數(shù)
self.parse_review_num(css_content, content.xpath('//a[@class="review-num"]'))
- 2.對(duì)字體文件轉(zhuǎn)換娜饵,這里用到了
fontTools庫
坡贺,可以將.woff
文件中的字體編碼提取出來
# 下載字體文件,如沒有則下載箱舞,已存在則直接解析
if not os.path.exists(woff_path):
# 下載字體文件
response = requests.get(f'http:{woff_url[0]}.woff', headers=self._headers)
with open(woff_path, 'wb') as f:
f.write(response.content)
# 這里轉(zhuǎn)為xml格式是為了前期的分析跟后面的信息提取
time.sleep(2)
# 解析成xml文件
font_content = TTFont(woff_path)
font_content.saveXML(xml_path)
# 獲取字體對(duì)應(yīng)的編碼列表
uni_list = font_content['cmap'].tables[0].ttFont.getGlyphOrder()
uni_list = [uni_code for uni_code in uni_list if uni_code.startswith('uni')]
- 3.將字體文件轉(zhuǎn)換為
xml
文件后遍坟,通過xml
文件跟woff
文件對(duì)部分加密文字跟對(duì)應(yīng)編碼一一映射
# 判斷拿到的編碼在不在字體編碼列表中
if f'uni{str(code_one, encoding="utf-8")[2:]}' in uni_list:
# 如存在,則解析對(duì)應(yīng)的xml文件
DOMTree = parse(xml_path)
rootNode = DOMTree.documentElement
# 找到字體文件的坐標(biāo)標(biāo)簽
contentNodes = rootNode.getElementsByTagName("glyf")[0].getElementsByTagName('TTGlyph')[1:]
- 4.根據(jù)映射關(guān)系將頁面源碼中的編碼替換為相應(yīng)的文字晴股,至此解析完成
看下解析成功后的結(jié)果(內(nèi)容較多愿伴,拿出一條來舉例):
# 解析之前的編碼
[b'\\ue7e9', b'\\uecd9', b'\\uf1eb', b'\\uf350']
# 解析完成之后的真實(shí)數(shù)據(jù)
['2', '5', '6', '3']
最最后,看下存到MongoDB中的結(jié)果
至此电湘,CSS字體文件加密已經(jīng)基本上分析完成隔节,上面紅框的部分信息不全的原因是字體映射我只做了其中一部分,所以有些加密的字體還沒有做映射寂呛,有興趣的可以自己研究一下怎诫。