0

0

如何高效抓取动态加载的网页内容:以BeautifulSoup与XHR请求为例

碧海醫心

碧海醫心

发布时间:2025-11-23 12:51:21

|

768人浏览过

|

来源于php中文网

原创

如何高效抓取动态加载的网页内容:以BeautifulSoup与XHR请求为例

本教程旨在解决使用beautifulsoup抓取网页时,因内容动态加载而导致目标标签为空的问题。文章将深入探讨传统静态抓取工具的局限性,指导读者利用浏览器开发者工具识别并直接请求隐藏在xhr(xmlhttprequest)中的真实数据源,并通过python的`requests`库处理json响应,从而实现对动态内容的精准抓取。

理解动态内容抓取的挑战

在使用Python进行网页抓取时,BeautifulSoup库因其强大的HTML/XML解析能力而广受欢迎。然而,当目标网页的内容是通过JavaScript动态加载时,仅依赖requests.get()获取的初始HTML文档往往无法包含所有期望的数据。此时,BeautifulSoup解析到的特定标签(例如一个带有id的

    标签)可能会显示为空,即使在浏览器中查看时该标签下有丰富的内容。这是因为requests.get()只获取了服务器返回的原始静态HTML,而JavaScript在页面加载后才执行并填充了这些内容。

    例如,尝试从一个动态加载内容的页面抓取id="demoFour"的

      标签,可能会得到一个空的
        标签:
        import requests
        from bs4 import BeautifulSoup
        
        url = "https://www.parliament.lk/en/members-of-parliament/directory-of-members/?cletter=A"
        response = requests.get(url)
        soup = BeautifulSoup(response.text, 'html.parser')
        
        # 尝试查找id为demoFour的ul标签
        ul_tag = soup.find('ul', id='demoFour')
        print(ul_tag)
        # 预期输出可能是:
          # 实际上,在浏览器中这个ul标签下有li列表项

          识别动态数据源:XHR请求

          要解决这个问题,关键在于识别并直接访问那些负责动态加载数据的幕后请求。这些请求通常是XHR(XMLHttpRequest)或Fetch API请求,它们在后台与服务器通信,获取JSON或XML格式的数据,然后由JavaScript渲染到页面上。

          使用浏览器开发者工具

    1. 打开目标网页: 在Chrome、Firefox等浏览器中打开目标网页。
    2. 打开开发者工具: 按F12键或右键点击页面选择“检查”。
    3. 切换到“网络” (Network) 选项卡: 这个选项卡会显示浏览器加载页面时发出的所有请求。
    4. 过滤XHR/Fetch请求: 在“网络”选项卡中,通常有一个过滤器选项,选择“XHR”或“Fetch/XHR”,这样可以只显示JavaScript发起的异步请求。
    5. 刷新页面或触发内容加载: 如果内容是页面加载时自动填充的,刷新页面即可看到相关请求。如果内容是通过点击按钮、滚动等方式触发的,则需要执行相应的操作。
    6. 检查请求: 仔细查看这些XHR请求的URL、请求方法(GET/POST)、请求头(Headers)、请求载荷(Payload)以及响应(Response)。通常,数据会以JSON格式在响应中返回。

    通过检查,我们会发现原页面中议员列表的数据并非直接嵌入HTML,而是通过一个POST请求发送到https://www.parliament.lk/members-of-parliament/directory-of-members/index2.php?option=com_members&task=all&tmpl=component&letter={letter}&wordfilter=&search_district=这样的API端点,并以JSON格式返回。

    直接请求API并处理数据

    一旦找到了实际的数据API端点,我们就可以直接使用requests库向其发送请求,获取原始数据。

    示例代码

    以下代码演示了如何通过直接调用XHR API来获取斯里兰卡议会成员的列表数据:

    import requests
    import string
    import json # 导入json模块以更好地处理JSON数据
    
    # 存储所有议员数据的列表
    all_members_data = []
    
    # 遍历字母A-Z,因为议员列表是按字母分类加载的
    for letter in list(string.ascii_uppercase):
        # 构建API请求URL。注意这里使用了POST请求
        # 这个URL是通过浏览器开发者工具的XHR请求中发现的
        api_url = f'https://www.parliament.lk/members-of-parliament/directory-of-members/index2.php?option=com_members&task=all&tmpl=component&letter={letter}&wordfilter=&search_district='
    
        try:
            # 发送POST请求到API端点
            # 实际的网页可能会在请求头中包含其他参数,例如User-Agent,
            # 如果遇到反爬,可能需要模拟更多请求头
            response = requests.post(api_url)
            response.raise_for_status() # 检查请求是否成功(状态码200)
    
            # 解析JSON响应
            members_json = response.json()
    
            # 遍历返回的每个议员数据项
            for member_info in members_json:
                # 提取所需信息并构建字典
                member_details = {
                    'url': f"https://www.parliament.lk/en/members-of-parliament/directory-of-members/viewMember/{member_info['mem_intranet_id']}",
                    'id': member_info['mem_intranet_id'],
                    'name': member_info['member_sname_eng']
                }
                all_members_data.append(member_details)
    
        except requests.exceptions.RequestException as e:
            print(f"请求字母 {letter} 时发生错误: {e}")
        except json.JSONDecodeError as e:
            print(f"解析字母 {letter} 的JSON响应时发生错误: {e}")
    
    # 打印获取到的部分数据作为示例
    print(json.dumps(all_members_data[:5], indent=2, ensure_ascii=False)) # 打印前5条数据,格式化输出
    
    # 如果需要,可以将所有数据保存到文件
    # with open('parliament_members.json', 'w', encoding='utf-8') as f:
    #     json.dump(all_members_data, f, indent=2, ensure_ascii=False)

    代码解析

    1. import requests, string, json: 导入必要的库。string用于生成字母列表,json用于处理API返回的JSON数据。
    2. all_members_data = []: 初始化一个空列表,用于存储所有抓取到的议员信息。
    3. for letter in list(string.ascii_uppercase):: 循环遍历所有大写字母(A到Z)。这是因为目标网站的议员列表是按姓氏首字母分类加载的,通过改变API请求中的letter参数来获取不同字母开头的议员。
    4. api_url = f'...': 构建API请求的URL。这个URL是根据在浏览器开发者工具中分析XHR请求得到的。
    5. requests.post(api_url): 发送HTTP POST请求到API端点。注意,这里是post而不是get,因为开发者工具显示该请求是POST类型。
    6. response.raise_for_status(): 这是一个良好的实践,用于检查请求是否成功。如果HTTP状态码表示错误(如4xx或5xx),它会抛出一个requests.exceptions.HTTPError。
    7. members_json = response.json(): 将API响应体解析为Python字典或列表(如果响应是JSON格式)。
    8. 数据提取与存储: 遍历members_json中的每个成员对象,提取mem_intranet_id和member_sname_eng等关键信息,并构造一个包含议员详情URL、ID和姓名的字典,然后将其添加到all_members_data列表中。
    9. 错误处理: 使用try-except块捕获可能的requests请求错误和json解析错误,增强代码的健壮性。

    注意事项与总结

    1. 动态内容是常态: 现代网页开发中,动态加载内容已成为主流。当BeautifulSoup抓取不到数据时,首先应怀疑是否为动态加载。
    2. 开发者工具是利器: 熟练使用浏览器开发者工具是抓取动态网页的关键技能。特别是“网络”选项卡,能揭示所有HTTP请求的细节。
    3. API稳定性: 直接调用网站的内部API可能会受网站更新影响而失效。网站所有者随时可能更改API端点、参数或响应格式。
    4. 请求头模拟: 有些网站会检查请求头,例如User-Agent。如果直接请求API被拒绝,尝试在requests.post()或requests.get()中添加headers参数来模拟浏览器行为。
    5. 频率限制与道德: 抓取网站数据时,请务必遵守网站的robots.txt协议,并控制请求频率,避免对目标服务器造成过大负担。过高的请求频率可能导致IP被封禁。
    6. 数据格式: 大多数动态内容API返回JSON格式数据,但也有可能是XML或其他格式。根据实际响应调整解析方法。

    通过上述方法,我们不仅解决了最初

      标签为空的问题,更掌握了抓取动态网页的核心技术。这种直接与后端API交互的方式,通常比模拟浏览器行为(如使用Selenium)更高效、资源消耗更低,是处理这类抓取任务的首选方案。

    相关专题

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

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

    751

    2023.06.15

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

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

    636

    2023.07.20

    python能做什么
    python能做什么

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

    758

    2023.07.25

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

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

    618

    2023.07.31

    python教程
    python教程

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

    1262

    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相关的文章、下载、课程内容,供大家免费下载体验。

    706

    2023.08.11

    Java 桌面应用开发(JavaFX 实战)
    Java 桌面应用开发(JavaFX 实战)

    本专题系统讲解 Java 在桌面应用开发领域的实战应用,重点围绕 JavaFX 框架,涵盖界面布局、控件使用、事件处理、FXML、样式美化(CSS)、多线程与UI响应优化,以及桌面应用的打包与发布。通过完整示例项目,帮助学习者掌握 使用 Java 构建现代化、跨平台桌面应用程序的核心能力。

    34

    2026.01.14

    热门下载

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

    精品课程

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

    共137课时 | 8.6万人学习

    JavaScript ES5基础线上课程教学
    JavaScript ES5基础线上课程教学

    共6课时 | 7万人学习

    PHP新手语法线上课程教学
    PHP新手语法线上课程教学

    共13课时 | 0.9万人学习

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

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