0

0

深入解析:从动态加载网页中高效抓取数据

花韻仙語

花韻仙語

发布时间:2025-08-01 23:42:02

|

911人浏览过

|

来源于php中文网

原创

深入解析:从动态加载网页中高效抓取数据

本文旨在教授如何从采用动态加载机制的网页中高效抓取数据,特别是当传统HTML解析方法无法获取全部内容时。我们将通过一个实际案例,演示如何识别并直接调用网页背后的数据API接口,从而绕过前端渲染限制,获取完整的结构化数据,并提供详细的Python代码示例和最佳实践。

1. 传统网页抓取面临的挑战

在进行网页数据抓取时,我们经常会遇到内容并非一次性加载完成的网站。许多现代网站为了提升用户体验,会采用JavaScript动态加载数据,例如“加载更多”、“无限滚动”或通过点击按钮显示隐藏内容等。在这种情况下,仅仅使用requests库获取初始HTML内容,并结合BeautifulSoup进行解析,往往只能获取到页面首次加载时可见的部分数据。

例如,对于一个包含大量数据列表的页面,如 https://www.racingpost.com/bloodstock/sales/catalogues/5/2023-12-04,初次加载时可能只显示前50条记录。页面底部通常会有一个“加载更多”的按钮或提示,点击后才会通过异步请求加载后续数据。此时,如果直接解析初始HTML,你将无法获取到这些隐藏的数据。

from bs4 import BeautifulSoup as BS
import requests
import re

url = 'https://www.racingpost.com/bloodstock/sales/catalogues/5/2023-12-04'
res = requests.get(url)
print(f"HTTP Status Code: {res.status_code}")

soup = BS(res.content, "html.parser")

# 尝试从初始HTML中提取数据,可能只获得部分内容
# string = str(soup.find_all("script", type="text/javascript")[1])
# raw_data = re.findall(r'\{"lot(.*?)\}', string)
# print(f"通过初始HTML解析到的数据条数: {len(raw_data)}")
# 此时,len(raw_data)通常远小于页面实际的总数据量

上述代码尝试从初始HTML中提取数据,但由于数据是动态加载的,这种方法无法获取到所有分页内容。

2. 识别并利用隐藏的数据API

解决动态加载数据问题的关键在于,理解这些“隐藏”的数据并非真的隐藏,而是通过JavaScript向服务器发送了额外的请求来获取。这些请求通常会指向一个专门的数据接口(API),其返回格式多为JSON或XML。通过直接调用这些API,我们可以绕过前端渲染过程,直接获取原始数据,从而实现更高效、更稳定的数据抓取。

如何识别API接口?

最常用的方法是使用浏览器的开发者工具(通常按F12键打开)。

  1. 打开目标网页。
  2. 切换到“网络”(Network)或“XHR/Fetch”选项卡。
  3. 刷新页面,或点击页面上的“加载更多”按钮。
  4. 观察网络请求列表,寻找那些返回JSON或XML格式数据的请求。这些请求的URL通常包含“api”、“data”、“json”等关键词,并且请求参数(如page、offset、limit)会指示分页信息。

对于本案例中的 racingpost.com 页面,经过观察,可以发现其数据实际上是从 https://www.racingpost.com/bloodstock/sales/catalogues/5/2023-12-04/data.json 这个JSON接口获取的。这个接口不仅提供了数据,还包含了分页元数据,如总页数。

Sider
Sider

多功能AI浏览器助手,帮助用户进行聊天、写作、阅读、翻译等

下载

3. 通过API接口抓取完整数据

一旦确定了数据API接口,我们就可以直接使用requests库来请求这些接口,获取完整的JSON数据。

import requests
import json # 导入json库以便更好地处理数据

# 定义基础URL和数据API路径
base_url = 'https://www.racingpost.com/bloodstock/sales/catalogues/5/2023-12-04'
data_api_url = f'{base_url}/data.json'

# 1. 获取分页元数据
try:
    page_metadata_response = requests.get(data_api_url)
    page_metadata_response.raise_for_status() # 检查HTTP请求是否成功
    page_metadata = page_metadata_response.json()

    # 提取总页数
    total_pages = page_metadata['pagination']['totalPages']
    print(f"发现总页数: {total_pages}")

    all_data = [] # 用于存储所有页的数据

    # 2. 遍历所有页,抓取数据
    for page in range(1, total_pages + 1):
        print(f"正在抓取第 {page}/{total_pages} 页数据...")
        # 发送带分页参数的请求
        response = requests.get(data_api_url, params={'page': str(page)})
        response.raise_for_status() # 检查HTTP请求是否成功

        # 解析JSON响应,提取'rows'字段的数据
        page_data = response.json()['rows']
        all_data.extend(page_data) # 将当前页数据添加到总列表中

        # 可以在此处添加延迟,防止请求过快被封禁
        # import time
        # time.sleep(0.5) 

    print(f"\n成功抓取到总计 {len(all_data)} 条数据。")
    # 打印前几条数据作为示例
    if all_data:
        print("部分抓取到的数据示例:")
        for i, item in enumerate(all_data[:5]): # 打印前5条
            print(f"  数据 {i+1}: {item}")

    # 可以将数据保存到文件
    # with open('racingpost_data.json', 'w', encoding='utf-8') as f:
    #     json.dump(all_data, f, ensure_ascii=False, indent=4)
    # print("数据已保存到 racingpost_data.json")

except requests.exceptions.RequestException as e:
    print(f"请求发生错误: {e}")
except KeyError as e:
    print(f"JSON解析错误,键不存在: {e}. 响应内容可能不符合预期。")
    print(f"原始响应内容: {page_metadata_response.text if 'page_metadata_response' in locals() else response.text}")
