Python爬虫实战:两点间的真实行车时间与路况分析(上)

本文来源于公众号【程序猿声】,作者向柯玮

前言

大家好,我又又来来来来了!在这里先祝大家身体健康,天天开心!

虽然放假,在家里小玮同学也没有休息,这一次给大家带来的是利用爬虫爬取地图软件的相关数据,并制作成图表进行分析。

为什么突然想做一期关于爬虫的内容呢?其实是因为前段时间收到老师的任务,研究一下现实中两点之间的旅行时间是否受出发时间的影响。

这个题目可把当时的小玮吓坏了--python我都还没有开始学习呢--咋就叫我做这么有难度的事情。

看了几天的python基础知识,了解了爬虫的相关知识,最终还是勉勉强强地完成了任务,现在把这段时间的体会写出来,让各位看客老爷们检查。

Python的基本语法内容呢,在这里就不多说了。

因为在本次爬取数据的过程中,我们用的和python相关的知识并不是很复杂,不需要给大家介绍别的东西,大家完全可以在具体的过程中就可以学会本次爬取需要的东西。

鉴于整个流程涉及到的知识很广我们分成三篇推文来讲解,本篇推文的内容是《数据爬取》

目录

  • 问题的分析

  • 简单的准备

  • 寻找高校

  • 获取相应地点的坐标

  • 制作excel表格

  • 相应时间的获取

  • 开始我们的工作

  • 进入目标网页

  • 爬取目标内容

  • 定时操作

  • 小小的总结

问题的分析

Q:现实中两点的旅行时间是否受到出发时间的影响呢?这是什么意思呢,因为每个时间段的路况不同,比如早高峰晚高峰等等,两点之间的实际旅行时间就有可能受到出发时间的影响。

好了,现在问题清楚了。下面我们选取武汉的一些高校作为测试点,给大家演示如何提取相应的数据进行分析。(武汉快点好起来呀!小编好想去上学!)

首先我们需要关注的点有以下几个:

  • 武汉著名的高校包括哪些大学
  • 旅行的出发点和终点的坐标
  • 旅行的出发时间,旅行所用时间
  • 如何对所收集的数据进行可视化处理
  • 如何对数据进行分析

简单的准备

寻找高校

寻找高校这个步骤很简单,在这里我是直接通过百度获取的。

获取相应地点的坐标

获取比如说通过某某路段的时间,某某点的坐标,我们通常是进入百度地图官网为开发者提供API服务。百度开发者平台的账号注册,创建应用等等操作在这里就不多说了。

在这里指出我们需要注意的一个地方,在请求验证方式这个地方,要记住使用IP白名单,然后下面推荐填0.0.0.0/0,具体的原因会在后面给出。

完成了这个步骤之后,我们就可以在开发文档里选择坐标选取器。获取我们目标点的坐标。

进入之后搜索相应的地点就可以知道其坐标。这里将我找到我坐标放在下面。

制作excel表格

为了方便我们对数据进行处理,我们选择将数据存入到excel表格之中。

相应时间的获取

坐标获取好了之后,我们还需要回到开发文档,再选取Web服务API,进入后再选择批量算路服务。通过这一项服务,我们可以获得目标路段当前时刻下的指定交通方式所花费的时间。

进入了以后,就可以看到这一项服务明确的要求了要使用IP白名单检验,这也就是为什么我们在创建应用的时候设置IP白名单检验。

在简介中也给出了我们能够通过坐标获取两点之间的距离,行车,步行以及骑行所需要的时间,这个是实时的,会结合实时的交通状况。

在服务指南中,详细地给出了我们想要获得目标内容的方法。

在这里简单的解释一下为什么无论起点坐标还是终点坐标都是两个坐标。其实很好理解。

因为在正常情况下一个地点他不会是一个点,而是一块,而两个点刚好就可以构成一个矩形了。

但是在我们这里为了简化操作,地点就简单地认为只有一点,这是一种简化哈,大家在实际复现的时候建议弄两个点。所以我们这次的爬取URL的模式如下。

URL=http://api.map.baidu.com/routematrix/v2/交通方式?output=json&origins=起点坐标(先纬度再经度)&destinations=终点坐标&ak=你的AK值。

