
本教程旨在解决使用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)# 预期输出可能是:识别动态数据源: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
微信扫一扫
支付宝扫一扫