如何抓取 Google 航班

了解如何使用 Python 抓取 Google 航班数据,获取强有力的旅行见解。
4 min read
如何抓取 Google Flights 博客图片

Google 航班 是一项广泛使用的航班预订服务,可提供丰富的数据,包括航班价格、时刻表和航空公司详细信息。遗憾的是,Google 没有提供访问这些数据的公共 API。不过,网页抓取可以成为提取这些数据的不错选择。

在本文中,我将向您展示如何使用 Python 构建一个强大的 Google 航班抓取工具。我们将仔细检查每一个步骤,确保一切都清晰明了。

为什么要抓取 Google 航班数据?

抓取 Google 航班有多种好处,包括:

  • 追踪航班价格的变化
  • 分析价格趋势
  • 确定预订航班的最佳时间
  • 比较不同日期和航空公司的价格

对于旅行者来说,这样可以找到最实惠的价格并省钱。对于企业而言,它有助于市场分析、竞争情报和制定有效的定价策略。

构建 Google 航班抓取工具

我们构建的抓取工具将允许您输入详细信息,例如出发机场、目的地、旅行日期和机票类型(单程或往返)。如果您预订往返行程,则还需要提供回程日期。其余的工作将由抓取工具处理:它加载所有可用的航班,抓取数据,并将结果保存在 JSON 文件中以供进一步分析。

如果您是使用 Python 进行网页抓取的新手,可以查看本 教程 以开始使用。

1.您可以从 Google 航班中提取哪些数据?

Google 航班提供大量数据,包括航空公司名称、出发和到达时间、总时长、停靠次数、机票价格和环境影响数据(例如二氧化碳排放量)。

抓取 Google Flights 数据

以下是可以抓取的数据示例:

{
  "airline": "Alaska",
  "departure_time": "5:22 PM",
  "arrival_time": "9:13 PM",
  "duration": "6 hr 51 min",
  "stops": "Nonstop",
  "price": "₹51,984",
  "co2_emissions": "282 kg CO2e",
  "emissions_variation": "-22% emissions"
}

2.设置环境

首先,让我们在系统中设置运行抓取工具的环境。

# Create a virtual environment (optional)
python -m venv flight-scraper-env

# Activate the virtual environment
# On Windows:
.\flight-scraper-env\Scripts\activate
# On macOS/Linux:
source flight-scraper-env/bin/activate

# Install required packages
pip install playwright tenacity asyncio

# Install Playwright browsers
playwright install chromium

Playwright 非常适合自动化浏览器以及与动态网页(例如 Google 航班)进行交互。我们使用 Tenacity 来实现重试机制。

如果您是 Playwright 新手,一定要查看 Playwright 网页抓取指南。

3.定义数据类

使用 Python的 数据类,您可以巧妙地组织搜索参数和航班数据。

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 (航班数据)类存储有关每个航班的数据,包括航空公司、价格、二氧化碳排放量和其他相关详细信息。

4.FlightScraper 类中的抓取工具逻辑

主要的抓取逻辑封装在 FlightScraper 类中。以下是详细的分类:

4.1 定义 CSS 选择器

您需要在 Google 航班页面上找到特定元素才能提取数据。这是使用 CSS 选择器完成的。以下是 FlightScraper 类中选择器的定义方式:

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

这些选择器的目标是航空公司名称、航班时刻、时长、停靠点、价格和排放数据。

航空公司名称

抓取 Google Flights 航空公司名称

出发时间:

抓取 Google Flights 出发时间

到达时间:

抓取 Google Flights 到达时间

航班时长:

抓取 Google Flights 飞行时长

停靠次数:

抓取 Google Flights 中的经停次数

价格:

抓取 Google Flights 中的价格

二氧化碳当量:

抓取 Google Flights 中的二氧化碳排放量 (CO₂e)

二氧化碳排放量变化:

抓取 Google Flights 中的二氧化碳排放量 (CO₂e)

4.2 填写搜索表单

 _fill_search_form 方法模拟填写包含出发地、目的地和日期详细信息的搜索表单:

async def _fill_search_form(self, page, params: SearchParameters) -> None:
    # First, let's pick our ticket type

    ticket_type_div = page.locator("div.VfPpkd-TkwUic[jsname='oYxtQd']").first
    await ticket_type_div.click()
    await page.wait_for_selector("ul[aria-label='Select your ticket type.']")
    await page.locator("li").filter(has_text=params.ticket_type).nth(0).click()

    # Now, let's fill in our departure and destination

    from_input = page.locator("input[aria-label='Where from?']")
    await from_input.click()
    await from_input.fill("")
    await page.keyboard.type(params.departure)
    # ... rest of the form filling code

4.3 加载所有结果

Google 航班使用分页来加载航班。您需要点击“显示更多航班”按钮来加载所有可用航班:

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

4.4 提取航班数据

航班加载完毕后,您可以抓取航班详细信息:

async def _extract_flight_data(self, page) -> List[FlightData]:
    await page.wait_for_selector("li.pIav2d", timeout=30000)
    await self._load_all_flights(page)

    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

5.添加重试机制

