手把手教你用Python抓取热门景点热力图!(附代码)

简介:

国庆倒计时1天,我们即将迎来8天的小长假,相信很多小伙伴们已经提前规划国庆去哪儿?你是选择去人最少的单位加班呢?还是选择人山人海的景点观光?


如果去人最少的单位加班,一定要记得告知老板,以望升职加薪走上人生巅峰;


如果选择人山人海的景点,一定要提前查看攻略,比如下文中使用 Python 技术抓取热门景点的热力图。


金秋九月,丹桂飘香,在这秋高气爽,阳光灿烂的收获季节里,我们送走了一个个暑假余额耗尽哭着走向校园的孩子们,又即将迎来一年一度伟大祖国母亲的生日趴体(无心上班,迫不及待想为祖国母亲庆生)。


640?wx_fmt=jpeg&wxfrom=5&wx_lazy=1


那么问题来了,去哪儿玩呢?


百度输了个“国庆”,出来的第一条居然是“国庆去哪里旅游人少”。


640?wx_fmt=png&wxfrom=5&wx_lazy=1


于是我想到可否通过旅游网站的景点销量来判断近期各景点流量情况呢?本文按去哪儿网景点页面,得到景点的信息。


1.百度的地图API和echarts


本次主要抓取的内容是数据,因此我决定用图表来输出抓取的数据,也就意味着我要用爬取的景点销量以及景点的具体位置来生成一些可视化数据。


在这里使用的是百度的地图API和echarts,前者是专门提供地图API的工具,后者是数据处理居家旅行的好伙伴。


那么API是什么?API是应用程序的编程接口,就好像插头与插座一样,我们的程序需要电,插座中提供了电,我们只需要在程序中写一个与插座匹配的插头接口,就可以使用电来做我们想做的事情,而不需要知道电是如何产生的。


640?wx_fmt=png&wxfrom=5&wx_lazy=1

引入数据后的百度热力图


而具体流程如下,好比出书的过程,想要将完结的小说出书,首先要通过出版社的出版服务,提供正文内容和封面设计图,将保存好的 word 文本和封面图发给出版社,由此得到一本书。在此过程中,并不需要了解出版社印刷、装订的过程。


640?wx_fmt=png&wxfrom=5&wx_lazy=1

通过API对接的开发者与服务商


2.确定输出文件


百度地图提供了很多API使用示例,有HTML基础,有JS基础就可以尝试改函数了。仔细观察源代码,可以知道热力图的生成主要的数据都存放在points这个变量中。


640?wx_fmt=png&wxfrom=5&wx_lazy=1


这种[{x:x,x:x},{x:x,x:x}]格式的数据,是一种json格式的数据,由于具有自我描述性,所以比较通俗易懂,大概可以知道这里的三个值,前俩个是经纬度,最后一个应该是权重。


也就是说,如果我希望将景点的热门程度生成为热力图,我需要得到景点的经纬度,以及它的权重,景点的销量可以作为权重,并且这个数据应该是json格式的呈现方式。echarts也是一样的。


3.爬取数据


其实这次的爬虫部分是比较简单的。


分析网址(去哪儿景点)→爬取分页中信息(景点经纬度、销量)→转为json文件。


分析去哪儿景点页的网址可得出结构:<http://piao.qunar.com/ticket/list.htm?keyword=搜索地点&region=&from=mpl_search_suggest&page=页数>


这次没有用正则来匹配内容,而使用了xpath匹配。


def getList():

    place = raw_input('请输入想搜索的区域、类型(如北京、热门景点等):')

    url = 'http://piao.qunar.com/ticket/list.htm?keyword='+ str(place) 


def getList():

    place = raw_input('请输入想搜索的区域、类型(如北京、热门景点等):')

    url = 'http://piao.qunar.com/ticket/list.htm?keyword='+ str(place) +'&region=&from=mpl_search_suggest&page={}'

    i = 1

    sightlist = []

    while i:

        page = getPage(url.format(i))

        selector = etree.HTML(page)

        print '正在爬取第' + str(i) + '页景点信息'

        i+=1

        informations = selector.xpath('//div[@class="result_list"]/div')

        for inf in informations: #获取必要信息

            sight_name = inf.xpath('./div/div/h3/a/text()')[0]

            sight_level = inf.xpath('.//span[@class="level"]/text()')

            if len(sight_level):

                sight_level = sight_level[0].replace('景区','')

            else:

                sight_level = 0

            sight_area = inf.xpath('.//span[@class="area"]/a/text()')[0]

            sight_hot = inf.xpath('.//span[@class="product_star_level"]//span/text()')[0].replace('热度 ','')

            sight_add = inf.xpath('.//p[@class="address color999"]/span/text()')[0]

            sight_add = re.sub('地址:|(.*?)|\(.*?\)|,.*?$|\/.*?$','',str(sight_add))

            sight_slogen = inf.xpath('.//div[@class="intro color999"]/text()')[0]

            sight_price = inf.xpath('.//span[@class="sight_item_price"]/em/text()')

            if len(sight_price):

                sight_price = sight_price[0]

            else:

                i = 0

                break

            sight_soldnum = inf.xpath('.//span[@class="hot_num"]/text()')[0]

            sight_url = inf.xpath('.//h3/a[@class="name"]/@href')[0]

            sightlist.append([sight_name,sight_level,sight_area,float(sight_price),int(sight_soldnum),float(sight_hot),sight_add.replace('地址:',''),sight_slogen,sight_url])

        time.sleep(3)

    return sightlist,place


  • 这里把每个景点的所有信息都抓取下来。

  • 使用了while循环,for循环的break的方式是发现无销量时给i值赋零,这样while循环也会同时结束。

  • 地址的匹配使用re.sub()函数去除了n多复杂信息,这点后面解释。


