编程语言
首页 > 编程语言> > 坐地铁不知道到哪里能转线?我用Python把地铁路线爬下来了!

坐地铁不知道到哪里能转线?我用Python把地铁路线爬下来了!

作者:互联网

前言

 

爬虫是一段定向抓取相关网页资源的程序或脚本,Python爬虫是用Python编程语言实现的网络爬虫,相较于其他语言,Python内的大量内置包可以轻松实现网络爬虫功能。

 

 

 

 

 

 

 

 

 

本期聚焦

▶  BeautifulSoup(bs4)库介绍

▶  find()、find_all()函数介绍

▶  实战代码Part1——地铁线路网址的获取

▶  实战代码Part2——具体线路下线路数据的获取

▶  实战代码Part3——整合数据

BeautifulSoup(bs4)库介绍

 

 

 

 

BeautifulSoup:“美味的汤,绿色的浓汤”,是一个可以从HTML或XML文件中提取数据的Python库。BeautifulSoup提供一些简单的、python式的函数用来处理导航、搜索、修改分析树等功能。它是一个工具箱,通过解析文档为用户提供需要抓取的数据,因为简单,所以不需要多少代码就可以写出一个完整的应用程序。

BeautifulSoup自动将输入文档转换为Unicode编码,输出文档转换为utf-8编码。你不需要考虑编码方式,除非文档没有指定一个编码方式,这时,BeautifulSoup就不能自动识别编码方式了。然后,你仅仅需要说明一下原始编码方式就可以了。

安装BeautifulSoup

BeautifulSoup3目前已经停止开发,推荐在现在的项目中使用BeautifulSoup4,不过它已经被移植到BS4了,也就是说导入时我们需要import bs4。所以这里我们用的版本是BeautifulSoup4.3.2(简称BS4)。

可以直接使用pip安装:

pip install BeautifulSoup

 

BeautifulSoup支持Python标准库中的HTML解析器,还支持一些第三方的解析器,如,lxml,XML,html5lib等,但是需要安装相应的库:

pip install lxml

 

如果我们不安装它,则Python会使用Python默认的解析器,lxml解析器更加强大,速度更快,推荐安装。

find()、find_all()函数介绍

BeautifulSoup的find()和find_all()是搜索文档时常用的函数,它们的入参称为过滤器。一般的过滤器有以下几种:字符串,正则表达式,列表,布尔值以及函数。不同的参数过滤可以应用到以下情况:基于name参数查找标签、基于text参数查找文本、基于attrs参数查找标签的属性、基于正则表达式的查找和基于函数的查找。

 

 

 

 

BeautifulSoup主要用来遍历子节点及子节点的属性,通过点取属性的方式只能获得当前文档中的第一个tag。find_all()方法搜索当前tag的所有tag子节点,并判断是否符合过滤器的条件,返回文档中符合条件的所有tag。而当文档中只有一个<body>标签,那么使用find_all()方法来查找<body>标签就不太合适,使用find_all方法并设置limit=1参数不如直接使用find()方法。两者唯一的区别是find_all()方法的返回结果是值包含一个元素的列表,而find()方法直接返回结果

以下是下文实例中将会出现的通过find()方法的attrs 参数定义一个字典参数来搜索包含特殊属性的tag:

soup = BeautifulSoup(response.content, 'lxml').find(attrs={'class': 'fs-fdLink'})routes = soup.find('tr').find('td').findAll('a')

 

接下来我们以爬取8684网站上的深圳地铁线路数据为例来进行爬虫实战。

 

 

 

 

实战代码Part1——地铁线路网址的获取

首先导入库bs4、lxml、requests:

import requestsimport jsonfrom bs4 import BeautifulSoupimport lxml.html

 

获取地铁线路网址

etree = lxml.html.etreedef get_urls():    url = 'https://dt.8684.cn/so.php?k=pp&dtcity=sz&q=wedwed'    response = requests.get(url=url)    soup = BeautifulSoup(response.content, 'lxml').find(attrs={'class': 'fs-fdLink'})    routes = soup.find('tr').find('td').findAll('a')# 查找所有有关的节点    route_list = []    for i in routes:        per = {}        per['key'] = i.string        per['value'] = 'https://dt.8684.cn' + i.get('href')        route_list.append(per)    return route_list

 

其中,

soup = BeautifulSoup(response.content, 'lxml')

 

为创建BeautifulSoup对象,其意义是将发送网络请求返回的响应数据创建为soup对象,数据格式为lxml。

实战代码Part2——具体线路下线路数据的获取