为了使我们的抓取工具更可靠,请使用 tenacity 库添加重试逻辑:

@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=False)
        context = await browser.new_context(
            user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) ..."
        )
        # ... rest of the search implementation

6.保存抓取的结果

将抓取的航班数据保存到 JSON 文件中以供将来分析。

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": {
            "departure": params.departure,
            "destination": params.destination,
            "departure_date": params.departure_date,
            "return_date": params.return_date,
            "search_timestamp": timestamp,
        },
        "flights": [vars(flight) for flight in flights],
    }

    filepath = os.path.join(self.results_dir, filename)
    with open(filepath, "w", encoding="utf-8") as f:
        json.dump(output_data, f, indent=2, ensure_ascii=False)
    return filepath

7.运行抓取工具

以下是运行 Google 航班抓取工具的方法:

async def main():
    scraper = FlightScraper()
    params = SearchParameters(
        departure="MIA",
        destination="SEA",
        departure_date="2024-12-01",
        # return_date="2024-12-30",
        ticket_type="One way",
    )

    try:
        flights = await scraper.search_flights(params)
        print(f"Successfully found {len(flights)} flights")
    except Exception as e:
        print(f"Error during flight search: {str(e)}")

if __name__ == "__main__":
    asyncio.run(main())

最终结果

运行抓取工具后,您的航班数据将保存在如下所示的 JSON 文件中:

{
  "search_parameters": {
    "departure": "MIA",
    "destination": "SEA",
    "departure_date": "2024-12-01",
    "return_date": null,
    "search_timestamp": "20241027_172017"
  },
  "flights": [
    {
      "airline": "American",
      "departure_time": "7:45 PM",
      "arrival_time": "11:38 PM",
      "duration": "6 hr 53 min",
      "stops": "Nonstop",
      "price": "₹50,755",
      "co2_emissions": "303 kg CO2e",
      "emissions_variation": "-16% emissions"
    },
    {
      "airline": "Alaska",
      "departure_time": "5:22 PM",
      "arrival_time": "9:13 PM",
      "duration": "6 hr 51 min",
      "stops": "Nonstop",
      "price": "₹51,984",
      "co2_emissions": "282 kg CO2e",
      "emissions_variation": "-22% emissions"
    },
    {
      "airline": "Alaska",
      "departure_time": "9:00 AM",
      "arrival_time": "12:40 PM",
      "duration": "6 hr 40 min",
      "stops": "Nonstop",
      "price": "₹62,917",
      "co2_emissions": "325 kg CO2e",
      "emissions_variation": "-10% emissions"
    }
  ]
}

您可以在我的 GitHub Gist中找到完整的代码。

扩大 Google 航班数据抓取规模时的常见挑战

在扩大 Google 航班数据抓取规模时,诸如 IP 封锁 和 验证码 之类的挑战很常见。例如,如果您使用抓取工具在短时间内发送过多请求,则网站可能会封锁您的 IP 地址。为避免这种情况,您可以使用手动 IP 轮换,也可以选择一项 顶级代理服务。如果您不确定哪种代理类型最适合您的用例,请查看我们关于 网页抓取最佳代理的指南。

另一个挑战是处理验证码。网站在怀疑有机器人流量时通常会使用验证码,在解析出验证码之前封锁您的抓取工具。手动处理此问题既耗时又复杂。

那么,解决方案是什么?接下来,我们深入探讨一下!

解决方案:Bright Data 网页抓取工具

Bright Data 提供了一系列解决方案,旨在高效简化和规模化您的网页抓取工作。让我们探讨 Bright Data 如何帮助您克服这些常见挑战。

1. 住宅代理

Bright Data 的 住宅代理 使您能够访问和抓取复杂的目标网站。住宅代理可通过合法的住宅连接传递网页抓取请求。目标网站会认为您的请求来自特定地区或区域的真实用户。因此,您可以使用此类代理有效访问受到基于 IP 的反抓取措施保护的页面。

2. 网页解锁器

Bright Data 的 网页解锁器 非常适合抓取出现验证码或限制的项目。网页解锁器并非手动处理这些问题,而是进行自动处理,适应不断变化的网站封锁,成功率很高(通常为 100%)。您只需发送一个请求,剩下的交由网页解锁器处理即可。

3. 抓取浏览器

Bright Data 的 抓取浏览器 对于使用 Puppeteer 或 Playwright等无头浏览器的开发人员来说是另一款强大的工具。与传统的无头浏览器不同,抓取浏览器可以自动处理验证码解析、浏览器指纹识别、重试等操作,因此您可以专注于收集数据,而不必担心网站限制。

结论

本文探讨了如何使用 Python 和 Playwright 抓取 Google 航班数据。尽管手动抓取可能有效,但它通常会带来诸如 IP 禁令和持续脚本维护之类的挑战。为了简化和增强您的数据收集工作,可以考虑利用 Bright Data 的解决方案,例如住宅代理、网页解锁器和抓取浏览器。

立即注册 即可免费试用 Bright Data!

此外,请浏览我们关于抓取其他 Google 服务的指南,例如 Google 搜索结果数据、 Google 趋势、 Google 学术和 Google 地图