Fork me on GitHub

长沙欢迎你之美景篇

长沙欢迎你-去哪里玩

长沙,著名的"星城"、“娱乐之都”,湖南省省会,素有“屈贾之乡”、“山水洲城”之名。每年都有很多的游客到长沙旅游,不仅是因为美食多,比如:文和友小龙虾、臭豆腐、糖油粑粑,还因为长沙真的有很多可以游逛的美景。

本文将结合实际的数据来告诉你,如果你想去长沙旅游,你应该去哪里玩。湖南欢迎你,长沙欢迎你👏

系统环境

  • Macos
  • jupyter notebook
  • python3.7.5
  • Pyecharts 1.7.1(这个版本一定要一致)

数据获取

导入库

首先我们需要导入各种库,这些库的主要功能如下

  • 爬虫请求发送及数据解析
  • csv保存爬取到的数据
  • Pandas处理爬取到的数据
  • Jieba中文分词
  • Pyecharts绘图专用库
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import pandas as pd
import re
import csv
import json
import requests
import random

# 显示所有列
# pd.set_option('display.max_columns', None)

# 显示所有行
# pd.set_option('display.max_rows', None)

# 设置value的显示长度为100,默认为50
# pd.set_option('max_colwidth',100)

# 绘图相关
import jieba
import matplotlib.pyplot as plt
from pyecharts.globals import CurrentConfig, OnlineHostType # 事先导入,防止不出图
from pyecharts import options as opts # 配置项
from pyecharts.charts import Bar, Pie, Line, HeatMap, Funnel, WordCloud, Grid, Page # 各个图形的类
from pyecharts.faker import Faker # 自身数据
from pyecharts.commons.utils import JsCode
from pyecharts.globals import ThemeType,SymbolType

爬取信息

先确定我们爬取的字段信息:

  1. 中文名:cn_title
  2. 英文名:en_title
  3. 排名:ranking
  4. 驴友百分比:lvyou
  5. 地点:location
  6. 简介:abstract
  7. 评论数:comment
  8. 攻略数:strategy

网页规律

首先看看网站URL的规律:

1
2
3
https://travel.qunar.com/p-cs300022-changsha-jingdian-1-1
https://travel.qunar.com/p-cs300022-changsha-jingdian-1-2
https://travel.qunar.com/p-cs300022-changsha-jingdian-1-3

我们发现是通过最后的数字来更新URL地址的,因此实际爬虫中我们构造了一个URL地址来循环爬取:

1
2
for i in range(1,165):
"https://travel.qunar.com/p-cs300022-changsha-jingdian-1-{}".format(i)

单页源码获取

我们使用requests模块来发送爬虫请求:

1
2
3
4
5
6
7
url = "https://travel.qunar.com/p-cs300022-changsha-jingdian-1-1"

# 需要更换自己的请求头
headers = {"user-agent": "个人实际请求头"}

response = requests.get(url=url,headers=headers)
result = response.content.decode()

源码规律

每页有10个景点(最后一页可能没有),再看看每个页面源码的规律:每个<li></li>标签中代表一个景点

看看第一个景点(橘子洲)中8个字段信息所在的位置:

正则匹配单页数据

我们使用re模块通过正则表达式来解析需要爬取的字段

如果解析的HTML源码中含有双引号,那么re.findall()方法后面的字符串的最外层使用单引号

1、景点中文名

1
2
3
4
5
# 1-景点中文名称

cn_title = re.findall('class="cn_tit">(.*?)<span class="en_tit">.*?</span>',result,re.S)
print("长度:",len(cn_title))
cn_title

2、景点英文名

1
2
3
4
5
# 2-景点英文名称

en_title = re.findall('<span class="en_tit">(.*?)</span>.*?</span>',result,re.S)
print("长度",len(en_title))
en_title

3、攻略数

4、点评数

1
2
3
4
5
# 4-comment点评数量

comment = re.findall('class="icon_comment" title="点评"></span>(.*?)</div>',result, re.S)
print(len(comment))
comment

5、地点

我们把去过()的驴友作为关键词

1
2
3
4
5
# 5-景点地点:去过+地点+的驴友.....

location = re.findall('去过(.*?)的驴友', result, re.S)
print(len(location))
location

6、排名

排名的提取稍微复杂些,因为有些景点没有排名信息,需要特殊处理,我们看看两种不同的源码

存在排名的情形:

不存在排名的情形:

我们以前10页为例,先提取ranking_sum后面的全部内容,如果有排名则再进一步处理,没有排名则显示为0:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
for i in range(1,5):
url = "https://travel.qunar.com/p-cs300022-changsha-jingdian-1-{}".format(i)
headers = {"user-agent": "个人请求头"}
response = requests.get(url=url,headers=headers)
result = response.content.decode()

ranking = re.findall('class="ranking_sum">(.*?)</span>.*?</div>',result,re.S)
print("原始数据{}:".format(i), ranking)

