首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Python实战:如何利用海外代理IP采集加拿大机票酒店价格

Python实战:如何利用海外代理IP采集加拿大机票酒店价格

原创
作者头像
阿秋数据采集
发布2025-09-30 10:43:35
发布2025-09-30 10:43:35
16300
代码可运行
举报
运行总次数:0
代码可运行

在全球市场中,机票和酒店价格往往存在显著差异。以加拿大多伦多、温哥华、蒙特利尔、卡尔加里和渥太华五大城市为例,同一家连锁酒店在不同城市的价格差可能高达40-60%,而机票价格在不同预订平台和不同时间点的差异也可达到30%以上。

这种价格差异对单个群体的影响可能仅仅是几百块或者几千块的差别,但是对于需要大批量定票的旅行社和票务代理而言,可以获取多市场价格信息有助于优化预算,寻找价格洼地,为客户提供最具竞争力的报价,从而提升利润空间;对于市场研究与数据分析公司而言,则可以采集不同市场的价格数据,为行业客户提供定价策略分析和竞品动态报告。

今天,我们就来带大家一起,看看如何使用python结合海外代理IP来获取不同市场的机票和酒店价格,获取最优报价。

1 项目需求背景

举个加拿大五家知名酒店的例子来说:

  • Fairmont Château Laurier
  • The Westin Ottawa
  • Andaz Ottawa Byward Market
  • Lord Elgin Hotel
  • Le Germain Hotel Ottawa

这些酒店的价格在不同市场(如美国市场、欧洲市场、亚洲市场)中往往差异明显。例如,在美国市场,Fairmont Chateau Laurier的标准间可能为每晚250加元,而在亚洲市场可能降至200加元以下。

核心实现逻辑也很简单:

我们可以借助海外代理 IP,模拟不同市场的用户 IP(如加拿大渥太华、美国纽约、中国上海、英国伦敦),用 Python 的requests库构建请求脚本,定向爬取 Booking、Expedia 等 OTA 平台的实时报价;最后,通过比较多个市场的报价,筛选出最低价作为最优报价。这种方法确保数据实时性,并避免因单一市场视图而错失优惠。

2 海外代理IP在其中的作用

2.1 海外代理IP的关键作用

  • 地域视角还原: 很多平台会基于访问来源的国家/地区(含税、币种、可售房型)做差异化展示。海外代理让请求“从当地出去”,更接近真实市场价。
  • 避免IP封锁与反爬虫: 稳定的代理池 + 合理限速与 UA 轮换,能减少“异常高频同源”造成的限流或反爬触发。
  • 并发与效率: 借助代理IP池,我们可以同时从多个不同市场的IP发起监控请求,实现并行处理,极大地提升了数据采集的效率。

2.2 青果网络海外代理IP的优势

作为深耕行业 10 年的老牌服务商,其稳定性经过长期验证,无论是长时间的爬虫任务还是高并发操作,都能保持低掉线率,延迟表现优异,确保业务流畅运行。

在资源覆盖上,它拥有超 2000 万全球IP资源池,能精准适配跨境电商、市场调研、数据采集等多场景的地域访问需求,轻松实现不同地区网络环境的无缝切换;

自研的业务分池技术大幅降低 IP 被识别封禁的风险,让业务成功率比行业平均水平高出 30%,有效解决了数据采集时常见的失败率高、内容抓取不完整等问题,以至于广受业内技术人员推荐,就连始皇也在用;

所有 IP 均来自主流运营商,符合主流 OTA 平台的访问规范,降低法律风险。

这是他们家多线程任务并行执行监控👆

这是使用他们家代理ip后台的带宽监控👇:

3. 实际操作

实际操作分为几个步骤:准备环境、获取青果网络代理、编写Python脚本、处理反爬虫机制、运行脚本并分析数据。下面详细解释每个步骤,确保初学者也能跟随操作。

本次,我们采集从纽约(NYC)到渥太华(YOW)的机票价格,以及Fairmont Chateau Laurier酒店的标准间价格(入住日期2025-10-01至10-02)。

3.1 准备环境

  • 安装Python(推荐3.8+版本),执行以下命令安装依赖库: pip install requests beautifulsoup4 playwright requests用于HTTP请求,BeautifulSoup用于解析HTML,Playwright用于处理动态加载页面,以应对JavaScript渲染的反爬虫。
  • 注册青果网络账号,获取API密钥。
代码语言:python
代码运行次数:0
运行
复制
def get_qg_proxies():
    """
    从青果网络API获取海外代理IP列表
    """
    try:
        response = requests.get(QG_PROXY_API, timeout=10)
        if response.status_code == 200:
            data = response.json()
            proxies = []
            for item in data['data']:
                proxy_url =  "https://overseas.proxy.qg.net/get?key=yourkey&num=1&area=&isp=&format=txt&seq=\r\n&distinct=false" # 青果网络海外代理IP API地址
                proxies.append(proxy_url)
            return proxies
        else:
            print("获取代理IP失败,使用直连")
            return []
    except Exception as e:
        print(f"获取代理IP异常: {e}")
        return []

