网站分析
广州市白云国际机场的到达航班数据可以在其官网的到达航班中进行查询,具体网址为:https://www.gbiac.net/byairport-web/flight/list?depOrArr=2&type=1&day=0&terminal=ALL。
通过分析网站页面我们可以锁定我们所需要数据包括计划到达时间和状态这两列,如下图所示:
通过浏览器开发者工具的 Elements 功能进行定位找所需元素时间和状态的位置在类为”column w200 bold”和”column w80″的 li 容器里中。
将网页下拉,发现网站的数据是动态加载的,直接爬取只能得到部分信息,更多的信息需要点击加载更多按钮才可以获取。
于是打开开发者工具的 Notwork 来研究按钮的功能,发现点击按钮后发出一个名为 loadMore 的请求,点击查看其详情。
通过详情可以看到按钮的功能是向地址 https://www.gbiac.net/byairport-web/flight/loadMore 发送一个 Post 请求。
查看返回报文可以看出其结构与原网页相似,无需改动,因此复用前面处理方法即可。
然后,研究 Post 请求的报文结构,关键是 header 头部的组成以及 Data 部分的数据处理。头部信息如下,复用以下信息即可。
Data 部分通过对比原网页和不同 loadMore 请求,可以发现发生改变的位置只有 flightNo 和 dataTime 字段。同样进行对比可以发现 flightNo 和 dataTime 字段实际上为上一也最后一行数据。到处网页分析部分就已经全部完成了,接下来开始编码实现。
数据爬取
我使用 python 进行编程编程,代码具体如下:
1)导包:
import csv import time import requests from bs4 import BeautifulSoup
2)构建函数用于判断航班号以及航班状态的合法性:
def IsChinese(character): """ 判断是否为中文 :param character: 字符串 :return: 是中文返回 False,否则返回 True """ for cha in character: if '\u0e00' <= cha <= '\u9fa5': return False else: return True def IsState(character): """ 判断状态是否合法 :param character: 字符串 :return: 是否合法 """ if character.find("到达") == 0: return True elif character.find("计划") == 0: return True elif character.find("途中") == 0: return True else: return False
3)初始化元素,定义访问的 url 和头部信息:
# 元素初始化 sj = list() zt = list() # 存储路径 savedatapath = r'D:\University\大三\数据挖掘\第五次作业\白云机场 10.20 航班数据.csv' # 初始化爬取的网站和访问头 url = 'https://www.gbiac.net/byairport-web/flight/list?depOrArr=2&type=1&terminal=ALL&day=-1' url2 = 'https://www.gbiac.net/byairport-web/flight/loadMore' headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36'} headers2 = { 'Accept': 'text/html, */*; q=0.01', 'Accept-Encoding': 'gzip, deflate, br', 'Accept-Language': 'zh-CN,zh;q=0.9,ja;q=0.8', 'Connection': 'keep-alive', 'Content-Length': '81', 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', 'Host': 'www.gbiac.net', 'Origin': 'https://www.gbiac.net', 'Referer': 'https://www.gbiac.net/', 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36', 'X-Requested-With': 'XMLHttpRequest' } # post 请求数据包 data = { 'depOrArr': '2', 'type': '1', 'day': '-1', 'terminal': 'ALL' }
4)访问原网页读取信息
# 解析原始网页 res = requests.get(url=url, headers=headers) res.encoding = 'utf-8' html = res.text if len(html) > 100: print('解析成功') else: print('解析失败', len(html)) # 元素提取 soup = BeautifulSoup(html, features="html.parser") company_items = soup.find_all('li', class_='column w200 bold') for company_item in company_items: dd = company_item.text.strip() sj.append(dd) lt = dd company_items = soup.find_all('li', class_='column w80') for company_item in company_items: dd = company_item.text.strip() if IsState(dd): zt.append(dd)
5)发送 Post 请求获取后续信息:
# 发起 post 请求 FL = 'MU2542' for i in range(11): print('第' + str(i + 2) + '页数据请求中') data['flightNo'] = FL data['dataTime'] = '2022-10-19 ' + lt res = requests.post(url=url2, data=data, headers=headers2) res.encoding = 'utf-8' html = res.text if len(html) > 100: print('第' + str(i + 2) + '页数据获取成功') else: print('第' + str(i + 2) + '页数据获取失败,结束进程:', len(html)) break soup = BeautifulSoup(html, features="html.parser") company_items = soup.find_all('li', class_="column w200 bold") company_items2 = soup.find_all('div', class_="item") for company_item in company_items: dd = company_item.text.strip() sj.append(dd) lt = dd for company_item in company_items2: tx = company_item.text.strip() if tx.isalnum() & IsChinese(tx): FL = tx company_items = soup.find_all('li', class_='column w80') for company_item in company_items: dd = company_item.text.strip() if IsState(dd): zt.append(dd) time.sleep(2)
6)写入数据到 csv 文件中:
# 存储数据 rows = zip(sj, zt) with open(savedatapath, "w", newline='') as f: writer = csv.writer(f) for row in rows: writer.writerow(row)