2021年國慶你的朋友去哪浪了?讓Python告訴你!

Python小二發表於2021-10-06

國慶假期已經過半,你是出去浪了?還是在家裡宅著呢?那你知道你的朋友去哪浪了嗎?本文我們通過爬取去哪網售票資料(piao.qunar.com)來簡單分析一下。

資料爬取

首選,我們開啟網址:piao.qunar.com,在搜尋框輸入一個省級行政區劃進行搜尋,以浙江為例,如圖所示:

再將頁面向下拉,F12 開啟開發者工具,點選下一頁看一下 URL,如圖所示:

通過觀察 URL 我們可以看出 keywordpage 是動態的,一個是輸入條件值,另一個是頁碼值,當我們需要翻頁爬取時可以進行動態賦值,再將開發者工具切到 Response,我們可以發現返回的資料是 JSON 格式的,如圖所示:

這裡我們以 34 個省級行政區劃作為 keyword 進行分頁爬取,主要爬取程式碼實現如下:

def get_city_data(cities, pages):
    cityNames = []
    sightNames = []
    stars = []
    scores = []
    qunarPrices = []
    saleCounts = []
    districtses = []
    points = []
    intros = []
    frees = []
    addresses = []
    for city in cities:
        for page in range(1, pages+1):
            try:
                print(f'正在爬取{city}第{page}頁資料...')
                time.sleep(random.uniform(1.5, 2.5))
                url = f'https://piao.qunar.com/ticket/list.json?from=mpl_search_suggest&keyword={city}&page={page}'
                print('url:', url)
                result = requests.get(url, headers=headers, timeout=(2.5, 5.5))
                status = result.status_code
                if(status == 200):
                    # 每頁資料
                    response_info = json.loads(result.text)
                    print('資料:', response_info)
                    sight_list = response_info['data']['sightList']
                    for sight in sight_list:
                        sightName = sight['sightName']  # 名稱
                        star = sight.get('star', None)  # 星級
                        score = sight.get('score', 0)  # 評分
                        qunarPrice = sight.get('qunarPrice', 0)  # 價格
                        saleCount = sight.get('saleCount', 0)  # 銷量
                        districts = sight.get('districts', None)  # 行政區劃
                        point = sight.get('point', None)  # 座標
                        intro = sight.get('intro', None)  # 簡介
                        free = sight.get('free', True)  # 是否免費
                        address = sight.get('address', None)  # 地址
                        cityNames.append(city)
                        sightNames.append(sightName)
                        stars.append(star)
                        scores.append(score)
                        qunarPrices.append(qunarPrice)
                        saleCounts.append(saleCount)
                        districtses.append(districts)
                        points.append(point)
                        intros.append(intro)
                        frees.append(free)
                        addresses.append(address)
            except:
                continue
    city_dic = {'cityName': cityNames, 'sightName': sightNames, 'star': stars,
               'score': scores, 'qunarPrice': qunarPrices, 'saleCount': saleCounts,
                'districts': districtses, 'point': points, 'intro': intros,
                'free': frees, 'address': addresses}
    city_df = pd.DataFrame(city_dic)
    city_df.to_csv('cities.csv', index=False)

資料分析

現在資料有了,我們再來簡單分析一下。

位置分佈

首選,我們來看一下景區的位置分佈情況。

先看一下景區的整體分佈情況,主要程式碼實現如下:

for city in df[(df.iloc[:, 5] > 0)].iloc[:, 0]:
    if city != "":
        cities.append(city)
data = Counter(cities).most_common(100)
gx = []
gy = []
for c in data:
    gx.append(c[0])
    gy.append(c[1])
(
    Map(init_opts=opts.InitOpts(theme=ThemeType.MACARONS, height="500px"))
    .add('數量', [list(z) for z in zip(gx, gy)], 'china')
    .set_global_opts(
    title_opts=opts.TitleOpts(title='各地景區數量分佈'),
    visualmap_opts=opts.VisualMapOpts(max_=150, is_piecewise=True),
    )
).render_notebook()

看一下效果:

再看一下各地景區的銷量情況,主要程式碼實現如下:

df_item = df[['cityName','saleCount']]
df_sum = df_item.groupby('cityName').sum()
(
    Map(init_opts=opts.InitOpts(theme=ThemeType.ROMANTIC, height="500px"))
    .add('銷量', [list(z) for z in zip(df_sum.index.values.tolist(), df_sum.values.tolist())], 'china')
    .set_global_opts(
    title_opts=opts.TitleOpts(title='各地景區銷量分佈'),
    visualmap_opts=opts.VisualMapOpts(max_=150000, is_piecewise=True)
    )
).render_notebook()

看一下效果:

最熱景區

我們接著看 TOP10 熱門景區有哪些?它們的價格又是多少呢?主要程式碼實現如下:

