【Python3爬蟲】大眾點評爬蟲
本次爬蟲的爬取目標是大眾點評上的一些店鋪的店鋪名稱、推薦菜和評分資訊。
一、頁面分析
進入大眾點評,然後選擇美食(http://www.dianping.com/wuhan/ch10),可以看到一頁有15家店鋪,而除了店鋪的名稱,還能看到店鋪的地址、推薦菜、評分等資訊,看起來都沒什麼問題。
開啟開發者工具,然後選擇檢視一下評分,就發現事情沒那麼簡單了(如下圖)。這些評分的數字去哪兒了呢?
其實這些數字是SVG向量圖,SVG向量圖是基於可擴充套件標記語言,用於描述二維向量圖形的一種圖形格式,通過使用不同的偏移量就能顯示不同的字元,這樣就能很巧妙地隱藏資訊了,如果我們用xpath去解析網頁得到的就是一個個""。這次爬蟲的難點就在於如何得到這些評分的資訊,既然我們能夠知道它是怎麼反爬的,那我們是不是就能想辦法實現反反爬呢?先說下破解思路吧:首先要解析網頁,找到這個網頁使用的SVG向量圖,拿到這個向量圖後,如果我們能得到每個數字對應的偏移量,那就能將這些偏移量轉化成圖片中的數字了。
二、破解步驟
首先檢視網頁原始碼,既然使用的是SVG向量圖,那我們搜尋一下svg會不會有驚喜呢?果然有驚喜:
把這個連結複製一下,然後開啟這個連結,會看到有很多的class名稱和background,這麼多的資料,怎麼知道有沒有我們想要的東西呢?這時候搜尋一下unbq2:
可以看到unbq2這個class對應的background為(-199.0px,-109.0px),但是我們還是沒有辦法得到具體的數字啊,怎麼辦呢?
我們再搜尋一下svg會有什麼結果呢?這一步會得到幾個以.svg結尾的連結,將這些連結提取出來:
span[class^="ma"]{background-image: url(//s3plus.meituan.net/v1/mss_0a06a471f9514fc79c981b5466f56b91/svgtextcss/9e045e6574fb7ae10b5aae4ae4a0c444.svg);span[class^="yj"]{background-image: url(//s3plus.meituan.net/v1/mss_0a06a471f9514fc79c981b5466f56b91/svgtextcss/39510b070120e6a5b7c8754ab729ee2e.svg);
span[class^="dz"]{background-image: url(//s3plus.meituan.net/v1/mss_0a06a471f9514fc79c981b5466f56b91/svgtextcss/8eecf780b3c9ecefd5ad508502dd80a5.svg);
span[class^="un"]{background-image: url(//s3plus.meituan.net/v1/mss_0a06a471f9514fc79c981b5466f56b91/svgtextcss/39ecd4a57969825db02c38a01f4f34c6.svg);
可以看到以"un"開頭的class使用的背景圖片的連結就是//s3plus.meituan.net/v1/mss_0a06a471f9514fc79c981b5466f56b91/svgtextcss/39ecd4a57969825db02c38a01f4f34c6.svg
這就是我們要找的SVG向量圖了,現在的問題就在於如何將偏移量轉化成對應的數字呢?首先把這些數字提取出來:
99851465728255648017534661485297040380627087820023
03763928255311814779807306445209731282368541175419
06266544999197136339
然後開啟開發者工具,可以發現每個數字都有對應著一組x和y的值:
在前面的分析中我們知道數字6對應的偏移量是(-199.0px,-109.0px),然後我們也可以分析一下別的數字對應的偏移量,然後通過這些分析可以知道y方向上的偏移量只是為了確定這個class對應的數字在哪一行,而x方向的偏移量需要進行一下處理,具體方法為:
(x方向上的偏移量+7)/(-12)
比如(-199+7)/(-12)=16,這個16就表示對應的數字索引為16(第一個數字索引為0),然後y方向的偏移量對應的行數為3,最後從上面的數字中尋找第3行第17個數字--正好為6,也就是說unbq2這個class對應的數字就是6,這樣我們就已經成功實現了反反爬。
三、爬取步驟
由於大眾點評會對我們的UserAgent和Cookie進行檢查,所以在爬取的時候要帶上Cookie,而且如果一直用一個UserAgent也會被識別出來,所以得采用不同的UserAgent。這裡我要分析一個第三方模組:fake_useragent,沒有安裝這個模組的可以使用pip命令進行安裝。我們通過使用這個模組就能得到隨機的UserAgent了,使用方法如下:
1 from fake_useragent import UserAgent
2
3 ua = UserAgent()
4 for i in range(3):
5 print(ua.random)
執行結果如下:
店鋪名稱和推薦菜的爬取相對簡單,這裡就不贅述了,主要說一下如何爬取店鋪的評分資訊。
在我們得到網頁的原始碼之後,需要先把css檔案的url提取出來:
# 提取css檔案的url
css_url = "http:" + re.search('(//.+svgtextcss.+\.css)', html).group()
然後將以"un"開頭的class名稱和對應的偏移量全部提取出來,以供後面使用:
css_res = requests.get(css_url)
# 這一步得到的列表內容為css中class的名字及其對應的偏移量
css_list = re.findall('(un\w+){background:(.+)px (.+)px;', '\n'.join(css_res.text.split('}')))
這裡還要對得到的資料進行一下處理,因為y方向上的偏移量並不參與計算,最終得到的y_dict中的鍵是y方向上的偏移量,值是y方向上的偏移量對應的行數:
# 過濾掉匹配錯誤的內容,並對y方向上的偏移量初步處理
css_list = [[i[0], i[1], abs(float(i[2]))] for i in css_list if len(i[0]) == 5]
# y_list表示在y方向上的偏移量,完成排序和去重
y_list = [i[2] for i in css_list]
y_list = sorted(list(set(y_list)))
# 生成一個字典
y_dict = {y_list[i]: i for i in range(len(y_list))}
然後我們要提取以”un“開頭的class所對應svg圖片的url,並訪問這個url,將圖片中的數字都提取出來:
# 提取svg圖片的url
svg_url = "http:" + re.findall('class\^="un".+(//.+svgtextcss.+\.svg)', '\n'.join(css_res.text.split('}')))[0]
svg_res = requests.get(svg_url)
# 得到svg圖片中的所有數字
digits_list = re.findall('>(\d+)<', svg_res.text)
進行到這一步,我們就已經得到了所有以un開頭的class對應的偏移量和所有的數字了,然後我們就可以利用前面的計算方法將這些偏移量轉變成對應的數字了,也就能得到每個店鋪的評分資訊了。
最終執行結果如下:
完整程式碼已上傳到GitHub:https://github.com/QAQ112233/DianPing