十一假期开始,打开朋友圈,看到小伙伴们纷纷晒出了自己的车票,不是出去玩就是回家。因为不可抗拒的因素,可怜的我只能坚守工作岗位,哪都去不了,心急难耐之余,虽然自己去不了,那就看看全国各地的广大旅友都喜欢去什么地方吧。

这里,数据来源是马蜂窝http://www.mafengwo.cn/。首先,马蜂窝对爬虫相对友好,另外,使用马蜂窝也是我和女友出游的习惯,在计划去某地前都会先在马蜂窝上查查攻略,不得不佩服很多小伙伴写的游记真的超级棒,起到事半功倍的效果。

目标:

通过分析马蜂窝中提及到某目的地的景点、餐饮、娱乐三个方面的游记做定量分析,客观程度上反映出某目的地的热门程度。

工具:

selenium自动化测试工具

ChromeDriver

pandas

pyecharts

原理:

Selenium是一个自动化测试工具,利用它可以驱动浏览器执行特定的动作,如点击、下拉等操作,还可以获取浏览器当前呈现的页面的源代码,做到可见即可爬。在这里可以利用Selenium模拟点击,做一些翻页操作。

步骤1:获取城市编号

马蜂窝中的所有城市或目的地都有一个专属的五位数字编号,要想获得该城市或目的地的具体信息,首先要获取该目的地(直辖市或地级市)的城市编号,然后进行后续的分析。

如上图所示,在目的地栏进入某个省份,以云南为例,总共有206个目的地。以上两个页面就是我们的城市编码来源,首先在目的地页面获得各省编码,之后进入各省的城市列表获得城市编码。这里采用Selenium进行动态数据爬取,获取城市编码的代码如下:

# -*- coding: utf-8 -*-
"""
Created on Tue May 29 21:53:47 2018@author: slash
"""import os
import time
from urllib.request import  urlopen
from urllib  import request
from bs4 import BeautifulSoup
import pandas as pd
from selenium import webdriver os.chdir('/Users/Macx/Desktop/python_demo/mafengwo_data-master')## 获得地区url地址
def find_cat_url(url):  headers = {'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:23.0) Gecko/20100101 Firefox/23.0'}      req=request.Request(url,headers=headers)  html=urlopen(req)#指定使用html.parser解析器进行解析,目前支持lxml, html5lib, 和 html.parserbsObj=BeautifulSoup(html.read(),"html.parser")#按照属性名和标签名找到所有目的地,目的地名放在dt标签里bs = bsObj.find('div',attrs={'class':'hot-list clearfix'}).find_all('dt')cat_url = []cat_name = []#遍历所有目的地for i in range(0,len(bs)):#遍历某个目的地的所有地区名,地区名放在a标签里for j in range(0,len(bs[i].find_all('a'))):#通过href属性查找地区网址进行添加cat_url.append(bs[i].find_all('a')[j].attrs['href'])#通过a标签查找地区名进行添加cat_name.append(bs[i].find_all('a')[j].text)cat_url = ['http://www.mafengwo.cn'+cat_url[i] for i in range(0,len(cat_url))]   return cat_url## 获得城市url地址
def find_city_url(url_list):city_name_list = []city_url_list = []for i in range(0,len(url_list)):             driver = webdriver.Chrome()driver.maximize_window()url = url_list[i].replace('travel-scenic-spot/mafengwo','mdd/citylist')driver.get(url)while True:try:time.sleep(2)bs = BeautifulSoup(driver.page_source,'html.parser')url_set = bs.find_all('a',attrs={'data-type':'目的地'})city_name_list = city_name_list +[url_set[i].text.replace('\n','').split()[0] for i in range(0,len(url_set))]city_url_list = city_url_list+[url_set[i].attrs['data-id'] for i in range(0,len(url_set))]#模拟滚动条向下滚动800个像素js="var q=document.documentElement.scrollTop=1000"#调用JS脚本driver.execute_script(js)time.sleep(2)driver.find_element_by_class_name('pg-next').click()except:breakdriver.close()return city_name_list,city_url_list## 执行代码
url = 'http://www.mafengwo.cn/mdd/'
url_list = find_cat_url(url)
city_name_list,city_url_list=find_city_url(url_list)
#从字典构造DataFrame
city = pd.DataFrame({'city_name':city_name_list,'city_code':city_url_list})
city.to_csv('city.csv')

最后,将爬取的城市编码作为一个二维数组放入一个表格里。总共得到3281条数据。

步骤2:获取城市具体信息

