如何通过解析 React 渲染页的内嵌 JSON 数据实现可靠分页爬取

聖光之護

聖光之護

2026-08-02

902人浏览

原创

如何通过解析 React 渲染页的内嵌 JSON 数据实现可靠分页爬取

本文介绍一种绕过前端 javascript 分页限制的方法:直接提取页面中由 react 注入的初始状态 json 数据,从而获取全部地点信息,避免因动态渲染导致的分页失效问题。

本文介绍一种绕过前端 javascript 分页限制的方法:直接提取页面中由 react 注入的初始状态 json 数据,从而获取全部地点信息,避免因动态渲染导致的分页失效问题。

在使用 requests + BeautifulSoup 爬取类似 https://www.php.cn/link/c391014771f4bf86024b31abdf19483d 这类基于 React(配合 Rails 后端)构建的现代网站时,传统基于 HTML 按钮或链接的分页逻辑往往失效——因为真实分页由前端 JavaScript 控制,且关键数据(如所有地点列表)通常已预先注入页面 DOM 的 <script> 标签中,而非通过多次 AJAX 请求动态加载。</script>

原代码尝试模拟点击“下一页”按钮并查找 链接,但失败的根本原因在于:

  • 页面未在 HTML 中静态渲染分页链接;
  • Pagination__pageItem__NsQSw 类按钮是 React 动态绑定事件的 DOM 元素,requests 无法执行 .click();
  • soup.find('a', href=True) 在当前页面上下文中匹配的是无关导航链接(如顶部菜单),而非真正的分页跳转地址。

✅ 正确解法:定位并解析内嵌的初始化状态 JSON

观察页面源码可发现,React 组件 StateShow 通过 <script class="js-react-on-rails-component" data-component-name="StateShow"> 标签注入了完整的州级地点数据(含 name、fullAddress、url 等字段)。该数据即为全量结果,无需手动翻页。</script>

php版微信js-sdk支付接口类
php版微信js-sdk支付接口类

php版微信js-sdk支付接口类

下载

以下是优化后的完整可运行脚本:

import requests
from bs4 import BeautifulSoup
import csv
import json

base_url = 'https://www.datacenters.com'
main_url = f'{base_url}/locations/united-states/virginia'

def get_detail_data(relative_link, name, address, writer):
    link = f'{base_url}{relative_link}'
    try:
        detail_response = requests.get(link, timeout=10)
        detail_response.raise_for_status()
        detail_soup = BeautifulSoup(detail_response.content, 'html.parser')

        # 提取 Power 和 SQF 字段
        power_div = detail_soup.find('div', id='power')
        power = power_div.find('strong').text.strip() if power_div and power_div.find('strong') else 'N/A'

        sqf_div = detail_soup.find('div', id='statInfo')
        sqf = sqf_div.find('strong').text.strip() if sqf_div and sqf_div.find('strong') else 'N/A'

        writer.writerow([name, address, power, sqf, link])
        print(f"✓ Scraped: {name}")
    except Exception as e:
        print(f"✗ Failed for {name}: {e}")

# 主爬取流程
with open('datacenters.csv', mode='w', newline='', encoding='utf-8') as file:
    writer = csv.writer(file)
    writer.writerow(['Name', 'Address', 'Power', 'SQF', 'Link'])

    print(f"Fetching initial page: {main_url}")
    response = requests.get(main_url, headers={
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
    })
    response.raise_for_status()

    soup = BeautifulSoup(response.content, 'html.parser')

    # 定位 React 初始化数据脚本
    state_script = soup.find('script', {
        'class': 'js-react-on-rails-component',
        'data-component-name': 'StateShow'
    })

    if not state_script:
        raise ValueError("❌ Failed to locate StateShow JSON data in page source.")

    try:
        state_data = json.loads(state_script.string)
        locations = state_data.get('show', {}).get('mapLocations', [])

        if not locations:
            print("⚠️  No location data found in embedded JSON.")

        print(f"✅ Found {len(locations)} locations. Starting detail scraping...")
        for idx, loc in enumerate(locations, 1):
            # 确保关键字段存在
            url = loc.get('url')
            name = loc.get('name', 'Unknown')
            address = loc.get('fullAddress', 'N/A')

            if url:
                get_detail_data(url, name, address, writer)
            else:
                print(f"⚠️  Skipped location #{idx}: missing URL")

    except json.JSONDecodeError as e:
        raise ValueError(f"❌ Invalid JSON in StateShow script: {e}")
    except KeyError as e:
        raise ValueError(f"❌ Expected key missing in JSON structure: {e}")

