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

如何高效抓取动态加载的网页内容:以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 requestsfrom bs4 import BeautifulSoupurl = "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渲染到页面上。

    使用浏览器开发者工具

    打开目标网页: 在Chrome、Firefox等浏览器中打开目标网页。打开开发者工具: 按F12键或右键点击页面选择“检查”。切换到“网络” (Network) 选项卡: 这个选项卡会显示浏览器加载页面时发出的所有请求。过滤XHR/Fetch请求: 在“网络”选项卡中,通常有一个过滤器选项,选择“XHR”或“Fetch/XHR”,这样可以只显示JavaScript发起的异步请求。刷新页面或触发内容加载: 如果内容是页面加载时自动填充的,刷新页面即可看到相关请求。如果内容是通过点击按钮、滚动等方式触发的,则需要执行相应的操作。检查请求: 仔细查看这些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 requestsimport stringimport 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)

    代码解析

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

    注意事项与总结

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

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

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

    以上就是如何高效抓取动态加载的网页内容:以BeautifulSoup与XHR请求为例的详细内容,更多请关注php中文网其它相关文章!

    版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
    如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
    发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1598457.html

    (0)
    打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
    上一篇 2025年12月23日 12:56:21
    下一篇 2025年12月23日 12:56:41

    相关推荐

    • CSS背景图片全屏缩放问题的解决方案与最佳实践

      当网页背景图片在全屏模式下出现意外缩放或放大时,通常是由于background-size: cover属性的行为所致。本文将深入探讨cover和contain等background-size属性值的差异,并提供详细的css解决方案,指导您如何有效地控制背景图片在不同屏幕分辨率下保持预期的尺寸和比例,…

      2025年12月23日
      000
    • Bootstrap 5下实现特定区域滚动时二级粘性导航栏

      本文详细介绍了如何在Bootstrap 5项目中实现一个二级粘性导航栏。当用户滚动到特定内容区域时,该导航栏将出现在主固定导航栏下方并保持粘性,离开该区域后则消失。核心解决方案利用CSS的position-sticky属性配合top偏移量和z-index,提供了一种纯CSS的简洁高效实现方式,避免了…

      2025年12月23日 好文分享
      000
    • 现代浏览器中媒体自动播放的实现与策略:规避限制,优化用户体验

      现代浏览器为提升用户体验,对媒体自动播放施加了严格限制,要求用户显式交互才能触发播放。本文将深入解析浏览器自动播放策略的原理,解释为何直接使用`autoplay`属性常会失败,并提供符合当前规范的最佳实践和代码示例,指导开发者如何实现用户友好且兼容性良好的媒体播放功能。 理解浏览器自动播放策略 为了…

      2025年12月23日
      000
    • 使用Jinja2与Python动态加载并显示多张图片到HTML

      本文详细介绍了如何利用Jinja2模板引擎与Python后端,高效地将多张图片动态加载并渲染到HTML页面中。核心方法在于将图片数据组织成一个包含字典的列表,其中每个字典代表一张图片及其属性(如标题和文件路径),并通过Jinja2的`for`循环在HTML模板中迭代渲染,从而实现灵活且可维护的多图片…

      2025年12月23日 好文分享
      000
    • 使用 Jinja2 动态渲染多张图片到 HTML 教程

      本教程详细介绍了如何使用 Jinja2 模板引擎,将多张图片动态加载并渲染到 HTML 文件中。核心方法是采用 Python 中的列表嵌套字典结构来组织图片数据,并在 Jinja2 模板中使用 `for` 循环遍历这些数据,从而高效生成包含多张图片的 HTML 内容。 引言 在基于 Python 和…

      2025年12月23日 好文分享
      000
    • 使用 CSS Flexbox 和 Bootstrap 创建三栏网格布局

      本文旨在提供两种实现三栏网格布局的方法:使用 CSS Flexbox 和使用 Bootstrap 网格系统。通过简洁的代码示例和逐步讲解,帮助开发者快速掌握并应用这两种技术,构建灵活且响应式的网页布局。 使用 CSS Flexbox 实现三栏布局 Flexbox 是一种强大的 CSS 布局模块,能够…

      2025年12月23日
      000
    • Python实现HTML结构化数据提取与自定义JSON转换教程

      本教程旨在解决将html文件转换为特定、结构化json格式的需求,而非简单地复制html dom结构。文章将详细指导如何利用python的beautiful soup库高效解析html内容,通过自定义逻辑提取关键文本信息,并构建扁平化或层级化的数据模型,最终将其序列化为符合期望的json格式,从而实…

      2025年12月23日
      000
    • JavaScript实现页面加载后自动选中单选按钮教程

      本教程详细介绍了如何使用javascript在网页加载后,通过`settimeout`函数和`element.click()`方法,实现指定单选按钮的自动选中功能。文章涵盖了核心技术原理、详细的实现步骤、示例代码,并提供了关键的注意事项与最佳实践,旨在帮助开发者优化用户体验或自动化表单操作。 页面加…

      2025年12月23日
      000
    • 快速识别浏览器视口对应的Bootstrap响应式断点

      本文介绍了一个便捷的在线工具,旨在帮助开发者和设计师快速识别当前浏览器视口宽度所对应的bootstrap响应式断点(如x-small、small、medium等)。通过该工具,用户可以直观了解其浏览器窗口在bootstrap框架下的尺寸分类,这对于开发和测试响应式网页布局至关重要,确保设计在不同设备…

      2025年12月23日
      000
    • 如何使用Splinter和BeautifulSoup解决复杂网站的元素选择问题

      本教程旨在解决使用beautifulsoup在复杂网站上选择html元素时遇到的“none”或空结果问题。文章深入探讨了网站重定向、cookie及会话管理等挑战,并详细阐述了如何结合splinter进行浏览器自动化以处理这些动态行为,然后从splinter获取渲染后的html,再利用beautifu…

      2025年12月23日
      000
    • HTML布尔属性:声明元素状态的指南

      html元素通过一系列布尔属性来声明其当前状态,无需javascript即可提供丰富的交互性和控制。这些属性如`open`、`checked`、`disabled`、`autoplay`等,直接影响元素的渲染和行为,是构建语义化和用户友好界面的关键。本文将深入探讨这些常见的状态属性及其应用,帮助开发…

      2025年12月23日
      000
    • 使用Retrofit在Android应用中发送包含HTML字符串的POST请求

      本教程详细阐述了如何在Android应用中使用Retrofit正确地将HTML内容作为字符串嵌入JSON请求体并发送。文章涵盖了请求体数据模型的定义、Retrofit接口的配置,以及通过JSON转换器确保HTML字符串的正确序列化与传输,从而有效处理包含特殊字符的富文本数据。 1. 理解Retrof…

      2025年12月23日
      000
    • 解决响应式导航内容溢出:使用 Flexbox flex-wrap 实现优雅布局

      本教程旨在解决响应式设计中导航栏内容溢出容器的常见问题,尤其是在屏幕分辨率变化时。文章将深入探讨如何利用 CSS Flexbox 的 `display: flex` 和 `flex-wrap: wrap` 属性,确保导航项能够根据可用空间自动调整并换行,从而在不同设备尺寸下保持导航栏的清晰和功能性,…

      2025年12月23日
      000
    • CSS多背景图像与分层布局技巧:实现元素间背景共享与内容分离

      本文探讨如何利用css多背景图像技术,在不影响内容层级的前提下,优雅地实现一个背景图片穿梭于两个独立彩色区域之间的复杂布局。传统绝对定位可能导致内容覆盖问题,而通过在父容器上巧妙组合背景图片和渐变色,并精细控制其位置与大小,可以高效解决此类视觉呈现挑战,创建清晰且响应式的分层设计。 在现代网页设计中…

      2025年12月23日
      000
    • Laravel多选框数据编辑:如何预选中已保存的关联数据

      本文旨在解决laravel应用中编辑界面多选框(`select multiple`)数据预选的问题。当编辑一个已存在的记录时,如何确保多选框自动选中该记录已关联的数据,而非全部选中或全部不选。我们将通过控制器数据准备和视图条件渲染相结合的方式,实现这一功能,提升用户体验。 引言 在构建Laravel…

      2025年12月23日
      000
    • 解决Node.js/EJS项目中CSS文件加载失败的路径问题

      在使用node.js和ejs开发web项目时,css文件无法加载是一个常见问题,通常是由于静态文件路径配置不当所致。本文将深入解析express框架中`express.static`中间件的工作原理,并提供一种简洁有效的解决方案,即调整html文件中css链接的路径,使其与服务器端静态资源根目录保持…

      2025年12月23日
      000
    • HTML表单输入字段值进行数值加法运算的教程

      本教程旨在解决html表单文本输入字段值在进行加法运算时常见的字符串拼接问题。我们将深入探讨如何正确使用javascript的`parsefloat()`函数,确保从“元素获取的值能够被解析为数字,并在用户点击按钮时执行正确的数值加法,而非简单的字符串连接,最终实现动态地显示计算结果。 …

      2025年12月23日
      000
    • 使用CSS变量和JavaScript实现动态主题切换

      本教程详细介绍了如何利用css变量和html的data属性结合javascript,实现网页的动态主题切换功能,例如深色模式与浅色模式。相比直接操作document.stylesheets,这种方法更加简洁、高效且易于维护。文章还进一步探讨了如何使用localstorage来持久化用户的主题偏好,确…

      2025年12月23日
      000
    • PHP表单提交:解决 isset($_POST) 不生效的问题

      本教程旨在解决php表单提交中`isset($_post)`无法正确检测提交按钮的问题。核心原因在于html表单默认的`get`提交方法。文章将详细解释`$_get`与`$_post`超全局变量的区别,并提供正确的代码示例,指导开发者通过在` 根据需求选择方法:如果数据不敏感且希望用户能够分享或收藏…

      2025年12月23日
      000
    • 使用JavaScript安全转换HTML元素的href到data-href属性

      本教程详细介绍了如何使用原生JavaScript精确地将HTML元素的`href`属性转换为`data-href`属性。通过`removeAttribute`和`setAttribute`方法,您可以安全地移除原始`href`并添加带有相同值的`data-href`,避免多余属性的产生,并确保HTM…

      2025年12月23日
      000

    发表回复

    登录后才能评论
    关注微信