Python爬虫周游全国-兰州站
theme: smartblue
公众号:尤而小屋
作者:Peter
编辑:Peter
大家好,我是Peter~
本文是Python爬虫旅游全国的第7个城市:兰州,主要是介绍兰州的景点和美食信息。
之前写过厦门、长沙、西安、大连、苏州、成都
等,感兴趣的可以阅读,也可以当做一份旅游指南~
兰州
摘录一段来自维基百科中关于兰州的简介:
兰州市,简称兰,别称金城,是中华人民共和国甘肃省省会,国务院批复确定的中国西北地区重要的工业基地和综合交通枢纽,丝绸之路经济带的重要节点城市,西部地区重要的中心城市之一,西北地区第三大城市,“兰州—西宁城市群”中的核心城市,位于甘肃省中部。
下面是兰州的行政区域:
爬取信息
爬取的信息主要是兰州的美食和景点信息:
```python 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
```
景点爬取
下面单页爬取的代码,采用的是正则爬取的方式:
```python url = "http://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">(.?).?',result,re.S) print("长度:",len(cn_title)) cn_title 长度: 10 ```
Out[3]:
['甘肃省博物馆',
'黄河铁桥',
'白塔山公园',
'黄河母亲雕塑',
'兰州新区长城影视基地',
'石佛沟国家森林公园',
'黄河索道',
'五泉山公园',
'兰州极地海洋世界',
'兰山公园']
In [4]:
```
2-景点英文名称
en_title = re.findall('(.?).?',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="攻略">(.*?)
Out[5]:
['50', '94', '40', '35', '0', '1', '3', '2', '0', '1']
In [6]:
```
4-comment点评数量
comment = re.findall('class="icon_comment" title="点评">(.*?)',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">(.?)',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">(.?)',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">(.*?)',result,re.S) print(len(abstract)) abstract 10 ```
Out[10]:
python
['通过丰富精彩的展品了解古丝绸之路、唐蕃古道上多民族的文化和历史。',
'兰州市最为经典的地标建筑,夜晚时铁桥彩灯闪耀,周围夜景非常漂亮。',
'登上山顶可以俯瞰壮观的兰州城市全景,山间建筑古朴树木众多,让人感受舒心惬意。',
'黄河母亲雕塑现已经成为兰州的标志性雕塑,也代表着兰州形象。',
'', # 空值
'',
'',
'公园景点以五眼名泉和佛教古建筑为主,园内丘壑起伏,林木葱郁,环境清幽。',
'',
'公园就位于山顶制高点上,可俯瞰兰州全景。']
最终爬取的结果:
美食爬取
单页信息爬取的代码,同样是基于正则表达式的爬取:总共是200页
In [2]:
python
url = "http://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">(.*?)', 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('¥ (.*?)',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">(.?)',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">(.?)',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">(.?)',sublistbox[i],re.S)[0]) else: comment.append("无") continue except: comment.append("无") ```
In [17]:
print(len(comment))
comment
10
Out[17]:
python
['吃客云集的小吃街,地道吃食令人回味。',
'专注正宗牛肉面,开放式厨房热气腾腾',
'大众巷是兰州最古老的美食街,拥有许多老字号当地特色美食,是游客体验兰州美食文化的绝佳去处。',
'兰州代表性的小吃店,明档操作干净放心',
'颇具名气的牛肉面馆,当地人的家庭食堂',
'个人觉得安泊尔是我吃过最好吃的牛肉面了,不过这家店的位置很尴尬,只有这趟路线才能涉及到',
'老牌人气甜食店,荣获多个美食奖项',
'店里面的装修环境是非常不错的,有人说价格有点贵,看了一下菜单,相对于夜市上的来说确实有一点贵,...',
'人气爆棚的口碑餐厅,各式烤串喷香诱人',
'当地食堂级别的老店,牛肉面汤清味醇面韧。']
最终爬取结果:刚好是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分,好像并不是很高~
得分前10的店铺
店铺均价占比
高档餐厅
面馆
到了兰州肯定得吃面:据数据统计有284家面馆
火锅店
统计出来有129家火锅店:
python
px.bar(huoguo[:15],x="中文名",y="得分")
美食统计信息
推荐菜词云
绘制当地推荐菜的词云图:
```python 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() ```
攻略数
评论数前10名
```python 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个词语的展示:
```python 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() ```
整体绘图
```python
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")
```
- 我正在参与掘金技术社区创作者签约计划招募活动,点击链接报名投稿。
- 基于机器学习分类算法的钢材缺陷检测分类
- JSON数据,Python搞定!
- 逻辑回归:信贷违规预测!
- kaggle实战-肿瘤数据统计分析
- Pandas操作mysql数据库!
- 数学公式编辑神器-Mathpix Snipping Tool
- 精选20个Pandas统计函数
- 露一手,利用Python分析房价
- 德国信贷数据建模baseline!
- Python函数传参机制详解
- Python爬虫周游全国-兰州站
- 一道Pandas题:3种解法
- 机器学习实战:基于3大分类模型的中风病人预测
- 利用seaborn绘制柱状图
- 机器学习实战:基于MNIST数据集的二分类问题
- 基于深度学习Keras的深圳租房建模
- 机器学习高频使用代码片段
- Python入门:Python变量和赋值
- 深度学习框架Keras入门保姆教程
- kaggle实战:极度不均衡的信用卡数据分析