4.输出本地文本


为了防止代码运行错误,为了维护代码运行的和平,将输出的信息列表存入到excel文件中了,方便日后查阅,很简单的代码,需要了解pandas的用法。


def listToExcel(list,name):

    df = pd.DataFrame(list,columns=['景点名称','级别','所在区域','起步价','销售量','热度','地址','标语','详情网址'])

    df.to_excel(name + '景点信息.xlsx')


5.百度经纬度API


百度经纬度API网址:http://api.map.baidu.com/geocoder/v2/?address=地址&output=json&ak=百度密钥,修改网址里的“地址”和“百度密钥”,在浏览器打开,就可以看到经纬度的json信息。


#上海市东方明珠的经纬度信息

{"status":0,"result":{"location":{"lng":121.5064701060957,"lat":31.245341811634675},"precise":1,"confidence":70,"level":"UNKNOWN"}}


这样我就可以根据爬到的景点地址,查到对应的经纬度!python获取经纬度json数据的代码如下。

def getBaiduGeo(sightlist,name):

    ak = '密钥'

    headers = {

    'User-Agent' :'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36'

    }

    address = 地址

    url = 'http://api.map.baidu.com/geocoder/v2/?address=' + address  + '&output=json&ak=' + ak

    json_data = requests.get(url = url).json()

    json_geo = json_data['result']['location']


观察获取的json文件,location中的数据和百度api所需要的json格式基本是一样,还需要将景点销量加入到json文件中,这里可以了解一下json的浅拷贝和深拷贝知识,最后将整理好的json文件输出到本地文件中。

def getBaiduGeo(sightlist,name):

    ak = '密钥'

    headers = {

    'User-Agent' :'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36'

    }

    list = sightlist

    bjsonlist = []

    ejsonlist1 = []

    ejsonlist2 = []

    num = 1

    for l in list:

        try:

            try:

                try:

                    address = l[6]

                    url = 'http://api.map.baidu.com/geocoder/v2/?address=' + address  + '&output=json&ak=' + ak

                    json_data = requests.get(url = url).json()

                    json_geo = json_data['result']['location']

                except KeyError,e:

                    address = l[0]

                    url = 'http://api.map.baidu.com/geocoder/v2/?address=' + address  + '&output=json&ak=' + ak

                    json_data = requests.get(url = url).json()

                    json_geo = json_data['result']['location']

            except KeyError,e:

                    address = l[2]

                    url = 'http://api.map.baidu.com/geocoder/v2/?address=' + address  + '&output=json&ak=' + ak

                    json_data = requests.get(url = url).json()

                    json_geo = json_data['result']['location']

        except KeyError,e:

            continue

        json_geo['count'] = l[4]/100

        bjsonlist.append(json_geo)

        ejson1 = {l[0] : [json_geo['lng'],json_geo['lat']]}

        ejsonlist1 = dict(ejsonlist1,**ejson1)

        ejson2 = {'name' : l[0],'value' : l[4]/100}

        ejsonlist2.append(ejson2)

        print '正在生成第' + str(num) + '个景点的经纬度'

        num +=1

    bjsonlist =json.dumps(bjsonlist)

    ejsonlist1 = json.dumps(ejsonlist1,ensure_ascii=False)

    ejsonlist2 = json.dumps(ejsonlist2,ensure_ascii=False)

    with open('./points.json',"w") as f:

        f.write(bjsonlist)

    with open('./geoCoordMap.json',"w") as f:

        f.write(ejsonlist1)

    with open('./data.json',"w") as f:

        f.write(ejsonlist2)


在设置获取经纬度的地址时,为了匹配到更准确的经纬度,我选择了匹配景点地址,然而,景点地址里有各种神奇的地址,因此有了第三部门中去除复杂的信息。