# 这里才是提取ranking排名的关键代码
for j in range(len(ranking)):
if ranking[j] is "":
ranking[j] = "0" # 没有排名显示为0
else:
ranking[j] = ranking[j].split(">")[1] # 根据>进行切割,取出右边的数据
print("修改后数据{}:".format(i), ranking)
print("-----------------------------")

7、驴友

1
2
3
4
5
# 有多少的驴友也去过这个地方

lvyou = re.findall('class="comment_sum">.*?class="sum">(.*?)</span>',result,re.S)
print(len(lvyou))
lvyou

8、景点简介

1
2
3
4
# 8-景点简介
abstract = re.findall('class="desbox">(.*?)</div>',result,re.S)
print(len(abstract))
abstract

全网数据

下面是全网爬取的代码,包含几个内容:

  • 请求网页获取源码
  • 解析源码得到每个字段信息
  • 保存到csv文件中

数据处理

读取数据

读取我们保存的数据:

我们关注的是长沙的相关景点,指定location=“长沙”,同时查看数据中字段的类型:

ranking处理

我们对景区排名进行处理,取出前20个景区,同时需要将排名为0的数据排除掉:

1
2
3
4
5
6
# 如何修改某个字段的类型
# changsha["ranking"] = changsha["ranking"].astype(int)

# 根据ranking排序取出前20名数据,排除ranking=0的数据
changsha1 = changsha[changsha["ranking"] != 0].sort_values(by=["ranking"])[:20].reset_index(drop=True)
changsha1.head()

从上面的表格数据可以得到初步结论:

  • 网游眼中排名第一的是橘子洲🍊;排名第二的是岳麓山⛰。两个景点的确很出名
  • 排名第三的黄兴路步行街🚶和第四的太平老街都是在长沙雨花区的五一广场附近

comment处理

评论comment处理,取出前20个评论最高的景点(降序):

1
2
changsha2 = changsha[changsha["comment"] != 0].sort_values(by=["comment"],ascending=False)[:20]
changsha2.head()

strategy处理

对攻略数量是和上面评论处理相同,取出前20个(降序):

1
2
changsha3 = changsha[changsha["strategy"] != 0].sort_values(by=["strategy"],ascending=False)[:20]
changsha3.head()

lvyou处理

我们爬取到的驴友数据是百分比,类型是字符串类型,我们现在去掉%符号,取出左边的数值,如果没有则用0代替:

1
2
3
4
5
# 去掉%取出左边数据
changsha["lvyou_number"] = changsha["lvyou"].apply(lambda x:x.split("%")[0])

changsha["lvyou_number"] = changsha["lvyou_number"].astype(int)
changsha.head()

abstract处理

简介是中文文字,我们接下来需要绘制词云图。我们先用jieba分词+去停用词的方法进行处理

1、简介全部转成一个大列表

1
2
abstract_list = changsha["abstract"].tolist()
abstract_list[:5]

2、使用jieba分词的效果

1
2
3
4
for i in range(len(abstract_list)):
# str函数强制将数值转成字符串,才能使用strip方法
seg_list = jieba.cut(str(abstract_list[i]).strip(), cut_all=False) # seg_list只是一个generator生成器:<class 'generator'>
print(("Default Mode: " + "/ ".join(seg_list))) # 用list方法展开

3、分词结果放入一个列表中

1
2
3
4
5
6
7
8
9
10
11
12
# 3-将分词的结果全部放入一个列表中,方便后续处理

jieba_name = []

for i in range(len(abstract_list)):
# seg_list只是一个generator生成器:<class 'generator'>
seg_list = jieba.cut(str(abstract_list[i]).strip(), cut_all=False)
# 对list(seg_list)中的每个元素进行追加
for each in list(seg_list):
jieba_name.append(each)

jieba_name[:20]

4、分词之后使用去停用词

停用词表是我自己在网上收集和整理的:

  • 先创建读取停用词表的数据的函数
  • 加载停用词之后再和现有的数据对比判断
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 创建停用词list
def stopwordslist(filepath):
stopwords = [line.strip() for line in open(filepath, 'r', encoding='utf-8').readlines()]
return stopwords

# 传入路径,加载去停用词
stopwords = stopwordslist('/Users/peter/Desktop/nlp_stopwords.txt')

stopword_list = []
for word in jieba_name: # jieba_name中的word不在停用词表中,且不是\t制表符
if word not in stopwords:
if word != "\t" and word != " " and word != "nan": # 几个特殊符号的排除
stopword_list.append(word)

stopword_list[:10]

5、统计单词个数

1
2
3
4
5
6
7
8
9
10
11
dic = {}
number = 0

for each in stopword_list:
if each in dic.keys():
number += 1 # 如果存在字典中则个数加1,并赋值给当前的each键
dic[each] = number
else:
dic[each] = 1 # 不存在则结果为1,只出现一次