? 关键注意事项:

  • 不要依赖可见按钮或分页链接:该站点分页实际由前端调用 /api/v1/locations?page=N&state_id=3173 实现,但全量数据已在首屏 JSON 中提供,直接使用更高效稳定;
  • 添加请求头(User-Agent):部分站点会拦截无头请求,模拟浏览器 UA 可降低被拒概率;
  • 健壮性处理:对 find('strong') 等嵌套元素做双重判空,避免 AttributeError;
  • 异常捕获全覆盖:网络超时、HTTP 错误、JSON 解析失败、字段缺失等均需显式处理;
  • 反爬友好提示:若后续遭遇频率限制,建议添加 time.sleep(1) 或使用 requests.Session() 复用连接。

? 总结:面对 SPA(单页应用)类网站,优先检查 <script> 标签中的内嵌 JSON 数据——它往往是比逆向 API 更简单、更可靠的“隐藏数据源”。掌握这一技巧,可大幅提升<a style="color:#f60; text-decoration:underline;" title= "爬虫"href="https://m.php.cn/zt/19377.html" target="_blank">爬虫开发效率与稳定性。</script>

相关专题

更多
免费爬虫工具有哪些
免费爬虫工具有哪些

免费爬虫工具有Scrapy、Beautiful Soup、ParseHub、Octoparse、Webocton Scriptly、RoboBrowser和Goutte。更多关于免费爬虫工具的问题,详情请看本专题下面的文章。php中文网欢迎大家前来学习。

2023.11.10

2198

9

Python爬虫获取数据的方法
Python爬虫获取数据的方法

Python爬虫可以通过请求库发送HTTP请求、解析库解析HTML、正则表达式提取数据,或使用数据抓取框架来获取数据。更多关于Python爬虫相关知识。详情阅读本专题下面的文章。php中文网欢迎大家前来学习。

2023.11.13

493

12

墨刀AI提示词教学
墨刀AI提示词教学

本合集由PHP中文网精心整理,为您提供全面的墨刀AI提示词教学。内容涵盖高质量原型撰写公式与实操窍门,助您轻松掌握AI设计工具。无论是零基础入门还是进阶技巧,都能让您快速上手,大幅提升产品设计与协作效率。

2026.08.04

10

21

墨刀AI完整入门
墨刀AI完整入门

PHP中文网为您倾力打造墨刀AI保姆级入门指南完整版!本合集从零基础讲起,涵盖AI生成原型、提示词优化、图片转原型及多轮对话等核心功能。无论您是新手还是进阶用户,都能轻松掌握产品设计全流程。快来PHP中文网,一键解锁高效设计技巧,让想法即刻成型!

2026.08.04

7

20

墨刀AI进阶技巧
墨刀AI进阶技巧

本合集由PHP中文网精心整理,为您提供墨刀AI核心进阶策略指南。内容涵盖高效提示词写作、原型智能生成与微调、结构化导图制作及行业分析报告输出等实战技巧。助您轻松掌握AI设计工具,大幅提升产品设计与团队协作效率。

2026.08.04

10

14

火山引擎实名认证失败怎么办
火山引擎实名认证失败怎么办

火山引擎实名认证失败可能与证件信息填写错误、姓名或企业信息不一致、证件照片不清晰、营业执照状态异常、手机号验证失败或审核资料不完整有关。本专题整理个人认证、企业认证、资料上传、审核退回、重新提交和认证不通过的常见处理方法。

2026.08.04

5

10

火山引擎域名备案流程详解
火山引擎域名备案流程详解

火山引擎域名备案适合需要在火山引擎云服务器、对象存储、CDN或网站服务上绑定域名的用户参考。本专题整理备案入口、账号实名认证、备案类型选择、主体信息填写、网站信息提交、资料上传、初审核验、管局审核和备案失败排查,帮助用户完成网站上线前的备案流程。

2026.08.04

1

10

火山引擎DNS解析配置步骤
火山引擎DNS解析配置步骤

使用火山引擎DNS解析网站域名时,需要确认域名已完成管理接入,并正确配置服务器IP、CNAME地址或验证记录。本专题整理域名添加、记录类型选择、TTL设置、解析状态检查、备案和访问测试等流程,适合新手搭建网站时参考。

2026.08.04

3

10

火山引擎对象存储使用教程
火山引擎对象存储使用教程

火山引擎对象存储适合用于网站图片、视频文件、备份数据、静态资源和应用附件管理。本专题整理TOS控制台入口、存储桶创建、地域选择、权限设置、文件上传、访问链接生成、CDN加速、费用查看和常见上传或访问失败问题,帮助用户快速掌握对象存储基础操作。

2026.08.04

1

10

热门下载

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

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
React 教程
React 教程

共58课时 | 11.1万人学习

国外Web开发全栈课程全集
国外Web开发全栈课程全集

共12课时 | 1.3万人学习