def get_schedule(url):    response = requests.get(url['value'])    soup = BeautifulSoup(response.content, 'lxml').find(attrs={'class': 'ib-mn'})    table_head = soup.find(attrs={'class': 'pi-table tl-table'})    per_info = table_head.findAll('tr')    route_list = []    if (url['key'].find('内圈') == -1 and url['key'].find('外圈') == -1):#地铁线路名称既无内环也无外环        route_info = {} #定义地铁内环字典        route_info_wai = {}#定义地铁外环字典        stations_nei = [] #定义地铁内环站台列表        route_info['name'] = url['key'] + '内环'#定义内环线路字典name键的值        route_info_wai['name'] = url['key'] + '外环'# 定义外环线路字典name键的值        time_nei_1 = []#定义地铁内环发车时间列表        time_nei_2 = []#定义地铁内环收班时间列表        time_wai_1 = [] #定义地铁外环发车时间列表        time_wai_2 = []# 定义地铁外环收班时间列表        for i in per_info:            if (i != []):                j = i.findAll('td')                if (j != []):                    for k in j[0]:                        stations_nei.append(k.text)#内外环站点名                    for k in j[3]:                        time_nei_2.append(k)#内环收车时间                    for k in j[1]:                        time_nei_1.append(k)#内环发车时间                    for k in j[4]:                        time_wai_2.append(k) #外环收车时间                    for k in j[2]:                        time_wai_1.append(k)#外环发车时间        try:            if (time_nei_1[0] != '--' and time_nei_1[0] != '—'):                route_info['startTime'] = startTime = time_nei_1[0]#筛除地铁内环线路发车时间为空的数值            else:                route_info['startTime'] = time_nei_1[1]#定义地铁内环线路发车时间            if (time_nei_2[len(time_nei_2) - 1] != '--' and time_nei_2[len(time_nei_2) - 1] != '—'):                route_info['endTime'] = time_nei_2[len(time_nei_2) - 1]#筛除地铁内环线路收车时间为空的数值            else:                route_info['endTime'] = time_nei_2[len(time_nei_2) - 2]# 定义地铁内环线路收车时间            if (time_wai_1[len(time_wai_1) - 1] != '--' and time_wai_1[len(time_wai_1) - 1] != '—'):                route_info_wai['startTime'] = time_wai_1[len(time_wai_1) - 1]# 筛除地铁外环线路发车时间为空的数值            else:                route_info_wai['startTime'] = time_wai_1[len(time_wai_1) - 2]# 定义地铁外环线路发车时间            if (time_wai_2[0] != '--' and time_wai_2[0] != '—'):                route_info_wai['endTime'] = startTime = time_wai_2[0]# 筛除地铁外环线路收车时间为空的数值            else:                route_info_wai['endTime'] = time_wai_2[1]# 定义地铁外环线路收车时间        except IndexError as e:            route_info_wai['startTime'] = '06:00'            route_info_wai['endTime'] = '23:00'            route_info['startTime'] = '06:00'            route_info['endTime'] = '23:00'#若无法找到数据,则捕捉索引异常错误,并对运行时间赋默认值
        route_info['stations'] = stations_nei #内环线路字典stations值赋为内环站点名        route_info_wai['stations'] = list(reversed(stations_nei))#反转列表值并强制转换数据类型为列表,作为外环站点名        route_list.append(route_info)        route_list.append(route_info_wai)#将内外环线路字典插入列表    else:    #地铁线路名称包含“内环”或“外环”        route_info = {}        stations = []        route_info['name'] = url['key']# 定义线路字典name键的值        time_1 = [] # 定义地铁发车时间列表        time_2 = []#定义地铁收车时间列表        for i in per_info:            if (i != []):                j = i.findAll('td')                if (j != []):# 筛除表头相关空数据                    for k in j[0]:                        stations.append(k.text)#地铁线路站点名                    for k in j[1]:                        time_1.append(k)#地铁线路发车时间                    for k in j[2]:                        time_2.append(k)#地铁线路收车时间        if (time_1[0] != '--' and time_1[0] != '—'):            route_info['startTime'] = startTime = time_1[0]# 筛除地铁线路发车时间为空的数值        else:            route_info['startTime'] = time_1[1]#定义地铁线路发车时间        if (time_2[len(time_2) - 1] != '--' and time_2[len(time_2) - 1] != '—'):            route_info['endTime'] = time_2[len(time_2) - 1]#筛除地铁线路收车时间为空的数值        else:            route_info['endTime'] = time_2[len(time_2) - 2]#定义地铁线路收车时间        route_info['stations'] = stations# 线路字典stations值赋为站点名        route_list.append(route_info)#将线路字典插入列表    return route_list

 

其中,if语句(Part2的大部分代码)都是用于对非常规线路数据进行特殊处理,这也印证了“80%的代码处理20%的情况”,常规线路数据只需前六行代码即可爬取,最终返回线路列表rout_list。

实战代码Part3——整合数据

for i in get_urls():#遍历城市地铁线路网址    for j in get_schedule(i):        json_str = json.dumps(j, ensure_ascii=False)#转换数据格式为json格式,忽略格式转换错误进行强制转换        print(json_str)

部分结果展示

{"name": "1号线内环", "startTime": "06:30", "endTime": "00:04", "stations": ["罗湖", "国贸", "老街", "大剧院", "科学馆", "华强路", "岗厦", "会展中心", "购物公园", "香蜜湖", "车公庙", "竹子林", "侨城东", "华侨城", "世界之窗", "白石洲", "高新园", "深大", "桃园", "大新", "鲤鱼门", "前海湾", "新安", "宝安中心", "宝体", "坪洲", "西乡", "固戍", "后瑞", "机场东"]}

 

 

 

 

以上就是本期的全部内容了,希望对大家有所帮助。

标签:info,wai,Python,route,爬下来,地铁,time,我用,find
来源: https://blog.csdn.net/Pythoncxy/article/details/102756160