然而,就算去掉了复杂信息,还有一些匹配不到的景点地址,于是我使用了嵌套try,如果景点地址匹配不到;就匹配景点名称,如果景点名称匹配不到;就匹配景点所在区域,如果依然匹配不到,那就跳过。


这里生成的三个json文件,一个是给百度地图api引入用的,另俩个是给echarts引入用的。


6.网页读取json文件


将第二章中所述的百度地图api示例中的源代码复制到解释器中,添加密钥,保存为html文件,打开就可以看到和官网上一样的显示效果。echarts需要在实例页面,点击页面右上角的EN切换到英文版,然后点击download demo下载完整源代码。


根据html导入json文件修改网页源码,导入json文件。


#百度地图api示例代码中各位置修改部分

<head>

    <script src="http://libs.baidu.com/jquery/2.0.0/jquery.js"></script>

</head>

<script type="text/javascript">

    $.getJSON("points.json", function(data){

        var points = data;

        script中原有函数;

        });

</script>       


这里使用了jQuery之后,即使网页调试成功了,在本地打开也无法显示网页了,在chrome中右键检查,发现报错提示是需要在服务器上显示。


在本地创建一个服务器,在终端进入到html文件所在文件夹,输入python -m SimpleHTTPServer,再在浏览器中打开http://127.0.0.1:8000/,记得要将html文件名设置成index.html哦~


gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAA


7.总结


因为注册但没有认证开发者账号,所以每天只能获取6K个经纬度API,所以我选择了热门景点中前400页(每页15个)的景点,结果可想而知。为了调试因为数据增多出现的额外bug,最终的获取的景点数据大概在4.5千条左右(爬取时间为2017年09月10日,爬取关键词:热门景点,仅代表当时销量)。


640?wx_fmt=png&wxfrom=5&wx_lazy=1

热门景点热力图


640?wx_fmt=png&wxfrom=5&wx_lazy=1

热门景点示意图


这些地图上很火爆的区域,我想在国庆大概是这样的


640?wx_fmt=jpeg&wxfrom=5&wx_lazy=1


这样的


640?wx_fmt=jpeg&wxfrom=5&wx_lazy=1


还有这样的


640?wx_fmt=jpeg&wxfrom=5&wx_lazy=1


将地图上热门景点的销量Top20提取出来,大多数都是耳熟能详的地点,帝都的故宫排在了第一位,四川则占据了Top5中的三位,而排在Top20中四川省就占了6位,如果不是因为地震,我想还会有更多的火爆的景点进入排行榜的。这样看来如果你这次国庆打算去四川的话,可以脑补到的场景就是:人人人人人人人人人……


640?wx_fmt=png&wxfrom=5&wx_lazy=1

热门景点销量top20


于是我又做了一个各城市包含热门景点数目的排行,没想到在4千多个热门景点中,数目最多的竟是浙江,是第二个城市的1.5倍,而北京作为首都位居第二。


640?wx_fmt=png&wxfrom=5&wx_lazy=1

主要城市热门景点数


这些城市有那么多热门景点,都是些什么级别的景点呢?由下图看来,各城市的各级别景点基本与城市总热门景点呈正相关,而且主要由4A景区贡献而来。


640?wx_fmt=png&wxfrom=5&wx_lazy=1

主要城市热门景点级别


既然去哪些地方人多,去哪里景多都已经知道了,那再看看去哪些地方烧得钱最多吧?下图是由各城市景点销售起步价的最大值-最小值扇形组成的圆,其中湖北以单景点销售起步价600占据首位,但也可以看到,湖北的景点销售均价并不高(在红色扇形中的藏蓝色线条)。而如果国庆去香港玩,请做好钱包减肥的心理和生理准备。


640?wx_fmt=png&wxfrom=5&wx_lazy=1

各省旅游景点销售起步价


到这里已经分析完啦,最后祝大家国庆和中秋快乐!


原文发布时间为:2017-09-30

本文来自云栖社区合作伙伴“数据派THU”,了解相关信息可以关注“数据派THU”微信公众号