这里,主要获取马蜂窝中的城市印象标签、景点、餐饮、娱乐四个板块的信息。

(1)城市印象标签

(2)景点页面

(2)餐饮页面

(3)娱乐页面

将每个城市获取数据的过程封装成函数,每次传入之前先获得城市编码:

# -*- coding: utf-8 -*-
"""
Created on Sat Jun  2 16:46:19 2018@author: slash
"""import os
from urllib.request import  urlopen
from urllib  import request
from bs4 import BeautifulSoup
import pandas as pd
from pyecharts import Bar,Geo,Gridos.chdir('/Users/Macx/Desktop/python_demo/mafengwo_data-master')## 获得城市url内容
def get_static_url_content(url):headers = {'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:23.0) Gecko/20100101 Firefox/23.0'}      req=request.Request(url,headers=headers)  html=urlopen(req)  bsObj=BeautifulSoup(html.read(),"html.parser")return bsObj## 获得城市信息
def get_city_info(city_name,city_code):this_city_base = get_city_base(city_name,city_code)#景点try:this_city_jd = get_city_jd(city_name,city_code)this_city_jd['city_name'] = city_namethis_city_jd['total_city_yj'] = this_city_base['total_city_yj']except:this_city_jd=pd.DataFrame()#餐饮try:this_city_food = get_city_food(city_name,city_code)this_city_food['city_name'] = city_namethis_city_food['total_city_yj'] = this_city_base['total_city_yj']except:this_city_food=pd.DataFrame()#娱乐try:this_city_yl = get_city_yl(city_name,city_code)this_city_yl['city_name'] = city_namethis_city_yl['total_city_yj'] = this_city_base['total_city_yj']except:this_city_yl=pd.DataFrame()return this_city_base,this_city_jd,this_city_food,this_city_yl#从这里开始进入!!!!
## 获得城市各类标签信息
def get_city_base(city_name,city_code):url = 'http://www.mafengwo.cn/xc/'+str(city_code)+'/'bsObj = get_static_url_content(url)#<a href="/yl/10186/1487.html" target="_blank">#酒吧<em> 4088</em>                        </a>#在社区行程页面寻找城市印象的标签,如丽江印象node =  bsObj.find('div',{'class':'m-box m-tags'}).find('div',{'class':'bd'}).find_all('a')#寻找印象提及次数的标签tag_node = bsObj.find('div',{'class':'m-box m-tags'}).find('div',{'class':'bd'}).find_all('em')#将提及次数的text文本信息转化成整型tag_count = [int(k.text) for k in tag_node]#<a href="/yl/10186/1487.html" target="_blank">#其中不同标签有不同代号,看该标签是属于娱乐还是餐饮还是景点还是购物#<a href="/yl/10186/1487.html" target="_blank">par = [k.attrs['href'][1:3] for k in node]#所有印象被提及次数的总和tag_all_count = sum([int(tag_count[i]) for i in range(0,len(tag_count))])#有多少人的游记中提到该城市的景点tag_jd_count = sum([int(tag_count[i]) for i in range(0,len(tag_count)) if par[i]=='jd'])#有多少人的游记中提到该城市的餐饮tag_food_count = sum([int(tag_count[i]) for i in range(0,len(tag_count)) if par[i]=='cy'])#有多少人的游记中提到该城市的娱乐tag_yl_count = sum([int(tag_count[i]) for i in range(0,len(tag_count)) if par[i] in ['gw','yl']])#第一页url = 'http://www.mafengwo.cn/yj/'+str(city_code)+'/2-0-1.html 'bsObj = get_static_url_content(url)#<span class="count">共<span>391</span>页 / <span>5860</span>条</span>#下滑后查看页码和记录条数,记录总的游记数量total_city_yj = int(bsObj.find('span',{'class':'count'}).find_all('span')[1].text)return {'city_name':city_name,'tag_all_count':tag_all_count,'tag_jd_count':tag_jd_count,'tag_food_count':tag_food_count,'tag_yl_count':tag_yl_count,'total_city_yj':total_city_yj}## 获得某个城市具体那些食物的信息
def get_city_food(city_name,city_code):#进到目的地餐饮页面#<ol class="list-rank">#    <li class="rank-item top1">#        <a href="/cy/10819/1664.html" title="牛肉面">#            <span class="r-img"><img src="http://n2-q.mafengwo.net/s6/M00/9C/BC/wKgB4lMNs5GAAShMAAE0pvbJJvQ35.jpeg?imageMogr2%2Fthumbnail%2F%21135x100r%2Fgravity%2FCenter%2Fcrop%2F%21135x100%2Fquality%2F90" width="110" height="70"><em class="r-num">1</em></span>#                <h3>牛肉面</h3>#                    <span class="trend"><i></i>501</span>                            <p><span class="num-orange">501</span> 游记提及</p>#                        <p><span class="num-blue">4</span> 推荐美食</p>#                        </a>#                    </li>url = 'http://www.mafengwo.cn/cy/'+str(city_code)+'/gonglve.html'bsObj = get_static_url_content(url)#餐饮名称food=[k.text for k in bsObj.find('ol',{'class':'list-rank'}).find_all('h3')]#餐饮推荐次数food_count=[int(k.text) for k in bsObj.find('ol',{'class':'list-rank'}).find_all('span',{'class':'trend'})]return pd.DataFrame({'food':food[0:len(food_count)],'food_count':food_count})## 获得某个城市具体那些景点的信息
def get_city_jd(city_name,city_code):url = 'http://www.mafengwo.cn/jd/'+str(city_code)+'/gonglve.html'bsObj = get_static_url_content(url)#找到景点名称标签node=bsObj.find('div',{'class':'row row-top5'}).find_all('h3')jd = [k.text.split('\n')[2] for k in node]#<span class="rev-total"><em>5833</em> 条点评</span>node=bsObj.find_all('span',{'class':'rev-total'})#将字符串格式转化成整型jd_count=[int(k.text.replace(' 条点评','')) for k in node]return pd.DataFrame({'jd':jd[0:len(jd_count)],'jd_count':jd_count})## 获得某个城市具体那些娱乐的信息
def get_city_yl(city_name,city_code):url = 'http://www.mafengwo.cn/yl/'+str(city_code)+'/gonglve.html'bsObj = get_static_url_content(url)#娱乐标签名称yl=[k.text for k in bsObj.find('ol',{'class':'list-rank'}).find_all('h3')]#娱乐推荐次数yl_count=[int(k.text) for k in bsObj.find('ol',{'class':'list-rank'}).find_all('span',{'class':'trend'})]return pd.DataFrame({'yl':yl[0:len(yl_count)],'yl_count':yl_count})## 执行函数
city_list = pd.read_csv('city.csv')
#数据帧(DataFrame)是二维数据结构,即数据以行和列的表格方式排列
city_base = pd.DataFrame()
city_food = pd.DataFrame()
city_jd =  pd.DataFrame()
city_yl =  pd.DataFrame()
#读取矩阵第一维度的长度
for i in range(0,city_list.shape[0]):try:#iloc是根据标签所在的位置,从0开始计数#loc根据列的具体名称进行选取k = city_list.iloc[i]#city_name是str类型   city_code是64int型this_city_base,this_city_jd,this_city_food,this_city_yl=get_city_info(k['city_name'],k['city_code'])city_base=city_base.append(this_city_base,ignore_index=True)#axis=0,按照行数首尾链接city_food = pd.concat([city_food,this_city_food],axis=0)city_jd = pd.concat([city_jd,this_city_jd],axis=0)city_yl = pd.concat([city_yl,this_city_yl],axis=0)print(i)print('正确:'+k['city_name'])except:print(i)print('错误:'+k['city_name'])continue## 绘制图片
#######################################对城市作分析###########################################ascending=False 降序排列   ,ascending=True, 升序排列   inplace默认为True
city_base.sort_values('total_city_yj',ascending=False,inplace=True)
attr1 = city_base['city_name'][0:10]#提到某城市的游记总数量
v1 = city_base['total_city_yj'][0:10]
#提到某城市景点的游记总数量
v2 = city_base['tag_jd_count'][0:15]
#提到某城市餐饮的游记总数量
v3 = city_base['tag_food_count'][0:15]
#提到某城市娱乐的游记总数量
v4 = city_base['tag_yl_count'][0:15]bar1 = Bar("游记TOP15")
#"游记总数"为标题,attr为横坐标城市名称,v1为纵坐标游记总数
bar1.add("游记总数", attr1, v1, is_stack=True)
bar1.render('游记总数量TOP10.html')city_base.sort_values('tag_jd_count',ascending=False,inplace=True)
attr_jd = city_base['city_name'][0:15]
bar2 = Bar("景点类标签排名")
bar2.add("景点类标签分数", attr_jd, v2, is_splitline_show=False,xaxis_rotate=30)city_base.sort_values('tag_food_count',ascending=False,inplace=True)
attr_food = city_base['city_name'][0:15]
bar3 = Bar("餐饮类标签排名")
bar3.add("餐饮类标签分数", attr_food, v3, legend_top="30",is_splitline_show=False,xaxis_rotate=30)city_base.sort_values('tag_yl_count',ascending=False,inplace=True)
attr_yl = city_base['city_name'][0:15]
bar4 = Bar("休闲类标签排名")
bar4.add("休闲类标签分数", attr_yl, v4, legend_top="67.5",is_splitline_show=False,xaxis_rotate=30)
grid = Grid(height=800)
grid.add(bar2,grid_bottom="75%")
grid.add(bar3,grid_bottom="37.5%",grid_top="37.5%")
grid.add(bar4,grid_top="75%")
grid.render('城市分类标签.html')
'''
#遍历CSV中的每一行数据,城市名称和每个城市提到的游记数量
data=[(city_base['city_name'][i],city_base['total_city_yj'][i]) for i in range(0,
city_base.shape[0])]
#地理坐标系Geo
geo = Geo('马蜂窝全国城市旅游热力图', title_color="#fff",
title_pos="center", width=1200,
height=600, background_color='#404a59')
attr, value = geo.cast(data)
geo.add("", attr, value, visual_range=[0, 30000], visual_text_color="#fff",
symbol_size=15, is_visualmap=True,is_roam=False)
geo.render('蚂蜂窝全国城市旅游热力图.html')
'''
#########################################对景点作分析#####################################
city_jd.sort_values('jd_count',ascending=False,inplace=True)
city_food.sort_values('food_count',ascending=False,inplace=True)
city_yl.sort_values('yl_count',ascending=False,inplace=True)
attr2 = city_jd['jd'][0:15]
attr3 = city_food['food'][0:15]
attr4 = city_yl['yl'][0:15]
v22 = city_jd['jd_count'][0:15]
v33 = city_food['food_count'][0:15]
v44 = city_yl['yl_count'][0:15]
bar11=Bar("景点人气排名")
bar11.add("景点人气分数", attr2, v22, is_splitline_show=False,xaxis_rotate=30)
bar22=Bar("餐饮人气排名")
bar22.add("餐饮人气分数", attr3, v33, legend_top="30",is_splitline_show=False,xaxis_rotate=30)
bar33 = Bar("休闲人气排名")
bar33.add("休闲人气分数", attr4, v44, legend_top="67.5",is_splitline_show=False,xaxis_rotate=30)
grid = Grid(height=800)
grid.add(bar11,grid_bottom="75%")
grid.add(bar22,grid_bottom="37.5%",grid_top="37.5%")
grid.add(bar33,grid_top="75%")
grid.render('人气排名.html')