sort_sale = df.sort_values(by='saleCount', ascending=True)
(
    Bar(init_opts=opts.InitOpts(theme=ThemeType.MACARONS, width='125%'))
    .add_xaxis(list(sort_sale['sightName'])[-10:])
    .add_yaxis('銷量', sort_sale['saleCount'].values.tolist()[-10:])
    .add_yaxis('價格', sort_sale['qunarPrice'].values.tolist()[-10:])
    .reversal_axis()
    .set_global_opts(
        title_opts=opts.TitleOpts(title='最熱景區TOP10'),
        yaxis_opts=opts.AxisOpts(name='名稱', axislabel_opts=opts.LabelOpts(rotate=-30)),
        xaxis_opts=opts.AxisOpts(name='銷量/價格'),
        )
    .set_series_opts(label_opts=opts.LabelOpts(position="right"))
).render_notebook()

看一下效果:

從圖中我們可以看出 TOP10 熱門景區的價格大多數都在 500 以內,算是比較親民了。如果你的朋友喜歡熱鬧,他(她)可能去了熱門景區。

再接著看熱門景區的介紹情況,這裡我們選取 T100 資料,通過詞雲來看一下。主要實現程式碼如下:

sort_sale = df.sort_values(by='saleCount', ascending=True)
stylecloud.gen_stylecloud(text=cts_str, max_words=100,
                          collocations=False,
                          font_path="SIMLI.TTF",
                          icon_name="fab fa-firefox",
                          size=800,
                          output_name="hot.png")

看一下效果:

最豪景區

我們再看一下票價 TOP10 景區有哪些?它們的銷量怎麼樣呢?主要程式碼實現如下:

sort_price = df.sort_values(by='qunarPrice', ascending=True)
(
    Bar(init_opts=opts.InitOpts(theme=ThemeType.ROMA))
    .add_xaxis(list(sort_price['sightName'])[-10:])
    .add_yaxis('價格', sort_price['qunarPrice'].values.tolist()[-10:])
    .add_yaxis('銷量', sort_price['saleCount'].values.tolist()[-10:])
    .reversal_axis()
    .set_global_opts(
        title_opts=opts.TitleOpts(title='最豪景區TOP10'),
        yaxis_opts=opts.AxisOpts(name='名稱'),
        xaxis_opts=opts.AxisOpts(name='價格/銷量'),
        )
    .set_series_opts(label_opts=opts.LabelOpts(position="right"))
).render_notebook()

看一下效果:

如果你的朋友是一個熱愛旅遊的土豪,他(她)很有可能去了土豪景區了。

再接著看一下土豪景區的介紹情況,這裡我們還是選取 T100 資料,通過詞雲來看一下。

主要程式碼實現如下:

sort_price = df.sort_values(by='qunarPrice', ascending=True)
stylecloud.gen_stylecloud(text=cts_str, max_words=100,
                          collocations=False,
                          font_path="SIMLI.TTF",
                          icon_name="fas fa-yen-sign",#最豪
                          size=800,
                          output_name="money.png")

看一下效果:

景區星級

我們再來看一下各省級行政區劃的 5A 級景區數量情況,主要程式碼實現如下:

df_sum = df[df['star']=='5A'].groupby('cityName').count()['star']
(
    Bar(init_opts=opts.InitOpts(theme=ThemeType.MACARONS))
        .add_xaxis(df_sum.index.values.tolist())
        .add_yaxis('數量', df_sum.values.tolist())
        .set_global_opts(
        title_opts=opts.TitleOpts(title='各地5A景區數量'),
        datazoom_opts=[opts.DataZoomOpts(), opts.DataZoomOpts(type_='inside')],
    )
).render_notebook()

看一下效果:

如果你的朋友熱愛旅遊且對 5A 級景區情有獨鍾,他(她)可能去了 5A 景區的城市了。

最後,我們看一下 T200 熱門景區的星級比例情況是怎樣的?主要程式碼實現如下:

sort_data = df.sort_values(by=['saleCount'], ascending=True)
rates = list(sort_data['star'])[-200:]
gx = ["3A", "4A", "5A"]
gy = [
    rates.count("3A"),
    rates.count("4A"),
    rates.count("5A")
]
(
    Pie(init_opts=opts.InitOpts(theme=ThemeType.MACARONS))
    .add("", list(zip(gx, gy)), radius=["40%", "70%"])
    .set_global_opts(title_opts=opts.TitleOpts(title="銷量TOP200景區星級比例", pos_left = "left"))
    .set_series_opts(label_opts=opts.LabelOpts(formatter="{b}:{d}%", font_size=12))
).render_notebook()

看一下效果:

從圖中我們可以看出 90% 以上的景區均為 4/5A 級。

好了,本文就到這裡了,文中我們對去哪網售票資料中的幾個指標進行了簡單的分析,可以做個簡單的參考,當然了,如果你感興趣的話,還可以繼續對其他指標進行分析。

原始碼在公眾號Python小二後臺回覆qunar獲取。

相關文章