dic

结果的部分截图:

6、将上面👆的字典数据转成列表嵌套元组的形式,方便后续绘图:

1
2
3
4
5
tuple_list = []

for k,v in dic.items():
tuple_list.append(tuple([k,v]))
tuple_list[:20]

绘图

  • ranking:折线图
  • comment:柱状图
  • strategy:漏斗图
  • lvyou:柱状图
  • abstract:词云图

pyecharts配置项说明:https://zhuanlan.zhihu.com/p/117467519

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# 排名-折线图
def Ranking() -> Line:
ranking = (
Line()
.add_xaxis(changsha1["cn_title"].tolist())
.add_yaxis("景点排名",changsha1["ranking"].tolist())
.set_global_opts(title_opts=opts.TitleOpts(title="长沙前20景点排名"),
xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(rotate=-30)), # 设置旋转角度
)
)
return ranking

# 评论-柱状图
def Comment() -> Bar:
comment = (
Bar(init_opts=opts.InitOpts(theme=ThemeType.LIGHT))
.add_xaxis(changsha2["cn_title"].tolist())
.add_yaxis("景点评论数",changsha2["comment"].tolist())
.set_global_opts(title_opts=opts.TitleOpts(title="长沙前20最高的景点评论数"),
xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(rotate=-36)),
)
)

return comment

# 景点攻略-漏斗图
def Strategy() -> Funnel:
strategy = (
Funnel()
.add("景点攻略", [list(z) for z in zip(changsha3["cn_title"].tolist(), changsha3["strategy"].tolist())])
.set_global_opts(title_opts=opts.TitleOpts(title="景点攻略数漏斗",pos_left="center"),
legend_opts=opts.LegendOpts(type_="scroll", pos_left="1%", orient="vertical") # 图例滚动,且靠左
)
)

return strategy


# 驴友数-柱状图
def LvYou() -> Bar:
lvyou = (
Bar(init_opts=opts.InitOpts(theme=ThemeType.WONDERLAND))
.add_xaxis(changsha4["cn_title"].tolist())
.add_yaxis("景点驴友数",changsha4["lvyou_number"].tolist())
.set_global_opts(title_opts=opts.TitleOpts(title="长沙驴友最高的前10景点"),
xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(rotate=-25)), # 设置旋转角度
)
)

return lvyou

# 景点简介-词云图
def Abstract() -> WordCloud:
abstract = (
WordCloud()
.add("", tuple_list, word_size_range=[12, 55])
.set_global_opts(title_opts=opts.TitleOpts(title="长沙景点简介-词云图"))
)

return abstract

# Page类
def main():
page = Page(layout=Page.DraggablePageLayout)
# 将上面封装好的函数添加进来
page.add(
Ranking(),
Comment(),
Strategy(),
LvYou(),
Abstract()
)
page.render("changsha.html")

if __name__ == "__main__":
main()

看到效果中显示的图形,我们注意到两点:

  1. 左上角的Save Config按钮
  2. 整体图形靠左
  3. 图形是一个个上下排列

现在拖动图形和改变大小,排列成我们需要的形状和位置布局,点击Save Config按钮,生成一个chart_config.json的文件,我们运行如下的代码,便会将我们的图形固定下来。

1
2
3
Page.save_resize_html("changsha.html",   # 上面的HTML文件名称
cfg_file="chart_config.json", # 保存的json配置文件
dest="changsha_new.html") # 新的文件名称

结论

1、橘子洲你真的应该去👏

从上面的好几种图形中看出来,不管是排名,还是游客的评论数,亦或者游客的攻略数,橘子洲🍊都是排名第一,其附近的橘子洲烟火、橘子洲大桥等都是值得你去的第一个景点

2、五一广场你也不能错过

天心区的黄兴路步行街、太平老街、火宫殿、天心阁、南门口是一整片的繁华区,店铺和年轻人特别多,爱吃爱喝爱玩的你,最应该去那里

3、岳麓山散散步

从景区排名、网友的评论数、攻略数看出来,到长沙的朋友也特别爱去岳麓山。岳麓山、岳麓书院、爱晚亭是连在一起的,连湖南大学也在山脚下,也是一个很不错的景点。

4、逛逛博物馆和遗址

如果你喜欢历史,喜欢逛博物馆,那么你可不能错过:湖南省博物馆、马王堆汉墓遗址、长沙简牍博物馆,尤其是著名的马王堆汉墓遗址🐎。

湖南长沙欢迎你😊

本文标题:长沙欢迎你之美景篇

发布时间:2021年01月05日 - 17:01

原始链接:http://www.renpeter.cn/2021/01/05/%E9%95%BF%E6%B2%99%E6%AC%A2%E8%BF%8E%E4%BD%A0%E4%B9%8B%E7%BE%8E%E6%99%AF%E7%AF%87.html

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

Coffee or Tea