步骤3:数据可视化分析

(1)热门城市Top10

通过提炼提及到每个城市的游记数量,排列出受欢迎程度前十名的城市如图所示,不出意料,小清新的厦门果然受到广大旅友的青睐。在年初三月份的时候和女友一同去了鼓浪屿、曾厝垵等地方,印象真的很好。

(2)城市分类标签

按提及到的景点、餐饮、娱乐对城市进行排名,果然,厦门又英勇夺魁。

(3)人气排名

然后再分别看看景点、餐饮、休闲类的人气排名,看看大家到底喜欢什么地方。出乎意料的是,大家最喜欢逛的景点是第一市场,这个第一市场是什么鬼,没听过!!!!不过后几名的鼓浪屿、锦里、丽江古城、西湖还是在情理之中的。

因为去厦门的最多,自然而然排名前二的美食就是沙茶面和海蛎煎喽,本人也超级喜欢哈哈。

(4)马蜂窝全国城市旅游热力图。

在这里,主要想看看大家的足迹都涉及到哪些城市。过程中遇到了个问题,首先从马蜂窝提取出的目的地名称是不包含“市”、“县”、“区”这些字眼的,然而pyecharts带的地图资源包的json文件中的键名包含了这些字眼,因此画图时总出现键名不匹配的bug。除了对json包进行修改,暂时没想到其他方法,但3281条数据量比较大,就不修改了,这里仅修改了云南的50个目的地做演示。

