You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用BeautifulSoup抓取Airbnb数据时无法获取下一页内容的问题求助

解决Airbnb多页爬虫仅能抓取少量页面的问题

我帮你排查了代码里的几个关键问题,这应该就是你爬不到后续页面的核心原因,下面一步步给你分析和修正:

问题成因分析

  1. 反爬机制拦截:Airbnb对无标识的请求敏感度很高,你直接用requests.get发送请求却没携带浏览器标识(User-Agent),很容易被识别为机器人,后续页面会被限制访问,导致抓不到数据。
  2. 分页逻辑错误:你的find_next_page函数犯了一个低级错误——它没有用当前页面的soup对象,反而重新请求初始URL来查找下一页链接,这会导致永远找不到正确的后续分页地址,循环很快就会终止。
  3. 动态class名失效:Airbnb的class名是动态生成的(比如_8ssblpx、_1tanv1h这类带随机字符的),网站更新后这些名字大概率会变,依赖它们定位元素稳定性极差,容易抓不到内容。
  4. 信息提取逻辑混乱:get_listing_title这类函数接收的是单个房源对象,但函数内部又做了for l in listing循环,这会遍历房源的子元素,导致提取逻辑出错,很多时候会返回None。

修正后的完整代码

我调整了所有问题点,改用更稳定的元素定位方式(比如data-testid属性),添加了请求头,修复了分页逻辑:

import requests
import bs4
import pandas as pd
import time
import random

# 模拟浏览器的请求头,替换成你自己浏览器的User-Agent(可在浏览器控制台Network面板查看)
HEADERS = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36'
}

def get_page(url):
    # 添加随机延迟,模拟人类访问节奏
    time.sleep(random.uniform(3, 6))
    try:
        response = requests.get(url, headers=HEADERS)
        response.raise_for_status()  # 主动抛出请求错误
        soup = bs4.BeautifulSoup(response.text, "html.parser")
        return soup
    except requests.exceptions.RequestException as e:
        print(f"请求页面失败: {e}")
        return None

def get_listings(soup):
    # 改用data-testid定位房源容器,比动态class稳定得多
    if not soup:
        return []
    return soup.find_all("div", {"data-testid": "listing-card"})

def get_listing_title(listing):
    try:
        title_elem = listing.find('div', {'data-testid': 'listing-card-title'})
        return title_elem.text.strip() if title_elem else None
    except Exception as e:
        print(f"提取标题失败: {e}")
        return None

def get_listing_subtitle(listing):
    try:
        subtitle_elem = listing.find('span', {'data-testid': 'listing-card-subtitle'})
        return subtitle_elem.text.strip() if subtitle_elem else None
    except Exception as e:
        print(f"提取副标题失败: {e}")
        return None

def get_listing_info(listing):
    try:
        info_elem = listing.find('div', {'data-testid': 'listing-card-info'})
        return info_elem.text.lower().strip() if info_elem else None
    except Exception as e:
        print(f"提取房源信息失败: {e}")
        return None

def find_next_page(soup):
    base_url = "https://www.airbnb.it"
    if not soup:
        return None
    try:
        # 定位下一页按钮,改用更稳定的选择器
        next_btn = soup.find("a", {"data-testid": "pagination-next-arrow"})
        if next_btn and 'href' in next_btn.attrs:
            return base_url + next_btn['href']
        else:
            return None
    except Exception as e:
        print(f"查找下一页失败: {e}")
        return None

# 初始化数据列表
title = []
subtitle = []
info = []

# 初始URL(修正了原URL的转义字符)
url = 'https://www.airbnb.it/s/Italy/homes?checkin=2021-08-01&checkout=2021-08-02'

while url is not None:
    print(f"正在抓取页面: {url}")
    soup = get_page(url)
    listings = get_listings(soup)
    
    if not listings:
        print("当前页面未找到房源,可能被反爬或页面结构变化")
        break
    
    for l in listings:
        title.append(get_listing_title(l))
        subtitle.append(get_listing_subtitle(l))
        info.append(get_listing_info(l))
    
    # 获取下一页URL
    url = find_next_page(soup)

# 生成DataFrame
airbnb_data = pd.DataFrame(data={'title': title, 'subtitle': subtitle, 'info': info})
print(airbnb_data.head())
# 可选:保存到CSV文件
# airbnb_data.to_csv('airbnb_italy.csv', index=False, encoding='utf-8-sig')

额外建议

  • 更新User-Agent:代码里的User-Agent需要替换成你自己浏览器的(Chrome开发者工具→Network→任意请求→Headers中查看),避免被识别为固定机器人。
  • 处理动态内容:如果Airbnb部分内容是JS动态加载的,静态抓取仍无效,可以考虑用selenium或playwright模拟浏览器渲染页面。
  • 异常扩展:代码里加了基础的异常捕获,你可以根据需要扩展,比如处理IP被封的情况,或者添加代理池。
  • 请求频率:用随机延迟代替固定的5秒,更接近人类访问行为,降低被封风险。

内容的提问来源于stack exchange,提问作者ctrl_z

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 22:07:43