我们现在可以把我们搜索到的点的坐标按照上述样式改一下URL,然后进入这个网页,看看成不成功。如果出现了下面的画面就说明成功了。

开始我们的工作

做好了前期的准备工作,我们现在正式进入主题。

进入目标网页

在这个部分,我们会用到一些模块,在这里先拿出来,介绍一下相应的作用。

import requests

第一个模块顾名思义,就是请求的意思,那么对于我们来说有什么用呢?别急,我们来分析分析,我们进入一个网页的过程。

我们打开浏览器,然后输入网址,然后看到我们需要的内容是吧?

那么你有没有想过我们为什么需要通过浏览器去访问我们的网页呢?

原因很简单,其实就是我们需要浏览器代表我们发送一个请求给我们的URL,然后从URL的服务器再把我们想要的内容反馈给我们,然后我们才能看到。

在这个过程中,服务器还给我们一个header,简单的来说就是一个身份证,说明我们是通过合法途径的进入你的网页的,并不是通过非法的途径。

分析到这里,小伙伴一定有疑惑,那我们通过requests的时候,怎么证明我们是合法途径呢?

那当然是加上一个headers啦。在自己的浏览器中输入about:version。会出现如图所示的画面。

我们就可以发现headers就在这里。下面我们尝试着通过request来进行一下自动进入网页。

url=xxxx
header=xxxx
html=requests.get(url,headers=header).text

这段代码的主要内容在之前已经说了,这里讲解一下为什么要加入.text

其实就是获取网页中的除了标签以外的内容,因为有可能网站里面还有其他的标签一样的东西,这是构造这个网页是加入的,但是我们并不需要。

大家可以尝试,运行这段代码并输出html,可以看到下面的东西:

到这里为止,我们已经成功地利用程序进入了目标网页。

爬取目标内容

import pandas as pd
import re

解释一下我们当前添加的模块。

pandas是一种数组,在这里,我们为什么不使用内置的数组呢?简单的理解就是pandas数组比内置的数组运行速度更快,而且方便我们对文件进行读取。

re是一种切割文本的工具,在这里其实如果了解正则表达式的伙伴们应该认识,这个其实就是正则表达式的记号。

现在让我们再分析一下,我们从网页中获得的东西,是一长串字符串吧?我们需要什么?只需要里面的极少数的字符吧?其他的我们都不想要。那么我们应该怎么做?

是不是应该对字符串进行切割,对的,在这里我们就可以用re模块进行切割。这个函数的基本形式是re.split([分隔符],分割的字符串)

通过对我们所获得的字符串进行观察,找出应该分割的地方的分隔符号,就可以对字符串进行分割。最终结果如下图。

容易看出,我们需要的内容所在的下标为19,33。在这里位置为止,我们的工作看似已经完成了,但是我们只是把当前这一段路程的路程和时间记录下来了,还有别的呢?这个时候,我们的pandas数组就出现了。

在刚开始的时候,我们就已经把坐标和地址都存到了一个excel文件当中去大家应该都还记得吧。

那么我们现在的重点就是围绕这个excel文件展开的。既然我们需要这个excel文件中的东西,那么首先我们需要读取这个excel文件。如何读取呢?这里先放出代码。

path_data=pd.read_excel(r'F:\my python\数据\waypath.xlsx')
head=path_data['head']
tail=path_data['tail']
position=path_data['position']

如上图所示,上面就是pandas读取文件的操作。容易看出,第一段代码就是读取csv文件并存储起来。

括号里存放的是我们文件所在的地址,记住一定要在后面加上文件自身的属性,即加上xlsx,这是为了避免在这个地址下存在两个同名但属性不同的文件的矛盾问题。

由于python的强大,读取csv文件是按照字典形式存储,后面的head,tail,position就是相应的索引。要注意!前面的r是不可以省略的,因为它是说明在这一行里面出现的\都不是转义符号。

在这里我们已经完成了存储操作,伙伴们可以print一下path_data,看看里面的内容。

在这里我们可以发现,python中存储数据也是从index为0开始。现在我们已经完成了所有地点和坐标的存储,下面就是循环进行内容的获取和存储的过程了。

