文的文字及圖片來源於網絡,僅供學習、交流使用,不具有任何商業用途,版權歸原作者所有,如有問題請及時聯系我們以作處理。
作者: 胡蘿卜醬
PS:如有需要Python學習資料的小伙伴可以加點擊下方鏈接自行獲取
http://note.youdao.com/noteshare?id=3054cce4add8a909e784ad934f956cef
爬蟲
首先筆者定位為成都,美食類型選的“火鍋”,火鍋具體類型選的不限,區域選的不限,排序選的智能,如圖:
你也可以選擇別的選項,只是注意URL的變化。本文都是按照上述選項爬取的數據。接下來翻頁觀察一下URL的變化:
第二頁:
第三頁:
很容易觀察出翻頁變化的知識p后面的數字,倒推回第一頁,發現一樣的顯示內容,因此,寫一個循環,便可以爬取全部頁面。
但是大眾點評只提供了前50頁的數據,所以,我們也只能爬取前50頁。
這一次,筆者用的pyquery來分析網頁的,所以我們需要定位到我們所爬取的數據的位置,如圖:
在具體分析的網頁的時候,我震驚了,大眾點評的反爬做的太過分了,它的數字,一些文字居然都不是明文顯示,而是代碼,你還不知道怎么分析它。如圖:
很煩的,一些文字又可以顯示,一些又用代碼表示。一些數字也是,不過好一點的是數字只有9個,只要稍微觀察一下,就能發現數字的代碼是什么了。這里筆者列出來了。 {'hs-OEEp': 0, 'hs-4Enz': 2, 'hs-GOYR': 3, 'hs-61V1': 4, 'hs-SzzZ': 5, 'hs-VYVW': 6, 'hs-tQlR': 7, 'hs-LNui': 8, 'hs-42CK': 9}。值得注意的是,數字1,是用明文表示的。
那么,如何用pyquery來定位呢,很簡單,你找到你要獲取的數據,然后右鍵→copy→cut selector,你復制到代碼里面就OK了。pyquery的具體用法百度既有。
最后,我們獲取了火鍋50個頁面的數據,每頁15個數據,一共750家餐廳的數據。
分析
大眾點評已經給出了星級評價,可以看看大致趨勢。
准五星商戶最多,可能因為大部分食客都習慣給好評,只有實在不滿時才會打出低評有關,造成了評級一般不低,但近滿分還是蠻少的。
在本文,我們假設評論數目為飯店的熱度,也就是它越火,評論數目越多。
評論數目大多在1000以內,但是高於2000,甚至高於4000也還存在一些,這些飯店應該是一些網紅店。以5000為約束,篩選出飯店均為小龍坎、蜀大俠都非常知名的火鍋店。那么評論數量和星級有關系嗎?看下圖:
這里取其評論數平均值,發現對於四星以上商戶來說,評論數和星級並不關系,但均比低於四星的飯店銷量更好。這說明在四星以上之后,人們選擇差別不大,但一般不願意接受評論太差的飯店。
對於筆者這樣的學生黨來說,影響較大還有人均消費情況。
成都的火鍋店人均消費大部分都在50-100的區間內,高於150的也有一些。對於筆者來講,吃一頓火鍋,人均在50-100是可以接受的,高於100,就要低頭看看錢包了()。那擴展看,人均消費和星級、評論數量有關系嗎?
上圖是人均消費和星級的關系,看起來並無任何關系,那說明一些口碑好的火鍋店,其實人均也不貴。下面看看人均和評論數目的關系吧。
通過比較,發現評論數目低於500,人均在50-100區間是最多的。當然這肯定和評論數量、人均消費本身集中於這一階段有關。
吃火鍋,一家店的生意好壞,肯定還和它的特色菜有關,筆者通過jieba分詞,將爬取到的推薦菜做了一個詞雲圖,如下。
筆者最愛的牛肉是特色菜之最啊,尤其是麻辣牛肉,只要去吃火鍋,都要來上一份,其次是毛肚、蝦滑、鵝腸等等。
接下來是大家都關心的,口味、環境和服務的情況。
三者得分大多都是集中在8.0-9.2這一階段,筆者認為,低於7.5分的飯店還是不要去嘗試了。同時,星級評價應該也是由這三者得分產生的。
果然如預想的一向,星級評價越好,它在口味、環境和服務的得分越高。那么口味,環境,服務得分與評論數量,平均價格有關系嗎?
如圖所看,並無什么直接關系,但是我們發現口味、環境和服務三者之間存在着非常好的線性關系,於是單獨拿出來畫了一個較大的圖。
我們並且擬合了線性關系,由於三星商戶只有一家,它的情況較為特殊之外,其他星級在口味、環境和服務的關系擬合中保持的相當一致,這也證明我們的猜想,這些變量之間存在線性關系。鑒於筆者本文最大的目的是做推薦,於是,我們進行了K-means聚類,這里取K為3,並且把星級轉換為數字,五星對應5分,准五星對應4.5分,以此類推。最終得到了三類,通過作圖,看看聚類情況如何吧。
和我們想要的結果一致,在口味、環境、服務和星級上得分越高,我們就越推薦。然而推薦的店鋪還是好多,能不能在集中一些呢?於是通過限制評論數量、人均消費和特色菜來進行推薦。由於筆者喜歡人少,便宜還有牛肉的店鋪,這里得到了如下的結果:
1 import time 2 import requests 3 from pyquery import PyQuery as pq 4 import pandas as pd 5 6 headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36'} 7 8 def restaurant(url): 9 # 獲取網頁靜態源代碼 10 try: 11 response = requests.get(url, headers=headers) 12 if response.status_code == 200: 13 return response.text 14 except Exception: 15 return None 16 17 name=[] 18 url = [] 19 star = [] 20 comment = [] 21 avg_price = [] 22 taste = [] 23 environment = [] 24 services = [] 25 recommend = [] 26 27 num = {'hs-OEEp': 0, 'hs-4Enz': 2, 'hs-GOYR': 3, 'hs-61V1': 4, 'hs-SzzZ': 5, 'hs-VYVW': 6, 'hs-tQlR': 7, 'hs-LNui': 8, 'hs-42CK': 9} 28 def detail_number(htm): 29 try: 30 a = str(htm) 31 a = a.replace('1<', '<span class="1"/><') 32 a = a.replace('.', '<span class="."/>') 33 b = pq(a) 34 cn = b('span').items() 35 number = '' 36 for i in cn: 37 attr = i.attr('class') 38 if attr in num: 39 attr = num[attr] 40 number = number + str(attr) 41 number = number.replace('None', '') 42 except: 43 number = '' 44 return number 45 46 def info_restaurant(html): 47 # 獲取飯店的名稱和鏈接 48 doc = pq(html) 49 for i in range(1,16): 50 #獲取飯店名稱 51 shop_name = doc('#shop-all-list > ul > li:nth-child('+str(i)+') > div.txt > div.tit > a:nth-child(1) > h4').text() 52 if shop_name == '': 53 break 54 name.append(shop_name) 55 #獲取飯店鏈接 56 url.append(doc('#shop-all-list > ul > li:nth-child('+str(i)+') > div.pic > a').attr('href')) 57 try: 58 star.append(doc('#shop-all-list > ul > li:nth-child('+str(i)+') > div.txt > div.comment > span').attr('title')) 59 except: 60 star.append("") 61 #獲取評論數量 62 comment_html = doc('#shop-all-list > ul > li:nth-child('+str(i)+') > div.txt > div.comment > a.review-num > b') 63 comment.append(detail_number(comment_html)) 64 #獲取人均消費 65 avg_price_html = doc('#shop-all-list > ul > li:nth-child('+str(i)+') > div.txt > div.comment > a.mean-price > b') 66 avg_price.append(detail_number(avg_price_html)) 67 #獲取口味評分 68 taste_html = doc('#shop-all-list > ul > li:nth-child('+str(i)+') > div.txt > span > span:nth-child(1) > b') 69 taste.append(detail_number(taste_html)) 70 #獲取環境評分 71 environment_html = doc('#shop-all-list > ul > li:nth-child('+str(i)+') > div.txt > span > span:nth-child(2) > b') 72 environment.append(detail_number(environment_html)) 73 #獲取服務評分 74 services_html = doc('#shop-all-list > ul > li:nth-child('+str(i)+') > div.txt > span > span:nth-child(3) > b') 75 services.append(detail_number(services_html)) 76 #推薦菜,都是顯示三道菜 77 try: 78 recommend.append(doc('#shop-all-list > ul > li:nth-child('+str(i)+') > div.txt > div.recommend > a:nth-child(2)').text()+str(',')+\ 79 doc('#shop-all-list > ul > li:nth-child('+str(i)+') > div.txt > div.recommend > a:nth-child(3)').text()+str(',')+\ 80 doc('#shop-all-list > ul > li:nth-child('+str(i)+') > div.txt > div.recommend > a:nth-child(4)').text()) 81 except: 82 recommend.append("") 83 for i in range(1,51): 84 print('正在獲取第{}頁飯店信息'.format(i)) 85 hotpot_url = 'http://www.dianping.com/chengdu/ch10/g110p'+str(i)+'?aid=93195650%2C68215270%2C22353218%2C98432390%2C107724883&cpt=93195650%2C68215270%2C22353218%2C98432390%2C107724883&tc=3' 86 html = restaurant(hotpot_url) 87 info_restaurant(html) 88 print ('第{}頁獲取成功'.format(i)) 89 time.sleep(12) 90 91 shop = {'name': name, 'url': url, 'star': star, 'comment': comment, 'avg_price': avg_price, 'taste': taste, 'environment': environment, 'services': services, 'recommend': recommend} 92 shop = pd.DataFrame(shop, columns=['name', 'url', 'star', 'comment', 'avg_price','taste', 'environment', 'services', 'recommend']) 93 shop.to_csv("shop.csv",encoding="utf_8_sig",index = False)