def test_proxy(proxy_url, test_url="https://httpbin.org/ip"):
    """
    测试代理IP是否可用
    """
    try:
        proxies = {
            "http": proxy_url,
            "https": proxy_url
        }
        response = requests.get(test_url, proxies=proxies, timeout=5)
        if response.status_code == 200:
            return True
    except:
        return False
    return False

3.2 编写Python脚本

代码语言:python
代码运行次数:0
运行
复制
import requests
from bs4 import BeautifulSoup
import time
from playwright.sync_api import sync_playwright
import pandas as pd  # Added for DataFrame in analysis module

# 青果网络API配置(替换为你的实际API密钥)
QG_API_KEY = 'your_actual_key_here'  # Replace with your real API key
QG_PROXY_BASE_URL = 'https://overseas.proxy.qg.net/get?key={key}&num=1&area={area}&isp=&format=txt&seq=\\r\\n&distinct=false'

# 获取代理IP函数:从青果API获取代理,返回代理字典
def get_proxy(country='US'):
    """
    从青果网络API获取指定国家的代理IP。
    :param country: 国家代码,如 'US', 'GB', 'JP'
    :return: 代理字典或None
    """
    try:
        url = QG_PROXY_BASE_URL.format(key=QG_API_KEY, area=country)
        response = requests.get(url, timeout=10)
        if response.status_code == 200:
            proxy_text = response.text.strip()
            if ':' in proxy_text:
                ip, port = proxy_text.split(':', 1)
                proxy_url = f"http://{ip}:{port}"
                return {
                    'http': proxy_url,
                    'https': proxy_url
                }
            else:
                raise ValueError("Invalid proxy format returned")
        else:
            raise Exception(f"Failed to get proxy for {country}: {response.status_code} - {response.text}")
    except Exception as e:
        print(f"获取代理IP异常 ({country}): {e}")
        return None

# 测试代理IP是否可用
def test_proxy(proxy, test_url="https://httpbin.org/ip"):
    """
    测试代理IP是否可用。
    :param proxy: 代理字典
    :param test_url: 测试URL
    :return: True如果可用,否则False
    """
    if not proxy:
        return False
    try:
        response = requests.get(test_url, proxies=proxy, timeout=5)
        return response.status_code == 200
    except Exception:
        return False

# 获取Google Flights机票价格(优化:使用Playwright直接提取元素,避免BeautifulSoup如果可能)
def scrape_flight_price(proxy, origin='NYC', destination='YOW', date='2025-10-01'):
    """
    使用Playwright刮取Google Flights机票价格。
    :param proxy: 代理字典
    :param origin: 出发地
    :param destination: 目的地
    :param date: 日期
    :return: 价格字符串或'N/A'
    """
    if not proxy or not test_proxy(proxy):
        print("无效代理,使用直连(可能不准确)")
        proxy = None  # Fallback to no proxy

    with sync_playwright() as p:
        launch_args = {}
        if proxy:
            launch_args['proxy'] = {'server': proxy['http']}
        browser = p.chromium.launch(**launch_args)
        page = browser.new_page()
        url = f'https://www.google.com/flights?hl=en#flt={origin}.{destination}.{date}'
        try:
            page.goto(url, wait_until='networkidle', timeout=30000)
            page.wait_for_selector('.gws-flights-results__price', timeout=10000)  # 增加超时
            price = page.query_selector('.gws-flights-results__price').inner_text().strip()
        except Exception as e:
            print(f"刮取机票价格失败: {e}")
            price = 'N/A'
        finally:
            browser.close()
    return price

# 获取Booking.com酒店价格(类似优化)
def scrape_hotel_price(proxy, hotel='fairmont-chateau-laurier', city='Ottawa', checkin='2025-10-01', checkout='2025-10-02'):
    """
    使用Playwright刮取Booking.com酒店价格。
    :param proxy: 代理字典
    :param hotel: 酒店slug
    :param city: 城市(未使用,但保留)
    :param checkin: 入住日期
    :param checkout: 退房日期
    :return: 价格字符串或'N/A'
    """
    if not proxy or not test_proxy(proxy):
        print("无效代理,使用直连(可能不准确)")
        proxy = None

    with sync_playwright() as p:
        launch_args = {}
        if proxy:
            launch_args['proxy'] = {'server': proxy['http']}
        browser = p.chromium.launch(**launch_args)
        page = browser.new_page()
        url = f'https://www.booking.com/hotel/ca/{hotel}.en-gb.html?checkin={checkin}&checkout={checkout}'
        try:
            page.goto(url, wait_until='networkidle', timeout=30000)
            page.wait_for_selector('[data-testid="price-and-discounted-price"]', timeout=10000)
            price = page.query_selector('[data-testid="price-and-discounted-price"]').inner_text().strip()
        except Exception as e:
            print(f"刮取酒店价格失败: {e}")
            price = 'N/A'
        finally:
            browser.close()
    return price