在这里我们的数据的最后一个下标是27,那么就意味着我们需要循环的次数为28,那么怎么进行这个循环呢?Python中给出了一个非常简单的方式,如下。

for i in range(28):

这个位置的意思是,依次生成0-27的整数,然后赋给i,这样i在每次循环中对应的值都是相应的次数,基于这个,我们就可以知道后面的循环函数怎么写了。

for i in range(28):    
  url='http://api.map.baidu.com/routematrix/v2/driving?output=json&origins={}&destinations={}&ak=S0LC4C1KdAOVGPLcbzlBGL7bLfGz5G1c'.format(str(head[i]),str(tail[i]))   
  html=requests.get(url,headers=header).text    
  html=re.split('[:",}]',html)    
  if i==0:       
    dict_data={'position':[position[i]],'distance':[html[19]],'time':[html[33]]}   
    data=pd.DataFrame(dict_data,columns=['position','distance','time'])   
  else:       
    dict_data =pd.DataFrame({'position': [position[i]], 'distance': [html[19]], 'time': [html[33]]})      
    data=data.append(dict_data,ignore_index=True)
data.to_csv('path_data.csv')

看到这个代码,一定很蒙,这都写了些啥啊,咋看不懂?不急,我们一步一步分析。首先是我们对于url的改写,我们把原来存放起点坐标和终点坐标的位置改为了{},后面加上了

.format(str(head[i]),str(tail[i]))

这是为什么呢?其实大家从上面读到这里看到代码一定知道这个是为了什么,对,就是为了更新每一次的地址,使她成为excel文件中相应的地址,那么这里{}就和后面的format中的内容进行对应。

format具体的用法在这里就不多说了。看客老爷们如果感兴趣可以去查一查,在这里,大家只需要了解是替换相应位置内容就可以了。

那么后面我为什么要用if做判断呢?这其实是为了区分当前这个循环是建立一个类似excel一样的变量还是给这个变量里面进行元素添加。I=0时,当然是建立这个变量,I>0时就是添加元素。

在这里呢,重点讲解一下下面这一行。pd.DataFrame其实是一个强制转换类型的函数,把刚开始的dict_data转换成DataFrame类型的,为什么要转换呢?转换了有什么用呢?我们转换了其实是为了使用DataFrame类型所特有的一个函数,to_csv,生成csv文件的函数。

那么后面的.append()函数大家肯定就明白了,columns是做什么的呢?仔细一看可以发现这个其实和我们DataFrame最开始设的几个索引值是一样的,是的。

我们之所以在后面写这个是为了给dataframe进行一个排序,这样在输出这个data的时候她输出的顺序就是colunms里的顺序。

在最后一行,意思已经很清楚了,是生成这个csv文件,然后前面patn_data是文件的名字,.csv是文件的属性。

data=pd.DataFrame(dict_data,columns=['position','distance','time'])

定时操作

到这个位置,其实现在我们已经很好地完成了这一次的爬取任务,回到我们的文件夹中,你就可以看到生成的最终csv文件了。但是呢,作为一次数据分析,那么仅仅统计当前这一次的数据肯定是不够的。

我们还需要统计很多次来求取平均值。但是我们又不可能看着一个时间就去点一下运行程序,这肯定是不聪明的做法。那么什么是聪明的做法呢?当然是用python自带的函数来做了。这个时候需要添加一个模块。

from threading import Timer

这个模块就是计时器,为了我们定时运行程序所用的。

t = Timer(10, search)t.start()

这个函数的具体用法就是Timer(1,2),在1的位置,你需要填写的是你想程序在多久后运行,2的位置为相应的程序,即函数。

t.start()就是计时器开始运行。那么如果我们想要程序规定次数定时的多次运行,我们可以在在相应的函数中放置一个这个Timer函数,进行多次运行。

小小的总结

好了,本次推文中,着重给大家介绍了如何获取数据,做成csv文件的相关操作。在最后Timer的位置没有详细的讲解,希望大家通过代码进一步了解!

在下篇推文中,我们会着重讲述如何建立可视化的曲线。让我们下次再见!

最终的代码可以在后台留言 PC01即可获得

posted @ 2020-04-10 13:11  短短的路走走停停  阅读(1874)  评论(3编辑  收藏  举报