
在进行网页数据抓取时,我们经常会遇到内容并非一次性加载完成的网站。许多现代网站为了提升用户体验,会采用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中提取数据,但由于数据是动态加载的,这种方法无法获取到所有分页内容。
解决动态加载数据问题的关键在于,理解这些“隐藏”的数据并非真的隐藏,而是通过JavaScript向服务器发送了额外的请求来获取。这些请求通常会指向一个专门的数据接口(API),其返回格式多为JSON或XML。通过直接调用这些API,我们可以绕过前端渲染过程,直接获取原始数据,从而实现更高效、更稳定的数据抓取。
如何识别API接口?
最常用的方法是使用浏览器的开发者工具(通常按F12键打开)。
对于本案例中的 racingpost.com 页面,经过观察,可以发现其数据实际上是从 https://www.racingpost.com/bloodstock/sales/catalogues/5/2023-12-04/data.json 这个JSON接口获取的。这个接口不仅提供了数据,还包含了分页元数据,如总页数。
一旦确定了数据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}")代码解析:
通过API抓取数据的优势:
注意事项:
当面对动态加载内容的网页时,仅仅依赖于初始HTML和BeautifulSoup进行解析往往是不足的。通过使用浏览器的开发者工具,识别并直接访问网页背后的数据API接口,是获取完整、结构化数据的更高效、更稳定的方法。这种方法不仅简化了数据解析过程,也大大提高了数据抓取的成功率和效率。掌握这一技巧,将使你在复杂的网页数据抓取任务中游刃有余。
以上就是深入解析:从动态加载网页中高效抓取数据的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号