# 主函数:监控不同市场
def main_scrape():
    markets = {'US': 'US', 'EU': 'GB', 'Asia': 'JP'}  # 国家代码
    results = {}
    for market, country in markets.items():
        try:
            proxy = get_proxy(country)
            if proxy:
                flight_price = scrape_flight_price(proxy)
                hotel_price = scrape_hotel_price(proxy)
                results[market] = {'Flight': flight_price, 'Hotel': hotel_price}
                print(f"{market} 市场数据获取成功: 机票 {flight_price}, 酒店 {hotel_price}")
            else:
                results[market] = {'Flight': 'N/A', 'Hotel': 'N/A'}
            time.sleep(10)  # 避免高频请求
        except Exception as e:
            print(f"{market} 市场获取失败: {e}")
            results[market] = {'Flight': 'N/A', 'Hotel': 'N/A'}
    return results

通过这些详细步骤,你可以从零构建并运行监控系统。

3.3 数据存储与分析模块

代码语言:python
代码运行次数:0
运行
复制
# 数据存储与分析模块(假设CanadaHotelMonitor是自定义类,这里简化;原代码中未定义,所以添加占位符)
class CanadaHotelMonitor:
    def monitor_all_hotels(self):
        # 占位符:假设返回当前价格列表(基于main_scrape结果扩展)
        # 在实际中,实现为采集多个酒店
        return [
            {'hotel': 'Fairmont Château Laurier', 'price': 'CAD 250', 'currency': 'CAD'},
            # 添加更多...
        ]

class PriceAnalyzer:
    def __init__(self):
        self.history_data = []
    
    def find_optimal_offers(self, current_data):
        """
        找出最优报价。
        :param current_data: 当前数据列表
        :return: 前3个最优报价
        """
        if not current_data:
            return None
        
        optimized_offers = []
        for offer in current_data:
            try:
                # 提取数值价格(改进:处理更多格式,如'CAD 250' -> 250.0)
                price_str = offer['price'].split()[-1]  # 假设最后是数字
                price_value = float(''.join(filter(lambda c: c.isdigit() or c == '.', price_str)))
                offer['price_value'] = price_value
                optimized_offers.append(offer)
            except ValueError:
                continue
                
        # 按价格排序
        optimized_offers.sort(key=lambda x: x['price_value'])
        return optimized_offers[:3]

def main_monitoring_loop():
    """
    主监控循环。
    """
    monitor = CanadaHotelMonitor()
    analyzer = PriceAnalyzer()
    
    while True:
        print(f"{time.strftime('%Y-%m-%d %H:%M:%S')} 开始新一轮价格监控...")
        
        # 采集数据(集成main_scrape或扩展)
        current_prices = monitor.monitor_all_hotels()  # 替换为实际采集
        
        # 分析最优报价
        best_offers = analyzer.find_optimal_offers(current_prices)
        
        # 保存结果
        if best_offers:
            df = pd.DataFrame(best_offers)
            df.to_csv(f"ottawa_hotels_best_offers_{time.strftime('%Y%m%d')}.csv", index=False)
            print("最优报价已保存:")
            for offer in best_offers:
                print(f"{offer['hotel']}: {offer['price']} {offer['currency']}")
        
        # 间隔1小时
        print("等待下一轮监控...")
        time.sleep(3600)

if __name__ == "__main__":
    # 示例:运行一次刮取
    results = main_scrape()
    print("最终结果:", results)
    # 或运行循环:main_monitoring_loop()

4. 数据结果呈现

执行完上述脚本后,我们可以得到一个清晰的表格,直观地展示优化报价对比表。

酒店名称

平台报价 (CAD)

最优报价来源

价格优势

最后更新时间

Fairmont Château Laurier

289-345

Booking.com

标准价格

2025-09-25 10:23:45

Andaz Ottawa ByWard Market

275-315

Expedia

15%优惠

2025-09-25 10:25:12

Lord Elgin Hotel

189-225

Hotels.com

22%优惠

2025-09-25 10:26:33

Brookstreet Hotel

210-250

官网直订

免费早餐

2025-09-25 10:28:01

The Westin Ottawa

240-285

Booking.com

积分双倍

2025-09-25 10:29:27

注:以上数据为模拟,实际价格和货币单位会根据目标网站和代理IP的位置而变化。

5. 总结

通过Python结合青果网络的海外代理IP,我们成功构建了一个自动化、实时性的监测加拿大不同市场的机票和酒店价格,实现最优报价获取。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1 项目需求背景
  • 2 海外代理IP在其中的作用
    • 2.1 海外代理IP的关键作用
    • 2.2 青果网络海外代理IP的优势
  • 3. 实际操作
    • 3.1 准备环境
    • 3.2 编写Python脚本
    • 3.3 数据存储与分析模块
  • 4. 数据结果呈现
  • 5. 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档