html网页的结构由哪些部分组成? html网页结构分析
在Web抓取过程中,网站HTML结构的不一致性常导致程序中断。本文将深入探讨这一常见挑战,以IBM文档网站为例,如何通过分析网站的内部展示API调用来获取稳定并重构的数据。我们将利用Python的httpx和trio进行异步请求,并通过识别的API端点,实现更健壮、高效的数据导出,避免直接可靠易变的HTML结构。Web抓取中HTML结构不一致的挑战
在进行网页抓取时,开发者经常会遇到一个棘手的问题:同一个url在不同或不同的请求条件下返回的html结构可能不尽相同。这可能是由于多种原因造成的,例如:动态加载:现代网站普遍使用JavaScript动态加载。如果爬虫无法正确执行JavaScript内容,可能只能获取到最初的、不完整的HTML内容。A/B测试或个性化时间:网站可能会针对不同用户展示不同版本的页面,或根据用户断层、设备等信息提供个性化内容。用户代理(User-Agent)检测: 网站可能会根据请求头中的User-Agent来判断请求来源是浏览器还是爬虫,从而返回不同的HTML内容,甚至直接返回错误页面或简化版本页面。 服务器端渲染(SSR)与客户端渲染(CSR)混合:某些页面可能部分内容由服务器渲染,部分由客户端渲染,导致第一次请求与完全加载后的DOM结构不一致。错误或重定向: 当原始URL失效或被重定向时,可能会返回一个包含错误信息的HTML页面,而不是预期的内容。
在上述IBM文档网站的案例中,观察到两种不同的HTML结构:一种是包含完整表格数据的预期结构,另一种则包含大量error.sorryText等JavaScript标志,明显是一个错误或备用页面。这表明网站可能根据请求的某些特征,或在无法找到特定内容时,返回不同的响应。识别并利用API数据源
当面对策略刷新的HTML结构时,一个更可靠的方法是尝试识别网站用于加载数据的底层API。很多现代网站,尤其是那些动态加载的网站,通常会通过内部API获取数据,然后直接使用JavaScript在客户端渲染这些数据。这些API端点,往往能获得更稳定、构造的JSON或XML数据,甚至直接是包含目标数据的HTML组件。
要找到这些API端点,通常需要借助浏览器开发者工具(如Chrome) DevTools或Firefox Developer Tools)的“网络”(网络) 它的选项卡。在加载目标页面时,监控所有发出的XHR/Fetch请求,通常可以找到返回所需数据的API调用。
在IBM文档网站的案例中,通过分析请求流程,可以发现首先访问了一个常规URL,然后该页面会提供一个“oldUrl”:“(.*?)”的指针。这个oldUrl实际上指向了一个内部的API端点,该端点能够直接返回其包含表格数据的HTML部分。
立即学习“前端免费学习笔记(深入)”;解决方案:我们异步请求与API调用
为了解决HTML结构不一致的问题,可以采取以下步骤:创一AI
AI助写短视频脚本155查看详情模拟浏览器行为:使用一个真实的用户代理请求头,以近似地模拟浏览器行为,被网站识别为爬虫返回而异常。首次请求获取API线索:对原始URL发起GET请求,解析其内容以提取指向实际数据API的oldUrl。构造API请求:利用提取到的oldUrl正确构建的API请求URL,并添加必要的参数(例如parsebody=true和lang=en),这些参数通常是API正常工作所必需的。发起API请求并解析数据:对API端点发起请求,获取其响应。由于API通常返回更清晰、更格式化的数据(或包含目标HTML片段),我们可以直接使用pandas.read_html()等工具进行高效解析。异步处理: 对于需要抓取大量页面的场景,使用异步HTTP客户端(如httpx)配合异步运行时(如trio或asyncio)可以显着提高抓取效率。
以下是实现这一策略的Python代码示例:import httpx # 异步HTTP客户端import trio # 异步运行时import re # 正则表达式模块 import pandas as pd # 数据处理库# 定义请求头,模拟浏览器headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/113.0'}async def fetch_table_data(identifier: str): quot;quot;quot;异步函数:根据标识符获取表格数据 quot;quot;quot; async with httpx.AsyncClient(headers=headers, base_url='https://www.ibm.com/docs') as client: # 1. 初始化原始URL的参数initial_params = { 'topic':f'tables-{identifier}' # 使用命名的标识符 } # 2.对原始URL发起首次请求,获取包含线索API的HTML #注意:这里假设标识符最终会映射到类似t-accessdateval这样的主题 # 如果原始问题中的URL结构是固定的,如quot;en/imdm/12.0?topic=t-accessdatevalquot;#那么initial_params['topic']应该直接是't-accessdateval'或类似的固定值#这里为了演示通用性,我们用f'tables-{identifier}' # 原始问题中的 URL 是 quot;https://www.ibm.com/docs/en/imdm/12.0?topic=t-accessdatevalquot; # 对应的路径是 'en/imdm/12.0',topic 是 't-accessdateval' # 所以这里的路径和参数需要根据实际情况调整 # 表示标识符已经是 't-accessdateval' 这样的形式初始响应=等待client.get('en/imdm/12.0', params={'topic':identifier}) # 3.使用正则表达式从响应文本中提取 'oldUrl' # 'oldUrl' 通常指向一个内部 API 端点 match = re.search(r'quot;oldUrlquot;:quot;(.*?)quot;',initial_response.text) if not match: print(fquot;无法找到 {identifier} 的
oldUrl。quot;) return pd.DataFrame() # 返回空DataFrame old_url_path = match.group(1) # 4. 构造API请求的URL路径 # API路径通常是 'api/v1/content/' 加上提取的oldUrl api_url_path = quot;api/v1/content/quot; old_url_path # 5. 定义API请求的参数 api_params = { 'parsebody': 'true', #确保API返回解析后的内容 'lang': 'en' # 指定语言 } # 6. 对API端点发起GET请求 api_response = wait client.get(api_url_path, params=api_params) # 7. 使用pandas.read_html直接解析API响应中的表单数据 # attrs={'class': 'defaultstyle'} 用于精准匹配目标表单 try: # api_response.content包含的是HTML片段,pandas可以直接解析dataframes = pd.read_html(api_response.content, attrs={'class': 'defaultstyle'}) if dataframes: df = dataframes[0] # 可以根据需要添加其他信息,例如原始的标识符 df.insert(0, quot;Source_Identifierquot;,identifier) return df else: print(fquot;无法从 {identifier} 的 API 响应中找到表格。
quot;) return pd.DataFrame() except ValueError as e: print(fquot;解析 {identifier} 的 HTML 表格时出错: {e}quot;) return pd.DataFrame()async def main(): # 假设 'identifiers.csv' 包含一列名为 'Identifier' 的数据 # 例如:Identifier # t-accessdateval # t-another-table df_identifiers = pd.read_csv('identifiers.csv') all_dfs = [] # 遍历所有标识符,并发地获取数据 async with trio.TaskGroup() as tg:for index,row in df_identifiers.iterrows():identifier = row['Identifier'] tg.start_soon(lambda id=identifier:all_dfs.append(trio.run(fetch_table_data, id))) # 包装为同步调用以添加到列表 # 注意,trio.run(fetch_table_data, id) 是一个阻塞调用,这里需要调整为异步收集结果 # 正确的异步收集方式如下: # task_result = wait fetch_table_data(identifier) # all_dfs.append(task_result) # 或者更优的,使用 tg.start_soon 来支持运行任务,并收集结果 # 由于 trio.run 不能在另一个 trio.run内部调用,我们需要简单等待调整收集结果的方式 # 内部调用,我们需要简单等待见,这里先串行演示,如果需要一些东西,可以构建一个列表的可等待 # 或者让 fetch_table_data 返回一个 Future/Deferred,然后在 TaskGroup 中 # 对于本教程,我们先采用一个简化的串行起混合方式,或者直接在 main 中串行调用 # 更直接的串行收集方式: #tasks = [tg.start_soon(fetch_table_data,identifier) foridentifier in df_identifiers['Identifier']] # 然后需要一种机制来收集这些任务的结果。
# 这里为了教程的简洁性,先一个可以运行的串行/伪玩具结构, # 真正的资源收集需要更复杂的任务组模式,例如使用 trio.Queue 或共享列表加锁。 # 为了避免复杂性,我们这里直接串行调用,或者展示使用一个简单的异步列表收集 df = wait fetch_table_data(identifier) if not df.empty: all_dfs.append(df) if all_dfs:combined_df = pd.concat(all_dfs,ignore_index=True) print(combined_df)combined_df.to_csv('combined_table_data_api.csv',index=False) else: print(quot;未获取到任何数据。quot;)if __name__ == quot;__main__quot;: trio.run(main)登录后复制
代码解析:httpx和trio: httpx是一个现代的HTTP客户端,支持同步和异步请求。trio是一个异步I/O库,提供了一种格式化的并行编程方式。headers:设置User-Agent,模拟浏览器请求,这对于避免被网站反爬机制识别非常重要。fetch_table_data函数:接收标识符作为参数,用于构建URL。首先向en/imdm/12.0路径发送请求,并形成topic参数。使用re.search从响应文本中查找"oldUrl":"(.*?)"模式,提取出实际的API路径。将提取到的oldUrl_path与api/v1/content/粘贴,形成完整的API请求路径。向这个API路径发送请求,并带上parsebody=true和lang=en参数,这些参数告诉API返回可解析的HTML内容。pd.read_html(api_response.content, attrs={'类': 'defaultstyle'}):这是核心步骤。pandas库的read_html函数可以直接从HTML内容中识别并提取表格,返回一个DataFrame列表。attrs={'class': 'defaultstyle'}用于指定只查找class为defaultstyle的表格,提高准确性。将获取到的DataFrame添加一个Source_Identifier列,以便追踪数据来源。main函数:读取包含标识符的CSV文件。获取每个标识符,调用fetc h_table_data函数获取数据。为了教程简洁,这里展示的是串行调用。在实际大规模抓取中,应利用trio.TaskGroup等实现真正的向量。将获取所有到的DataFrame合并成一个。打印并保存最终的合并数据到CSV文件。总结与最佳实践深入分析网站行为:当HTML结构不稳定时,不要只研究HTML本身,而要利用浏览器开发者工具(Network Tab)观察网站的实际数据加载方式,尤其是XHR/Fetch请求。
优先使用API:网站有明确的API来提供数据,需要直接调用API。API通常提供更稳定、格式化、易于解析的数据格式(如JSON、XML),且不易受UI胁迫的影响。模拟真实用户:使用合适的User-Agent和其他HTTP请求头(如Referer、Accept-Language等)来模拟真实浏览器,可以有效避免被网站的内容反抓取机制或返回异常。异步编程:用于需要处理大量请求的Web爬虫任务,httpx配合asyncio或trio等异步库可以显着提升性能和效率。健壮性与错误处理:在代码中加入适当的错误处理机制(如try- except块),以应对网络错误、API响应异常或解析失败等情况,确保爬虫的稳定运行。遵守Robots协议和使用网站条款:在进行Web抓取时,一定要检查网站的robots.txt文件,并遵守网站的使用条款,进行增益的抓取。
通过上述方法,我们可以更有效地应对Web抓取中HTML结构不一致的挑战,构建出更稳定、高效的数据抓取系统。
以上就是解决Web抓取中HTML结构不一致问题:IBM文档网站案例分析的详细内容,更多请关注乐哥常识网相关文章! ARM dom异步http ui大家都在看:JavaScript中监听单选按钮选中状态变化的事件处理 使用CSS关键帧动画和JavaScript实现箭头碰撞效果 使用CSS关键帧和JavaScript创建箭头动画解决JavaScript中滚动阻塞问题:利用调试器及高级调试技巧 如何在外部JavaScript函数中更新Alpine.js x-data状态