相关文章
|
2月前
|
Python
"揭秘!Python如何运用神秘的正则表达式,轻松穿梭于网页迷宫,一键抓取隐藏链接?"
【8月更文挑战第21天】Python凭借其强大的编程能力,在数据抓取和网页解析领域表现出高效与灵活。通过结合requests库进行网页请求及正则表达式进行复杂文本模式匹配,可轻松提取网页信息。本示例展示如何使用Python和正则表达式解析网页链接。首先确保已安装requests库,可通过`pip install requests`安装。接着,利用requests获取网页内容,并使用正则表达式提取所有`&lt;a&gt;`标签的`href`属性。
32 0
|
11天前
|
数据采集 存储 JavaScript
构建您的第一个Python网络爬虫:抓取、解析与存储数据
【9月更文挑战第24天】在数字时代,数据是新的金矿。本文将引导您使用Python编写一个简单的网络爬虫,从互联网上自动抓取信息。我们将介绍如何使用requests库获取网页内容,BeautifulSoup进行HTML解析,以及如何将数据存储到文件或数据库中。无论您是数据分析师、研究人员还是对编程感兴趣的新手,这篇文章都将为您提供一个实用的入门指南。拿起键盘,让我们开始挖掘互联网的宝藏吧!
|
2月前
|
搜索推荐 前端开发 数据可视化
基于Python协同过滤的旅游景点推荐系统,采用Django框架,MySQL数据存储,Bootstrap前端,echarts可视化实现
本文介绍了一个基于Python协同过滤算法的旅游景点推荐系统,该系统采用Django框架、MySQL数据库、Bootstrap前端和echarts数据可视化技术,旨在为用户提供个性化的旅游推荐服务,提升用户体验和旅游市场增长。
129 9
基于Python协同过滤的旅游景点推荐系统,采用Django框架,MySQL数据存储,Bootstrap前端,echarts可视化实现
|
2月前
|
数据采集 Python
如何用Python Selenium和WebDriver抓取LinkedIn数据并保存登录状态
本文介绍了使用Python Selenium和WebDriver库抓取LinkedIn数据的方法。首先,安装Selenium库和对应的WebDriver,然后配置爬虫代理IP以避免频繁请求被检测。接下来,设置user-agent和cookies以模拟真实用户行为,实现登录并保持状态。登录后,使用WebDriver抓取目标页面数据,如用户名、年龄、性别和简历信息。最后,强调了优化代码、处理异常和遵守使用条款的重要性,以提高效率并避免账号被封禁。
如何用Python Selenium和WebDriver抓取LinkedIn数据并保存登录状态
|
1月前
|
数据采集 JavaScript 前端开发
构建简易Python爬虫:抓取网页数据入门指南
【8月更文挑战第31天】在数字信息的时代,数据抓取成为获取网络资源的重要手段。本文将引导你通过Python编写一个简单的网页爬虫,从零基础到实现数据抓取的全过程。我们将一起探索如何利用Python的requests库进行网络请求,使用BeautifulSoup库解析HTML文档,并最终提取出有价值的数据。无论你是编程新手还是有一定基础的开发者,这篇文章都将为你打开数据抓取的大门。
|
2月前
|
Python
【python】python抓取古诗文内容保存(源码)【独一无二】
【python】python抓取古诗文内容保存(源码)【独一无二】
|
2月前
|
数据采集 JavaScript 前端开发
构建你的第一个Python爬虫:抓取网页数据入门指南
【8月更文挑战第31天】在数字时代,数据是新的石油。本文将引导初学者通过简单的步骤,使用Python编程语言创建一个基础的网络爬虫程序。我们将探索如何从网络上提取信息,并理解背后的原理。无论你是编程新手还是想要扩展你的技术工具箱,这篇文章都将为你提供一条清晰的道路,让你学会编写能够自动获取网络数据的脚本。准备好开始你的网络数据抓取之旅了吗?让我们现在就开始吧!
|
2月前
|
数据采集 JavaScript 前端开发
Python 爬虫实战:抓取和解析网页数据
【8月更文挑战第31天】本文将引导你通过Python编写一个简单的网络爬虫,从网页中抓取并解析数据。我们将使用requests库获取网页内容,然后利用BeautifulSoup进行解析。通过本教程,你不仅能够学习到如何自动化地从网站收集信息,还能理解数据处理的基本概念。无论你是编程新手还是希望扩展你的技术工具箱,这篇文章都将为你提供有价值的见解。
|
2月前
|
数据采集 存储 JavaScript
构建你的首个Python网络爬虫:抓取、解析与存储数据
【8月更文挑战第31天】在数字时代的浪潮中,数据成为了新的石油。了解如何从互联网的海洋中提取有价值的信息,是每个技术爱好者的必备技能。本文将引导你通过Python编程语言,利用其强大的库支持,一步步构建出你自己的网络爬虫。我们将探索网页请求、内容解析和数据存储等关键环节,并附上代码示例,让你轻松入门网络数据采集的世界。
|
2月前
|
机器学习/深度学习 自然语言处理 算法
基于python旅游景点满意度分析设计与实现
本文介绍了一个基于Python的情感分析系统,旨在通过CNN算法、LDA主题模型和jieba分词等自然语言处理技术,对海口市旅游景点的网络评论进行满意度分析,以客观评估和提升游客体验及景点服务质量。
下一篇
无影云桌面