
如何使用 Python 抓取 Google Flights:分步指南
在这里,我将向你展示如何使用 Python 和 Playwright 库构建一个 Google Flights 爬虫工具。我们会一步步进行,从搭建环境到提取并保存数据。我还会分享一些处理常见抓取问题的技巧,比如 IP 封禁 和 CAPTCHA,因为这些挑战经常出现在像 Google Flights 这样流量很高的网站上。让我们开始吧!
为什么要抓取 Google Flights?
抓取 Google Flights 可以获取大量与航班相关的数据,这些数据可以通过多种方式使用:
-
跟踪价格变化:跟踪航班价格随时间的波动,有助于确定最佳预订时间。
-
比较航班选项: 查找符合特定要求的航班,例如直飞选项、更短的中转时间或更经济实惠的替代方案。
-
市场分析:对于企业来说,跟踪不同航空公司和航线的数据可以提供有关定价策略和市场趋势的洞察。
-
环境影响:提取 CO2 排放数据,以评估不同航班选项的环境影响。
用于自动化 Google Flights 数据采集的最佳工具
下面列出了一些不同的工具,它们可以帮助你自动化数据收集流程,节省大量时间,也可能节省资源:
-
Bright Data 的 Google Flights 抓取工具
如何用 Python 抓取 Google Flights
让我们先搭建环境,以构建自定义的 Google Flights 抓取工具。
第 1 步:设置你的 Python 环境
在开始编写代码之前,请确保你拥有一个干净的 Python 环境。最好使用虚拟环境来隔离依赖项。
创建并激活虚拟环境
打开终端并执行以下命令:
# Create a virtual environment
python -m venv flights-爬虫工具-env
# Activate the virtual environment
# On Windows:
.flights-抓取工具-envScriptsactivate
# On macOS/Linux:
source flights-爬虫-env/bin/activate
安装必要的软件包
我们将使用 Playwright 与 Google Flights 网站交互,因为它可以有效地自动化动态网页上的操作。Tenacity 将帮助实现重试机制,以提升可靠性。
# Install required packages
pip install playwright tenacity asyncio
# Install Playwright's browser dependencies
playwright install chromium
第 2 步:定义数据结构
为了让代码保持有序,我们将定义数据类来存储搜索参数以及我们提取的航班数据。
from dataclasses import dataclass
from typing import Optional
@dataclass
class SearchParameters:
departure: str
destination: str
departure_date: str
return_date: Optional[str] = None
ticket_type: str = "One way"
@dataclass
class FlightData:
airline: str
departure_time: str
arrival_time: str
duration: str
stops: str
price: str
co2_emissions: str
emissions_variation: str
-
SearchParameters 保存航班搜索所需的详细信息。
-
FlightData 存储每个航班的信息,包括航空公司、时间、时长、经停、价格和 CO2 排放。
第 3 步:编写航班抓取类
我们的爬虫工具核心将位于 FlightScraper 类中,我们会分阶段构建它。
定义 CSS 选择器
使用 CSS 选择器可以让我们定位页面上的特定元素,以提取航空公司名称、出发时间、价格等详细信息。
class FlightScraper:
SELECTORS = {
"airline": "div.sSHqwe.tPgKwe.ogfYpf",
"departure_time": 'span[aria-label^="Departure time"]',
"arrival_time": 'span[aria-label^="Arrival time"]',
"duration": 'div[aria-label^="Total duration"]',
"stops": "div.hF6lYb span.rGRiKd",
"price": "div.FpEdX span",
"co2_emissions": "div.O7CXue",
"emissions_variation": "div.N6PNV",
}
模拟填写搜索表单
我们将使用 Playwright 的异步函数,模拟用户在 Google Flights 上填写搜索参数。
async def _fill_search_form(self, page, params: SearchParameters) -> None:
ticket_type_div = page.locator("div.VfPpkd-TkwUic[jsname='oYxtQd']").first
await ticket_type_div.click()
await page.locator("li").filter(has_text=params.ticket_type).nth(0).click()
from_input = page.locator("input[aria-label='Where from?']")
await from_input.fill(params.departure)
to_input = page.locator("input[aria-label='Where to?']")
await to_input.fill(params.destination)
date_input = page.locator("input[aria-label='Departure date']")
await date_input.fill(params.departure_date)
加载所有可用航班
Google Flights 通常需要用户点击"Show more flights"才能显示所有选项。使用循环自动完成此操作,不断点击该按钮,直到不再显示更多航班。
async def _load_all_flights(self, page) -> None:
while True:
try:
more_button = await page.wait_for_selector(
'button[aria-label*="more flights"]', timeout=5000
)
if more_button:
await more_button.click()
await page.wait_for_timeout(2000)
else:
break
except:
break
提取航班数据
当所有航班都可见后,遍历每个航班的元素,并使用 CSS 选择器获取详细信息。
async def _extract_flight_data(self, page) -> list[FlightData]:
await page.wait_for_selector("li.pIav2d", timeout=30000)
flights = await page.query_selector_all("li.pIav2d")
flights_data = []
for flight in flights:
flight_info = {}
for key, selector in self.SELECTORS.items():
element = await flight.query_selector(selector)
flight_info[key] = await self._extract_text(element)
flights_data.append(FlightData(**flight_info))
return flights_data
步骤 4:实现重试逻辑以提高可靠性
为了让我们的爬虫工具更具韧性,我们将使用 tenacity library 实现重试机制;当函数遇到某些错误时,它会自动重试。
from tenacity import retry, stop_after_attempt, wait_fixed
@retry(stop=stop_after_attempt(3), wait=wait_fixed(5))
async def search_flights(self, params: SearchParameters) -> list[FlightData]:
async with async_playwright() as p:
browser = await p.chromium.launch(headless=True)
context = await browser.new_context()
page = await context.new_page()
await page.goto("https://www.google.com/flights")
await self._fill_search_form(page, params)
flights = await self._extract_flight_data(page)
await browser.close()
return flights
步骤 5:将结果保存到 JSON 文件
抓取到数据后,将其存储在 JSON 文件中,便于检索和分析。
import json
from datetime import datetime
def save_results(self, flights: list[FlightData], params: SearchParameters) -> str:
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
filename = f"flight_results_{params.departure}_{params.destination}_{timestamp}.json"
output_data = {
"search_parameters": vars(params),
"flights": [vars(flight) for flight in flights],
}
with open(filename, "w", encoding="utf-8") as f:
json.dump(output_data, f, indent=2, ensure_ascii=False)
return filename
步骤 6:运行爬虫工具
以下是如何使用示例搜索参数启动该抓取工具。
import asyncio
async def main():
抓取工具 = FlightScraper()
params = SearchParameters(
departure="LAX",
destination="JFK",
departure_date="2024--12--01",
ticket_type="One way"
)
try:
flights = await 爬虫工具.search_flights(params)
抓取工具.save_results(flights, params)
print("Flights scraped successfully.")
except Exception as e:
print(f"Error during flight search: {str(e)}")
if __name__ == "__main__":
asyncio.run(main())
应对常见抓取挑战:IP 封锁和 CAPTCHA
抓取 Google Flights 面临一些独特挑战。以下是应对方法:
-
IP 封锁:使用动态代理来避免被 Google 的反抓取措施检测到。
-
CAPTCHA:实施 CAPTCHA 破解解决方案,例如 Bright Data 的网络解锁器,它可以自动绕过 CAPTCHA 验证挑战。
结论
抓取 Google Flights 可深入洞察旅行模式、价格和航空公司选项。通过使用 Python 和 Playwright 设置爬虫工具,并遵循可靠性最佳实践,你可以提取有价值的航班数据,用于个人或商业用途。要提升效率,在扩大规模时可充分利用代理和 CAPTCHA 处理工具。本指南为你提供了基础步骤;借助 Python,你的 Google Flights 抓取能力将没有限制!
对其他网页抓取指南感兴趣?
如需阅读其他精彩文章,请访问我的个人主页 --- Data Journal ❤️