爬取去哪兒網 6000 多個景點資料告訴你,國慶哪裡不是人山人海!
國慶長假已經過去一半啦,朋友們有多少是堵在了景區和路上?
為了方便大家的出遊選擇,筆者爬取了去哪兒網上面的 6000 多個景點資料,包含景點評級、熱度、銷量等等資料,彙總成這篇出遊參考指南。
爬蟲
爬蟲繼續用的是最近的心頭愛 Selenium,開啟去哪兒網站,右鍵,分析網頁。
我們需要的資料非常地清晰:
話不多說,只要定位到自己想要的資訊,那麼程式碼非常簡單。
from tqdm import tqdm
import time
from selenium import webdriver
from selenium.common.exceptions import TimeoutException, WebDriverException
import pandas as pd
import numpy as np
position = ["北京","天津","上海","重慶","河北","山西","遼寧","吉林","黑龍江","江蘇","浙江","安徽","福建","江西","山東","河南","湖北","湖南","廣東","海南","四川","貴州","雲南","陝西","甘肅","青海","臺灣","內蒙古","廣西","西藏","寧夏","新疆","香港","澳門"]
name,level,hot,address,num=[],[],[],[],[]
def get_one_page(key,page):
try:
#開啟瀏覽器視窗
option_chrome = webdriver.ChromeOptions()
option_chrome.add_argument('--headless')
driver = webdriver.Chrome(chrome_options=option_chrome)
time.sleep(1)
url = "http://piao.qunar.com/ticket/list.htm?keyword="+str(key)+"®ion=&from=mpl_search_suggest&page=" +str(page)
driver.get(url)
infor = driver.find_elements_by_class_name("sight_item")
for i in range(len(infor)):
#獲取景點名字
name.append(infor[i].find_element_by_class_name("name").text)
#獲取景點評級
try:
level.append(infor[i].find_element_by_class_name("level").text)
except:
level.append("")
#獲取景點熱度
hot.append(infor[i].find_element_by_class_name("product_star_level").text[3:])
#獲取景點地址
address.append(infor[i].find_element_by_class_name("area").text)
#獲取景點銷量
try:
num.append(infor[i].find_element_by_class_name("hot_num").text)
except:
num.append(0)
driver.quit()
return
except TimeoutException or WebDriverException:
return get_one_page()
for key in tqdm(position):
print ("正在爬取{}".format(key))
#取前10頁
for page in range(1,14):
print ("正在爬取第{}頁".format(page))
get_one_page(key,page)
sight = {'name': name, 'level': level, 'hot': hot, 'address': address, 'num':num}
sight = pd.DataFrame(sight, columns=['name', 'level', 'hot', 'address', 'num'])
sight.to_csv("sight.csv",encoding="utf_8_sig")
本文僅爬取國內的資料,由於景點資料眾多,每個省份僅取了前 13 頁。獲得景點個數 6630 個。
資料視覺化
熱門景區 TOP30:
大熊貓不愧為國寶,最熱門就是它。其次是故宮、鄭州動物園、峨眉山、秦始皇兵馬俑等等。因為筆者沒有去過多少地方玩,也不知道為什麼鄭州動物園能排到第三,大家知道的可以分享一下它的特色嗎?
省份與評級:
說實話,這個圖的配色真的是太醜了,主要是筆者過於懶惰,不想好好配色了。
熱力圖:
熱力圖根據省份和城市分別作圖,其次在根據銷量和熱度兩類圖,這裡採用的是 Python 呼叫高德地圖 API 實現經緯度換算、地圖視覺化一文的方式,呼叫高德地圖 API 完成。
首先是省份和景區熱度:
然後是省份和銷量:
接下來是城市和景區熱度:
最後是城市和景區銷量:
值得注意的是,城市和銷量一圖熱力範圍不明顯,原因為景區之間銷量天差地別,一些太少的統計下來,作圖非常的不明顯了。若大家不喜歡用高德地圖 API 作圖,那麼人生苦短,我要用 pyecharts 畫圖的方法也非常適合做熱力圖,比如這裡筆者做了一張省份和銷量的圖:
綜合來看,北京、四川及沿海地區都是旅遊的熱門省份。建議大家儘量避免去這些省份遊玩。
推薦景區:
知道了需要避免的景區和省份城市,那麼可以去哪些人少的地方呢?這裡筆者根據景區分級,分別推薦 15 個人少的景區:
最後兩張圖是根據熱度做的圖,沒有條形的則是熱度為 0,那麼大家可以選擇上述景點中熱度較高的進行遊玩。
視覺化程式碼:
data = pd.read_csv("sight.csv")
data = data.fillna(0)
data = data.drop(columns=['Unnamed: 0'])
#將地址分為省,市,區
data["address"] = data["address"].apply(lambda x: x.replace("[","").replace("]",""))
data["province"] = data["address"].apply(lambda x: x.split("·")[0])
data["city"] = data["address"].apply(lambda x: x.split("·")[1])
data["area"] = data["address"].apply(lambda x: x.split("·")[-1])
#銷量最多的前30景點
num_top = data.sort_values(by = 'num',axis = 0,ascending = False).reset_index(drop=True)
import seaborn as sns
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']#指定預設字型
plt.rcParams['axes.unicode_minus'] =False # 解決儲存影象是負號'-'顯示為方塊的問題
sns.set(font='SimHei') # 解決Seaborn中文顯示問題
sns.set_context("talk")
fig = plt.figure(figsize=(15,10))
sns.barplot(num_top["name"][:30],num_top["num"][:30])
plt.xticks(rotation=90)
fig.show()
#省份與景區評級
data["level_sum"] =1
var = data.groupby(['province', 'level']).level_sum.sum()
var.unstack().plot(kind='bar',figsize=(35,10), stacked=False, color=['red', 'blue','green','yellow'])
#根據省、市統計銷量和
pro_num = data.groupby(['province']).agg('sum').reset_index()
city_num = data.groupby(['city']).agg('sum').reset_index()
#基於資料做熱力圖
import requests
def transform(geo):
key = 'bb9a4fae3390081abfcb10bc7ed307a6'
url="http://restapi.amap.com/v3/geocode/geo?key=" +str(key) +"&address=" + str(geo)
response = requests.get(url)
if response.status_code == 200:
answer = response.json()
try:
loc = answer['geocodes'][0]['location']
except:
loc = 0
return loc
pro_num["lati"] = pro_num["province"].apply(lambda x: transform(x))
city_num["lati"] = city_num["city"].apply(lambda x: transform(x))
pro_num.to_csv("pro_num.csv",encoding="utf_8_sig")
city_num.to_csv("city_num.csv",encoding="utf_8_sig")
from pyecharts import Map
map=Map("省份景點銷量熱力圖", title_color="#fff", title_pos="center", width=1200, height=600, background_color='#404a59')
map.add("",pro_num["province"], pro_num["num"], maptype="china", visual_range=[5000, 80000], is_visualmap=True, visual_text_color='#000', is_label_show=True)
map.render(path="pro_num.html")
map=Map("省份景點熱度熱力圖", title_color="#fff", title_pos="center", width=1200, height=600, background_color='#404a59')
map.add("",pro_num["province"], pro_num["hot"], maptype="china", visual_range=[25,80], is_visualmap=True, visual_text_color='#000', is_label_show=True)
map.render(path="pro_hot.html")
#人少的5A景點,4A景點,3A景點
top_5A = data[data["level"] == "5A景區"].sort_values(by = 'num',axis = 0,ascending = True).reset_index(drop=True)
top_4A = data[data["level"] == "4A景區"].sort_values(by = 'num',axis = 0,ascending = True).reset_index(drop=True)
top_3A = data[data["level"] == "3A景區"].sort_values(by = 'num',axis = 0,ascending = True).reset_index(drop=True)
fig = plt.figure(figsize=(15,15))
plt.pie(top_5A["num"][:15],labels=top_5A["name"][:15],autopct='%1.2f%%')
plt.title("人少的5A景區")
plt.show()
fig = plt.figure(figsize=(15,15))
ax = sns.barplot(top_4A["hot"][:15],top_4A["name"][:15])
ax.set_title("人少的4A景區")
fig.show()
fig = plt.figure(figsize=(15,10))
ax = sns.barplot(top_3A["name"][:15],top_3A["hot"][:15])
ax.set_title("人少的3A景區")
plt.xticks(rotation=90)
fig.show()
結語
爬蟲採集於 2018.9.27,可能因為採集時間不同,結果會有偏差。需要注意的是,若採用 pyecharts 做城市和景區熱度、銷量的圖時,需要考慮 pyecharts 無法獲得一些景區位置,解決辦法可以參考《狄仁傑之四大天王》影評分析(爬蟲+詞雲+熱力圖)一文。
分析完了之後,筆者反正決定國慶節都呆在家裡了,不想出門,只想當快樂的肥宅。最後,祝大家國慶快樂,珍惜剩下不多的假期!!!
本文為經管人學資料分析(ID:DAT-2017)投稿,作者:胡蘿蔔醬。