赞
踩
疫情自从来了之后已经很久没有出去旅游过了,蹭着这段疫情好转,那肯定是要出去走一走的,这一篇其实是全国旅游中的一站,因为每个城市能玩的地方太多了,一篇文章下来肯定是写不了的,所以今天就抓取一下——兰州。如果大家喜欢这个案例的话 后续会陆续更新的。
摘录一段来自维基百科中关于兰州的简介:
兰州市,简称 兰 ,别称 金城 ,是 中华人民共和国 甘肃省 省会,国务院批复确定的中国西北地区重要的工业基地和综合交通枢纽,丝绸之路经济带的重要节点城市,西部地区重要的中心城市之一,西北地区第三大城市,“兰州—西宁城市群”中的核心城市,位于甘肃省中部。
下面是兰州的行政区域:
爬取的信息主要是兰州的美食和景点信息:
- 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, Scatter, Pie, Line, HeatMap, Funnel, WordCloud, Grid, Page # 各个图形的类
- from pyecharts.commons.utils import JsCode
- from pyecharts.globals import ThemeType,SymbolType
下面单页爬取的代码,采用的是正则爬取的方式:
- url = "https://travel.qunar.com/p-cs300026-lanzhou-jingdian-1-1"
-
- headers = {"user-agent": "个人请求头"}
-
- response = requests.get(url=url,headers=headers)
- result = response.content.decode()
如果解析的HTML源码中含有双引号,那么re.findall()方法后面的字符串的最外层使用单引号
In [3]:
- # 1-景点中文名称
-
- cn_title = re.findall('class="cn_tit">(.*?)<span class="en_tit">.*?</span>',result,re.S)
- print("长度:",len(cn_title))
- cn_title
- 长度: 10
Out[3]:
['甘肃省博物馆', '黄河铁桥', '白塔山公园', '黄河母亲雕塑', '兰州新区长城影视基地', '石佛沟国家森林公园', '黄河索道', '五泉山公园', '兰州极地海洋世界', '兰山公园']
In [4]:
- # 2-景点英文名称
-
- en_title = re.findall('<span class="en_tit">(.*?)</span>.*?</span>',result,re.S)
- print("长度",len(en_title))
- en_title
- 长度 10
Out[4]:
- ['Gansu Provincial Museum',
- 'Yellow River Steel Bridge',
- 'Baitashan Park',
- 'Yellow River Mother Sculpture',
- 'Lanzhou Xinqu Changcheng Yingshi Base',
- 'Lanzhou Shifo Valley National Forest Park',
- 'Huanghe Ropeway',
- 'Wuquanshan Park',
- 'Lanzhou Ocean World',
- 'Lanshan Park']
In [5]:
- # 3-strategy攻略数量
- strategy = re.findall('class="icon_strategy" title="攻略"></span>(.*?)</div>',result, re.S)
- print(len(strategy))
- strategy
- 10
Out[5]:
['50', '94', '40', '35', '0', '1', '3', '2', '0', '1']
In [6]:
# 4-comment点评数量 comment = re.findall('class="icon_comment" title="点评"></span>(.*?)</div>',result, re.S) print(len(comment)) comment 10
Out[6]:
['1295', '2948', '793', '489', '23', '30', '46', '354', '146', '80']
In [7]:
# 5-景点地点(长沙景点排名、宁乡景点排名等) # 我们只需要"景点排名"之前的信息,代表的是地址 location = re.findall('去过(.*?)的驴友', result, re.S) print(len(location)) location 10
Out[7]:
['兰州', '兰州', '兰州', '兰州', '永登', '兰州', '兰州', '兰州', '兰州', '兰州']
In [8]:
# 6-景点排名 ranking = re.findall('class="ranking_sum".*?class="sum">(.*?)</span>',result,re.S) print(len(ranking)) ranking 10
Out[8]:
['7', '3', '11', '10', '0%', '56', '1', '17', '5', '49']
In [9]:
# 7-驴友 # 有多少的驴友也去过这个地方 lvyou = re.findall('class="comment_sum">.*?class="sum">(.*?)</span>',result,re.S) print(len(lvyou)) lvyou 10
Out[9]:
['35%', '58%', '30%', '30%', '0%', '0%', '0%', '1%', '0%', '1%']
In [10]:
# 8-景点简介 abstract = re.findall('class="desbox">(.*?)</div>',result,re.S) print(len(abstract)) abstract 10
Out[10]:
['通过丰富精彩的展品了解古丝绸之路、唐蕃古道上多民族的文化和历史。', '兰州市最为经典的地标建筑,夜晚时铁桥彩灯闪耀,周围夜景非常漂亮。', '登上山顶可以俯瞰壮观的兰州城市全景,山间建筑古朴树木众多,让人感受舒心惬意。', '黄河母亲雕塑现已经成为兰州的标志性雕塑,也代表着兰州形象。', '', # 空值 '', '', '公园景点以五眼名泉和佛教古建筑为主,园内丘壑起伏,林木葱郁,环境清幽。', '', '公园就位于山顶制高点上,可俯瞰兰州全景。']
最终爬取的结果:
单页信息爬取的代码,同样是基于正则表达式的爬取:总共是200页
In [2]:
- url = "https://travel.qunar.com/p-cs300026-lanzhou-meishi?page=1"
- headers = {"user-agent": "个人请求头"}
- response = requests.get(url=url,headers=headers)
- result = response.content.decode()
cn_title
In [3]:
cn_title = re.findall('cn_tit">(.*?)</span>.*?countbox',result,re.S)
In [4]:
print(len(cn_title)) cn_title 10
Out[4]:
['正宁路小吃夜市', '安泊尔牛肉面(北滨河路店)', '兰州大众巷美食街', '马三洋芋片(兰州总店)', '清真·马安军辣子牛肉面', '安泊尔', '杜记甜食', '孙子烤肉(皋兰路店)', '大漠烤肉(盘旋路店)', '清真•白建强牛肉面']
score
In [5]:
score = re.findall('cur_score">(.*?)</span>.*?total_score',result,re.S)
In [6]:
print(len(score)) score 10
Out[6]:
['4.3', '4.5', '--', '4.3', '3.5', '5.0', '4.2', '3.5', '4.2', '0.0']
sublistbox
先提取整个sublistbox,然后对里面的每个子元素单独提取
In [7]:
sublistbox = re.findall('sublistbox">(.*?)</div>', result, re.S) sublistbox[:1]
Out[7]:
['<dl class="sublist_item clrfix"><dt class="sub_tit">人\u3000均</dt><dd class="sub_des">¥ 63</dd></dl><dl class="sublist_item clrfix"><dt class="sub_tit">地\u3000址</dt><dd class="sub_des des_line">白银路街道永昌南路正宁路</dd></dl><dl class="sublist_item clrfix"><dt class="sub_tit">推荐菜</dt><dd class="sub_des des_line">当地口味\t美食街\t老字号\t深夜营业</dd></dl><div class="desbox"><span class="img_doublequote img_l"></span><span class="txt">吃客云集的小吃街,地道吃食令人回味。<span class="img_doublequote img_r"></span></span>']
In [8]:
type(sublistbox)
Out[8]:
list
In [9]:
# 对sublistbox单独提取
均价
In [10]:
person_avg = [] for i in range(len(sublistbox)): try: if "均" in sublistbox[i]: person_avg.append(re.findall('¥ (.*?)</dd></dl>',sublistbox[i],re.S)[0]) else: person_avg.append(0) continue except: person_avg.append(0)
In [11]:
print(len(person_avg)) person_avg 10
Out[11]:
['63', '27', 0, '19', '17', 0, '14', '58', '58', '18']
地址
In [12]:
address = [] for i in range(len(sublistbox)): try: if "址" in sublistbox[i]: address.append(re.findall('址.*?des_line">(.*?)</dd></dl>',sublistbox[i],re.S)[0]) else: address.append("无") continue except: address.append("无")
In [13]:
print(len(address)) address 10
Out[13]:
['白银路街道永昌南路正宁路', '北滨河路754号(龙源斜对面)', '兰州市城关区大众巷', '通渭路79号', '七里河北街忠云宾馆斜对面', '北滨河路金城关3号', '大众巷72号', '皋兰路4号(虹云宾馆北侧)', '东岗西路451号', '雁滩路3423号']
推荐菜
In [14]:
recommand = [] for i in range(len(sublistbox)): try: if "推荐菜" in sublistbox[i]: recommand.append(re.findall('推荐菜.*?des_line">(.*?)</dd></dl>',sublistbox[i],re.S)[0]) else: recommand.append("无") continue except: recommand.append("无")
In [15]:
print(len(recommand)) recommand 10
Out[15]:
['当地口味\t美食街\t老字号\t深夜营业', '美食林风味\t当地口味\t肉汤萝卜\t三泡台\t酱牛肉\t蜂蜜油香\t安泊尔牛肉面\t牛筋\t雪梨汤\t牛腱子肉\t甜醅子\t灰豆子', '马子禄牛肉面\t香满楼\t俊杰羊肉泡馍馆\t杜维成甜食店', '美食林风味\t当地口味\t炸年糕\t里脊肉饼\t洋芋片\t年糕\t辣年糕\t胡萝卜汁\t豆腐皮\t油炸年糕\t炸糖年糕\t胡萝卜素饮料\t豆皮\t牛肚', '无', '无', '当地口味\t下午茶\t老字号\t美食林风味\t高担酿皮\t甜胚子\t牛肉馅饼\t粽子\t八宝醪糟\t炒粉\t茹记杏皮水\t热晶糕\t甜醅子\t牛奶鸡蛋醪糟\t甜醅\t灰豆子', '无', '深夜营业\t美食林臻选\t羊腰\t凉面\t烤羊肚\t羊汤\t羊肉泡馍\t烤羊排\t烤饼\t烤羊板筋\t烤肉串\t烤羊皮\t杏皮水\t烤茄子', '特色小吃\t当地口味\t其他\t兰州拉面\t牛肉面\t牛肉']
评价
In [16]:
comment = [] for i in range(len(sublistbox)): try: if "desbox" in sublistbox[i]: comment.append(re.findall('.*?txt">(.*?)<span class="img_doublequote img_r">',sublistbox[i],re.S)[0]) else: comment.append("无") continue except: comment.append("无")
In [17]:
print(len(comment)) comment 10
Out[17]:
['吃客云集的小吃街,地道吃食令人回味。', '专注正宗牛肉面,开放式厨房热气腾腾', '大众巷是兰州最古老的美食街,拥有许多老字号当地特色美食,是游客体验兰州美食文化的绝佳去处。', '兰州代表性的小吃店,明档操作干净放心', '颇具名气的牛肉面馆,当地人的家庭食堂', '个人觉得安泊尔是我吃过最好吃的牛肉面了,不过这家店的位置很尴尬,只有这趟路线才能涉及到', '老牌人气甜食店,荣获多个美食奖项', '店里面的装修环境是非常不错的,有人说价格有点贵,看了一下菜单,相对于夜市上的来说确实有一点贵,...', '人气爆棚的口碑餐厅,各式烤串喷香诱人', '当地食堂级别的老店,牛肉面汤清味醇面韧。']
最终爬取结果:刚好是2000条数据
下面是对上面爬取到的两份数据进行分析:
导入数据:
字段基本信息:
In [3]:
# 1-数据缺失值 df.isnull().sum()
Out[3]:
中文名 0 得分 0 均价 0 地址 0 推荐菜 0 评价 0 dtype: int64
In [4]:
# 2、字段类型 df.dtypes
Out[4]:
中文名 object 得分 object 均价 int64 地址 object 推荐菜 object 评价 object dtype: object
分析哪些店的得分靠前:
In [5]:
# 得分中有未评分的数据:-- df["得分"].value_counts()
Out[5]:
-- 1721 3.5 139 3.0 50 4.0 29 4.5 20 5.0 13 4.3 7 4.2 6 0.0 5 4.1 4 2.0 2 3.8 1 4.7 1 2.5 1 1.0 1 Name: 得分, dtype: int64
In [6]:
# 将未评分的数据统一替换成0.0,也就是0分 df["得分"] = df["得分"].apply(lambda x: x.replace("--","0.0"))
大部分店铺的得分在3.5分,好像并不是很高~
到了兰州肯定得吃面:据数据统计有284家面馆
统计出来有129家火锅店:
px.bar(huoguo[:15],x="中文名",y="得分")
绘制当地推荐菜的词云图:
rec_words = [tuple(z) for z in zip(result["词语"].tolist(), result["次数"].tolist())] # 选择前100个词语
- c = (
- WordCloud(init_opts=opts.InitOpts(theme=ThemeType.CHALK))
- .add("", rec_words[:100], word_size_range=[20, 80], shape=SymbolType.DIAMOND)
- .set_global_opts(title_opts=opts.TitleOpts(title="兰州美食词云图"))
- )
-
- c.render_notebook()
还是先导入数据
In [3]:
df1.shape
Out[3]:
(381, 8)
In [4]:
df1.isnull().sum()
Out[4]:
cn_title 0 en_title 113 strategy 0 comment 0 location 0 ranking 0 lvyou 0 abstract 351 dtype: int64
在景点的英文名en_title和简介abstract中存在缺失值
In [5]:
df1.dtypes
Out[5]:
cn_title object en_title object strategy int64 comment int64 location object ranking int64 lvyou object abstract object dtype: object
In [6]:
df2 = df1["location"].value_counts().reset_index() df2.columns = ["location","number"] df2
Out[6]:
location | number | |
---|---|---|
0 | 兰州 | 301 |
1 | 永登 | 39 |
2 | 皋兰 | 21 |
3 | 榆中 | 20 |
In [7]:
- c = (
- Pie(init_opts=opts.InitOpts(theme=ThemeType.CHALK))
- .add("", [list(z) for z in zip(df2["location"].tolist(), df2["number"].tolist())])
- .set_global_opts(title_opts=opts.TitleOpts(title="兰州景点分布"),
- legend_opts=opts.LegendOpts(pos_left="80%", orient="vertical"))
- .set_series_opts(label_opts=opts.LabelOpts(formatter="{b}: {c}"))
- )
-
- c.render_notebook()
- c = (
- Funnel(init_opts=opts.InitOpts(theme=ThemeType.CHALK,
- width="800px",
- height="500px"
- ))
- .add("兰州景点评论数漏斗", [list(z) for z in zip(df5["cn_title"].tolist(), df5["comment"].tolist())])
- .set_series_opts(label_opts=opts.LabelOpts(is_show=True))
- )
-
- c.render_notebook()
前50个词语的展示:
- rec_words = [tuple(z) for z in zip(result["词语"].tolist(), result["次数"].tolist())]
-
- c = (
- WordCloud(init_opts=opts.InitOpts(theme=ThemeType.ROMA))
- .add("", rec_words[:50], word_size_range=[20, 80], shape=SymbolType.DIAMOND)
- .set_global_opts(title_opts=opts.TitleOpts(title="兰州景点词云"))
- )
-
- c.render_notebook()
- # 1-景点位置
-
- def piePage() -> Pie:
- c = (
- Pie(init_opts=opts.InitOpts(theme=ThemeType.CHALK))
- .add("", [list(z) for z in zip(df2["location"].tolist(), df2["number"].tolist())])
- .set_global_opts(title_opts=opts.TitleOpts(title="兰州景点分布"),
- legend_opts=opts.LegendOpts(pos_left="80%", orient="vertical"))
- .set_series_opts(label_opts=opts.LabelOpts(formatter="{b}: {c}")))
-
- return c
-
- # 2-攻略数
-
- def barPageOne() -> Bar:
- c = (
- Bar(init_opts=opts.InitOpts(theme=ThemeType.CHALK))
- .add_xaxis(df4["cn_title"].tolist()[::-1])
- .add_yaxis("攻略数", df4["strategy"].tolist()[::-1])
- .reversal_axis() # 翻转坐标轴
- .set_series_opts(label_opts=opts.LabelOpts(is_show=True, position="right")) # 是否显示数据以及label的位置(显示在右方)
- .set_global_opts(title_opts=opts.TitleOpts(title="兰州景点攻略数前10"))
- )
- return c
-
- # 3-评论数
- def funnlePage() -> Funnel:
- c = (
- Funnel(init_opts=opts.InitOpts(theme=ThemeType.MACARONS,
- width="800px",
- height="600px"
- ))
- .add("兰州景点评论数漏斗", [list(z) for z in zip(df5["cn_title"].tolist(), df5["comment"].tolist())])
- .set_series_opts(label_opts=opts.LabelOpts(is_show=True)))
-
- return c
-
-
- # 4-驴友占比
-
- def barPageTwo() -> Bar:
- c = (
- Bar(init_opts=opts.InitOpts(theme=ThemeType.WALDEN))
- .add_xaxis(df6["cn_title"].tolist())
- .add_yaxis("", df6["lvyou_number"].tolist())
- # .reversal_axis() # 翻转坐标轴
- .set_series_opts(label_opts=opts.LabelOpts(is_show=True)) # 是否显示数据以及label的位置(显示在右方)
- .set_global_opts(title_opts=opts.TitleOpts(title="兰州景点驴友占比"),
- xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(rotate=-30)), # 设置旋转角度
- ))
- return c
-
-
-
- # 5-词云图
- def worldPage() -> WordCloud:
- rec_words = [tuple(z) for z in zip(result["词语"].tolist(), result["次数"].tolist())]
-
- c = (
- WordCloud(init_opts=opts.InitOpts(theme=ThemeType.ROMA))
- .add("", rec_words[:50], word_size_range=[20, 80], shape=SymbolType.DIAMOND)
- .set_global_opts(title_opts=opts.TitleOpts(title="兰州景点词云"))
- )
-
- return c
-
- page = (
- Page(layout=Page.DraggablePageLayout)
- .add(
- piePage(),
- barPageOne(),
- funnlePage(),
- barPageTwo(),
- worldPage()
- ))
-
- page.render("lanzhou.html")
需要完整项目代码关注下方 公众号:Python源码
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。