except json.JSONDecodeError as e:
    print(f"JSON解码错误: {e}. 响应内容可能不是有效的JSON。")
    print(f"原始响应内容: {page_metadata_response.text if 'page_metadata_response' in locals() else response.text}")

代码解析:

  1. 确定API URL: 根据开发者工具的发现,我们构建了 data_api_url。
  2. 获取元数据: 首先向 data.json 发送一个请求,获取包含 pagination 信息的JSON。从 pagination['totalPages'] 中提取总页数。
  3. 循环抓取: 使用一个 for 循环,从第1页迭代到 total_pages。
  4. 传递分页参数: 在每次循环中,通过 params={'page': str(page)} 将当前页码作为查询参数传递给API。这是API识别并返回对应页数据的方式。
  5. 解析JSON: response.json() 方法将HTTP响应体解析为Python字典或列表。本例中,实际数据位于返回JSON的 rows 键下。
  6. 数据汇总: 将每页获取到的数据列表通过 extend() 方法添加到 all_data 总列表中。
  7. 错误处理: 增加了 try-except 块来捕获 requests 库可能抛出的网络错误 (RequestException)、JSON解析错误 (JSONDecodeError) 或字典键不存在错误 (KeyError),增强了代码的健壮性。

4. 优势与注意事项

通过API抓取数据的优势:

  • 高效: 无需解析复杂的HTML结构,直接获取结构化数据,解析速度更快。
  • 稳定: API接口通常比HTML结构稳定,网站前端改版对API的影响较小。
  • 完整性: 能够获取到所有动态加载的数据,解决了传统方法无法获取完整数据的痛点。
  • 资源消耗低: 不需要渲染页面,节省了CPU和内存资源。

注意事项:

  • API文档: 如果有API文档,务必查阅,了解参数、返回格式和限制。
  • 请求频率: 大多数网站对API请求有频率限制(Rate Limiting)。过于频繁的请求可能导致IP被封禁。建议在每次请求之间添加 time.sleep() 延迟。
  • User-Agent: 在某些情况下,服务器会检查请求的 User-Agent 头。模拟浏览器行为可以提高成功率。
  • 错误处理: 务必添加健壮的错误处理机制,例如网络中断、API返回非预期数据格式等情况。
  • 遵守Robots.txt和网站政策: 在进行任何抓取活动前,请务必查看网站的 robots.txt 文件,并遵守其使用条款和隐私政策。尊重网站的数据所有权和服务器负载。

总结

当面对动态加载内容的网页时,仅仅依赖于初始HTML和BeautifulSoup进行解析往往是不足的。通过使用浏览器的开发者工具,识别并直接访问网页背后的数据API接口,是获取完整、结构化数据的更高效、更稳定的方法。这种方法不仅简化了数据解析过程,也大大提高了数据抓取的成功率和效率。掌握这一技巧,将使你在复杂的网页数据抓取任务中游刃有余。

相关专题

更多
python开发工具
python开发工具

php中文网为大家提供各种python开发工具,好的开发工具,可帮助开发者攻克编程学习中的基础障碍,理解每一行源代码在程序执行时在计算机中的过程。php中文网还为大家带来python相关课程以及相关文章等内容,供大家免费下载使用。

746

2023.06.15

python打包成可执行文件
python打包成可执行文件

本专题为大家带来python打包成可执行文件相关的文章,大家可以免费的下载体验。

634

2023.07.20

python能做什么
python能做什么

python能做的有:可用于开发基于控制台的应用程序、多媒体部分开发、用于开发基于Web的应用程序、使用python处理数据、系统编程等等。本专题为大家提供python相关的各种文章、以及下载和课程。

758

2023.07.25

format在python中的用法
format在python中的用法

Python中的format是一种字符串格式化方法,用于将变量或值插入到字符串中的占位符位置。通过format方法,我们可以动态地构建字符串,使其包含不同值。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

617

2023.07.31

python教程
python教程

Python已成为一门网红语言,即使是在非编程开发者当中,也掀起了一股学习的热潮。本专题为大家带来python教程的相关文章,大家可以免费体验学习。

1261

2023.08.03

python环境变量的配置
python环境变量的配置

Python是一种流行的编程语言,被广泛用于软件开发、数据分析和科学计算等领域。在安装Python之后,我们需要配置环境变量,以便在任何位置都能够访问Python的可执行文件。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

547

2023.08.04

python eval
python eval

eval函数是Python中一个非常强大的函数,它可以将字符串作为Python代码进行执行,实现动态编程的效果。然而,由于其潜在的安全风险和性能问题,需要谨慎使用。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

577

2023.08.04

scratch和python区别
scratch和python区别

scratch和python的区别:1、scratch是一种专为初学者设计的图形化编程语言,python是一种文本编程语言;2、scratch使用的是基于积木的编程语法,python采用更加传统的文本编程语法等等。本专题为大家提供scratch和python相关的文章、下载、课程内容,供大家免费下载体验。

705

2023.08.11

Java 项目构建与依赖管理(Maven / Gradle)
Java 项目构建与依赖管理(Maven / Gradle)

本专题系统讲解 Java 项目构建与依赖管理的完整体系,重点覆盖 Maven 与 Gradle 的核心概念、项目生命周期、依赖冲突解决、多模块项目管理、构建加速与版本发布规范。通过真实项目结构示例,帮助学习者掌握 从零搭建、维护到发布 Java 工程的标准化流程,提升在实际团队开发中的工程能力与协作效率。

9

2026.01.12

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
最新Python教程 从入门到精通
最新Python教程 从入门到精通

共4课时 | 0.6万人学习

Django 教程
Django 教程

共28课时 | 3万人学习

SciPy 教程
SciPy 教程

共10课时 | 1.1万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号