NO.31——Python爬虫分析马蜂窝十一假期城市旅游数据相关推荐

  1. Python爬取马蜂窝-推荐小众城市旅游及爬取某一城市的景点信息和游记信息

    目的: 推荐小众城市旅游及爬取某一城市的景点信息和游记信息. 第一部分 首先从目的地页面获得各省专属5位数字编号,之后进入各省城市列表获得热门城市专属5位数字编号. 1.获得直辖市编号和热门省编号,h ...

  2. Python爬虫可视化第1季-城市旅游数据分析

    前言: 本着跟大家一同探讨学习的态度,今后几期文章会更新一些用python实现爬虫&可视化的文章.Python对于本人来讲也是一个在逐渐学习掌握的过程,这次的内容就从旅游开始讲起,进入正文前首 ...

  3. 使用python爬虫分析去哪网的景点数据

    数据爬取 爬取景点的名称,热度和门票价格,并将数据存储在scenery.csv文件中 import requests from bs4 import BeautifulSoup # 正则表达式 imp ...

  4. 告诉你那里最受欢迎,python爬取全国13个城市旅游数据

    前言 文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. PS:如有需要Python学习资料的小伙伴可以加点击下方链接自行获取http ...

  5. python爬取全国13个城市旅游数据,告诉你那里最受欢迎

    抓取数据 通过请求https://piao.qunar.com/ticket/list.htm?keyword=北京,获取北京地区热门景区信息,再通过BeautifulSoup去分析提取出我们需要的信 ...

  6. ❤️大佬都在学什么?Python爬虫分析C站大佬收藏夹,跟着大佬一起学, 你就是下一个大佬❤️!

    ❤️大佬都在学什么?Python爬虫分析C站大佬收藏夹,跟着大佬一起学,你就是下一个大佬❤️! 前言 程序说明 数据爬取 获取 CSDN 作者总榜数据 获取收藏夹列表 获取收藏数据 爬虫程序完整代码 ...

  7. Python 爬虫分析豆瓣 TOP250 之 信息字典 和 马斯洛的锥子

    问题 本文是对<Python 爬虫分析豆瓣 TOP250 告诉你程序员业余该看什么书?> 一文的补充 我们以<追风少年>为例 用chrome的developer tool查看源 ...

  8. 手把手教你利用 python 爬虫分析基金、股票

    手把手教你利用 python 爬虫分析基金.股票 文章目录 手把手教你利用 python 爬虫分析基金.股票 第一步:基金数据爬取 第二步:股票增持计算 第三步:好股基金选取 桌面程序 exe 从前大 ...

  9. Python爬虫学习第十一天---pymongo模块使用

    Python爬虫学习第十一天-pymongo模块使用 一.安装pymongo模块 python3 -m pip install pymongo 二.pymongo模块的使用 1.配置基础项 user ...

