全國(guó)41611個(gè)景點(diǎn),用Python告訴你哪些地方更值得一游!
經(jīng)常聽(tīng)到別人說(shuō)“世界那么大,我想去看看”。在有機(jī)會(huì)走出***之前,還是先把祖國(guó)走一圈吧。都知道中國(guó)地廣人不稀,旅游資源非常豐富,古文化遺址、抗戰(zhàn)遺址、山川、河流等等,在選擇目的地的時(shí)候,不少人都會(huì)非常糾結(jié),不知道去哪更好。為了以后不再糾結(jié),筆者打算深度解析全國(guó)的旅游景點(diǎn)分布。
以下進(jìn)入正題。
01、數(shù)據(jù)抓取
去哪兒網(wǎng)有著非常豐富的旅游信息,不但幾乎涵蓋了全國(guó)所有景點(diǎn),而且使用去哪兒網(wǎng)購(gòu)買景區(qū)門票的人也非常多,所以筆者將爬取去哪兒網(wǎng)全國(guó) 32 個(gè)省市的所有景點(diǎn)數(shù)據(jù)。(沒(méi)有抓取香港和澳門的數(shù)據(jù),這邊的景點(diǎn)并沒(méi)有分 ***、4A)
去哪兒網(wǎng)的門票服務(wù)中暫時(shí)還沒(méi)有開(kāi)通 API 服務(wù),所以只能對(duì)網(wǎng)頁(yè)解析爬取。要抓取的數(shù)據(jù)有:景點(diǎn)名、景區(qū)等級(jí)、地點(diǎn)、景區(qū)簡(jiǎn)述、價(jià)格、銷量以及熱度。
將需要的數(shù)據(jù)進(jìn)行定位,一層一層解析,就可以把所需的全部?jī)?nèi)容抓取下來(lái)了。但并不是每一個(gè)景點(diǎn)的信息都是全的,所以筆者加了一個(gè) try/except 進(jìn)去,雖然代碼有變長(zhǎng),但是整個(gè)程序變得更加健壯。最終,一共抓取了 41611 條景點(diǎn)信息。
for i in s:
inf = {}
try:
inf['level'] = i.find('span', class_='level').text[0]
except Exception as e:
inf['level'] = '0'
try:
inf['price'] = i.find('span', class_='sight_item_price').find('em').text
except Exception as e:
inf['price'] = ''
try:
inf['name'] = i.find('a', class_='name').text
except Exception as e:
inf['name'] = ''
try:
inf['num'] = i.find('span', class_='hot_num').text
except Exception as e:
inf['num'] = ''
try:
inf['add_pro'] = i.find('span', class_='area').find('a').text.split('·')[0]
inf['add_city'] = i.find('span', class_='area').find('a').text.split('·')[1]
except Exception as e:
inf['add_pro'] = i.find('span', class_='area').find('a').text
inf['add_city'] = i.find('span', class_='area').find('a').text
try:
inf['hot'] = i.find('span', class_='product_star_level').find('em').get('title').split(':')[1]
except Exception as e:
inf['hot'] = ''
try:
inf['descri'] = i.find('div', class_='intro color999').text
except Exception as e:
inf['descri'] = ''
02、數(shù)據(jù)分析
*** 級(jí)景區(qū)
上圖為 *** 景區(qū)的銷量排行,可以看出秦始皇兵馬俑***,是第二名長(zhǎng)隆歡樂(lè)世界的 5/3 倍。讓筆者沒(méi)有想到的是歡樂(lè)谷游樂(lè)園等在前二十名中占了六個(gè)席位,所以對(duì)于那些想發(fā)展旅游業(yè)但是沒(méi)有美麗風(fēng)景或者歷史古跡的城市而言,大力發(fā)展游樂(lè)園行業(yè)是一個(gè)不錯(cuò)的選擇。廣州長(zhǎng)隆就是一個(gè)鮮活的例子。
江蘇省是全國(guó) *** 級(jí)景區(qū)最多的一個(gè)省,有 41 個(gè)之多;其次是浙江省和廣東省有 21 個(gè)。總體而言,東部地區(qū)的 *** 景區(qū)數(shù)量是遠(yuǎn)高于西部的,雖然西部的美景非常多,但是整體經(jīng)濟(jì)不行,對(duì)景區(qū)的開(kāi)發(fā)力度不夠,拉了不少后退。
如果大家想去人少景美的地方,可以參考上圖。比如武漢的東湖磨山、紅旗渠、野三坡等等(其實(shí)筆者都沒(méi)有聽(tīng)過(guò)。)雖然它們的銷量低,但好歹也是 AAAAA 級(jí)風(fēng)景區(qū)。
def huati(name,num,k):
kk=[]
for i in range(len(name)):
if not numpy.isnan(num[i]):
q = []
q.append(name[i])
q.append(num[i])
kk.append(q)
hh=sorted(kk,key=lambda i:i[1],reverse=True)
page=Page()
att,val=[],[]
for i in hh[:20]:
att.append(i[0])
val.append(i[1])
bar1 = Bar("", k+"A景區(qū)銷量排行", title_pos="center", width=1200, height=600)
bar1.add("",att,val, is_visualmap=True, visual_text_color='#fff', mark_point=["average"],
mark_line=["average"],
is_more_utils=True, is_label_show=True, is_datazoom_show=True, xaxis_rotate=45)
page.add_chart(bar1)
att, val = [], []
for i in hh[-20:]:
att.append(i[0])
val.append(i[1])
bar2 = Bar("", k+"A景區(qū)銷量排行", title_pos="center", width=1200, height=600)
bar2.add("", att, val, is_visualmap=True, visual_text_color='#fff', mark_point=["average"],
mark_line=["average"],
is_more_utils=True, is_label_show=True, is_datazoom_show=True, xaxis_rotate=45)
page.add_chart(bar2)
page.render(k+"A景區(qū)銷量bar.html")
def sum_pro(pro,k):#每個(gè)省有多少個(gè)景點(diǎn)
p=[]
c=[]
for i in set(pro):
'''
q={}
q[i]=pro.count(i)
p.append(q)'''
p.append(i)
c.append(pro.count(i))
map= Map('各省'+k+'A景點(diǎn)分布', width=1200, height=600)
map.add("", p,c, is_visualmap=True, visual_range=[min(c), max(c)],
visual_text_color='#000', is_map_symbol_show=True, is_label_show=True)
map.render( '各省'+k+'A景點(diǎn)分布.html')
4A 景區(qū)
在 4A 景區(qū)里,成都熊貓基地的銷量是***的,大熊貓最為國(guó)寶,這吸引力真是杠杠的。和 *** 景區(qū)一樣,歡樂(lè)谷游樂(lè)園等占了四成,我想這也是南京雖然是六朝古都,又是中華民國(guó)的首都,可是景區(qū)無(wú)論銷量還是人氣都不高的原因吧,希望在南京可以多造幾個(gè)大型游樂(lè)園!
在上圖中可以看到山東省是 4A 景區(qū)最多的省,有 167 個(gè)之多。而浙江省、江蘇省、廣東省、河北省、四川省、安徽省的 4A 景區(qū)數(shù)量均超過(guò)了 100。4A 景區(qū)最少的省是西藏,只有 6 個(gè)。
3A 景區(qū)
3A 景區(qū)銷量***的是竹林長(zhǎng)壽山景區(qū),但也只有 1326,在 4A 景區(qū)的中上游。
山東省的 3A 景區(qū)數(shù)量***,高達(dá) 211 個(gè),而河南省、安徽省、遼寧省、黑龍江省、新疆省 3A 景區(qū)均在 100 個(gè)以上。
綜合對(duì)比
從各等級(jí)景區(qū)人氣值可以看出,人氣值為 1 的 *** 景區(qū)占了將近三成,而 4A 和 3A 景區(qū)連一成都沒(méi)有;相反,人氣值為 0 的 3A 景區(qū)差不多有六成,看來(lái)這個(gè) 3A 景區(qū)不是一點(diǎn)點(diǎn)水呢?*** 景區(qū)也并非每一個(gè)都稱得上 *** 這個(gè)名號(hào),不然也不會(huì)有近兩成人氣值為 0。
def hottt(fivhot,fouhot,thrhot):
fiv, fou, th = [], [], []
atts = ['0', '0.7', '0.8', '0.9', '1']
for i in zip(fivhot,fouhot,thrhot):
fiv.append(round(i[0], 1))
fou.append(round(i[1], 1))
th.append(round(i[2], 1))
levels = ['***', '4A', '3A']
data = {}
data['att'] = atts
data['***'], data['4A'], data['3A'] = [], [], []
for i in range(len(atts)):
data['***'].append(round(fiv.count(float(atts[i])) / len(fiv) * 100, 3))
data['4A'].append(round(fou.count(float(atts[i])) / len(fou) * 100, 3))
data['3A'].append(round(th.count(float(atts[i])) / len(th) * 100, 3))
print(data)
output_file("bars.html") # 輸出文件名
x = [(att, level) for att in atts for level in levels]
counts = sum(zip(data['***'], data['4A'], data['3A']), ())
source = ColumnDataSource(data=dict(x=x, counts=counts))
p = figure(x_range=FactorRange(*x), plot_height=250, title="各等級(jí)景區(qū)人氣值占比",
toolbar_location=None, tools="")
p.vbar(x='x', top='counts', width=0.9, source=source)
show(p)
從各級(jí)景點(diǎn)的箱型圖可以看出,*** 景區(qū)人氣值是***的,整體在 0.7 以上。4A 景區(qū)人氣均值中位數(shù)在 0.7 左右,不過(guò)高于 0.7 的景區(qū)實(shí)在太少了。3A 景區(qū)就更不用說(shuō),整體人氣值非常低。
從景區(qū)銷量箱型圖可以看到:*** 景區(qū)的銷量是遠(yuǎn)超過(guò)了 4A 和 3A 景區(qū),*** 景區(qū)的 3/4 分為點(diǎn)達(dá)到了 400,而 4A 景區(qū)的僅為 82;而 4A 景區(qū)的箱型圖和 3A 的非常類似;看來(lái)大家對(duì) 4A 景區(qū)和對(duì) 3A 景區(qū)興趣都一致的不大。
def box(q,w,e,l):
a = go.Box(y=q, name='***景區(qū)')
b = go.Box(y=w, name='4A景區(qū)')
c = go.Box(y=e, name='3A景區(qū)')
g = go.Box(y=l, name='所有景區(qū)')
data = [a, b, c,g]
layout = go.Layout(legend=dict(font=dict(size=16)), orientation=270)
fig = go.Figure(data=data, layout=layout)
plotly.offline.plot(data)
將所有景點(diǎn)的概述用 R 生成了一個(gè)詞云圖:位于,文化,休閑,旅游,體驗(yàn),景區(qū),公園,歷史,娛樂(lè)等等這些詞是不是很熟悉呢。看來(lái)商家對(duì)景區(qū)的概括都差不多。
對(duì)比完各級(jí)景點(diǎn),下面來(lái)給各位看官排排雷。
上圖是 4A 級(jí)景區(qū)銷量排名的*** 20 位,全中國(guó)有 2193 個(gè) 4A 級(jí)景區(qū),這 20 個(gè)還排在***,在對(duì)比一下大家對(duì) 4A 級(jí)景區(qū)的人氣評(píng)分,想想還是不要去了。
首先,如果說(shuō) 3A 級(jí)景區(qū)不太推薦大家去游玩,因?yàn)槿藲庵祵?shí)在低的可怕;那上面列出的這 20 個(gè)景點(diǎn)那就是完全不建議游玩了。全國(guó)一共 1933 個(gè) AAA 級(jí)景區(qū),這 20 個(gè)排在***,可想而知去了會(huì)多么震驚了。
高德地圖可視化
高德地圖的 API 真的非常好,它提供各種和地圖有關(guān)的功能。其中有一項(xiàng)是 WEB 服務(wù)里的地理/逆地理編碼。將去哪兒爬取到的景點(diǎn)地址數(shù)據(jù)通過(guò)地理編碼轉(zhuǎn)變?yōu)閷?duì)應(yīng)的經(jīng)緯度。比如:北京市方恒國(guó)際中心 A 座將它經(jīng)過(guò)地理編碼后其經(jīng)緯度為 116.480656,39.989677。它的 URL:
其中 output 是輸出個(gè)格式,一共有兩種,XML 和 JSON;address 是要地理編碼的地址,city 是所在的城市。
Word is cheap,show me the code!
def trans(city,name,pro,level):
for i in range(len(name)):
x = pandas.DataFrame()
t={}
add = name[i]
chengshi=city[i]
parameters = { 'address': add, 'key': '','city':chengshi }
html = requests.get('https://restapi.amap.com/v3/geocode/geo',
params=parameters).json()
try:
t['jingwei'] = html['geocodes'][0]['location']
except IndexError:
t['jingwei']='0,0'
finally:
t['n'] = name[i]
t['level']=level[i]
t['pro']=pro[i]
t['city']=city[i]
x = x.append(t, ignore_index=True)
x.to_csv('55543.csv', encoding='utf-8', index=False, mode='a', header=False)
全國(guó)各級(jí)景區(qū)分布圖
全國(guó)各級(jí)景區(qū)分布六邊形熱力圖
在六邊形熱力圖中可以看到,北京是一個(gè)旅游資源及其豐富的城市,如果大家只想去一個(gè)城市轉(zhuǎn)一轉(zhuǎn),可以優(yōu)先選擇北京。重慶、廣州、天津、蘇州等也是不錯(cuò)的選擇。
全國(guó)景區(qū)分布熱力圖
筆者做了一個(gè)全國(guó)旅游景點(diǎn)分布軌跡的動(dòng)畫,鏈接如下:
- lbs.amap.com/dev/mapdata/share/7b986430c10e197fcb5babbddd510c67
***來(lái)看看筆者的家鄉(xiāng),湖南。如果大家去湖南游玩的話,長(zhǎng)沙一定要去!其次張家界、永州、懷化和郴州也值得一去。
相關(guān)代碼和數(shù)據(jù)已經(jīng)上傳到GitHub: