如何搜索谷歌航班

如何使用 Python 抓取 Google 航班:分步指南

在这里,我将向您展示如何创建一个 谷歌航班 使用 Python 和 Playwright 库的 scraper。从设置环境到提取和保存数据,我们将逐步进行。我还将分享处理常见刮擦问题的技巧,例如 IP 禁止 和验证码,因为这些挑战经常出现在谷歌航班等流量巨大的网站上。让我们深入了解一下!

为什么要抓取 Google 航班?

搜索 Google Flights 可以获取大量与航班相关的数据,这些数据有多种用途:

  • 跟踪价格变化: 跟踪航班价格随时间的波动情况,这有助于确定最佳预订时间。
  • 比较航班选择: 查找符合特定要求的航班,如直飞航班、停留时间较短的航班或经济实惠的航班。
  • 市场分析: 对于企业来说,跟踪航空公司和航线的数据可以为定价策略和市场趋势提供洞察力。
  • 环境影响: 提取二氧化碳排放数据,评估不同飞行方案对环境的影响。

自动获取谷歌航班数据的最佳工具

下面列出了一些不同的工具,它们可以帮助你实现数据收集过程的自动化,并节省大量时间和潜在资源:

  1. kcelebi 的飞行分析
  2. Google Flights Scraper by Bright Data
  3. SerpApi

让我们从设置环境开始,构建我们的自定义 Google Flights 搜刮器。

步骤 1:设置 Python 环境

在开始编码之前,请确保您有一个干净的 Python 环境。最好使用虚拟环境来隔离依赖关系。

创建并激活虚拟环境

打开终端,执行以下命令:

# Create a virtual environment
python -m venv flights-scraper-env
# Activate the virtual environment
# On Windows:
.flights-scraper-env\Scripts\activate
# On macOS/Linux:
source flights-scraper-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 存储每个航班的信息,包括航空公司、时间、持续时间、停靠站、价格和二氧化碳排放量。

步骤 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",
}

模拟填写搜索表单

We’ll use Playwright’s asynchronous functions to mimic a user filling in the search parameters on 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 通常要求用户点击 "显示更多航班 "来显示所有选项。通过循环点击该按钮,直到不再显示航班为止,从而实现自动化。

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 库实现重试机制。

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():
scraper = FlightScraper()
params = SearchParameters(
departure="LAX",
destination="JFK",
departure_date="2024-12-01",
ticket_type="One way"
)
try:
flights = await scraper.search_flights(params)
scraper.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 屏蔽和验证码

搜索 Google Flights 会遇到独特的挑战。下面介绍如何应对这些挑战:

  • IP 屏蔽: 使用旋转代理,避免被 Google 的反搜索措施发现。
  • 验证码 实施验证码解决方案,如 Bright Data 的 Web Unlocker,它可以自动绕过验证码挑战。

结论

搜索 Google Flights 可以深入了解旅行模式、价格和航空公司选择。通过使用 Playwright 在 Python 中设置刮擦工具,并遵循可靠性最佳实践,您可以提取有价值的航班数据,供个人或企业使用。为了提高效率,在扩展时应充分利用代理和验证码处理工具。本指南为您提供了基础步骤,有了 Python,您的 Google Flights 搜索能力将无限强大!

类似文章