最新文章

  1. “allegro中焊盘的设置”收藏
  2. 几个不错的java类、jar包及其依赖查找网站。。。
  3. AliOS Things KV组件的写平衡特性
  4. 机器学习公开课笔记(1):机器学习简介及一元线性回归
  5. hadoop之 Hadoop2.2.0中HDFS的高可用性实现原理
  6. 更换 PVE7 软件仓库源和 CT 模板(LXC)源为国内源
  7. wmic cpu get processorid获取的都一样_DJL 之 Java 玩转多维数组,就像 NumPy 一样
  8. 绝地求生服务器维护6.28,绝地求生6月28号更新完怎么进不去 绝地求生更新维护到几点6.28...
  9. linux ar3012蓝牙驱动,佳能 Bluetooth AR3012 驱动程序下载-更新佳能软件(蓝牙)
  10. Xilinx FPGA 将寄存器放入IOB中
  11. 学会爬虫不用再收藏了,直接把网站拍照留念
  12. Yolov5—实现目标检测(win10)
  13. hackerrank初级篇之Mini-Max Sum
  14. 圆形标定板_自己改的,圆形标定板,opencv标定代码
  15. Win10-更改c盘下的用户文件夹名[转]
  16. BAT文件的编写及使用
  17. 腾讯云数据库联手宇信科技发布联合方案,全面助力金融科技安全可控
  18. 【投稿】海思手撕代码之_RR_arbiter
  19. 东华大学计算机蔡博士,蔡雅琦博士为信息学院学生做“大学生人际关系”讲座...
  20. 安装keil5出现you are not logged in as an 'Administrator'

热门文章

  1. android 烟雾动画,android使用粒子动画实现炊烟袅袅的效果
  2. 神仙级Python办公自动化教程(非常详细),从零基础入门到精通,轻松玩转Excel,从看这篇开始
  3. iOS大小写字符串的转化
  4. 计算机仿真技术教学大纲,《计算机仿真技术》教学大纲
  5. 修改文件属性chmod,chown,utime,truncate
  6. 2022-7-29 第八组wly 异常处理
  7. 这几种下属会被领导喜欢
  8. 《网络攻防》第6周作业
  9. Creo 钣金设计视频教程
  10. Directx12 Spec 总目录