
当pandas.read_html无法从网页中提取表格时,通常是因为表格内容是动态加载的,而非直接存在于初始html源码中。本教程将指导您如何利用浏览器开发者工具识别这些动态数据请求(xhr),并通过python的requests库模拟这些请求,直接获取json格式的原始数据,最终使用pandas将其转换为dataframe,从而有效解决动态表格的数据抓取问题。
理解pandas.read_html的局限性
pandas.read_html是一个非常便捷的函数,它能够解析HTML文档中的
标签并将其转换为DataFrame列表。然而,它的工作原理是解析网页的初始HTML源代码。这意味着,如果网页上的表格数据是通过JavaScript在页面加载完成后动态生成的(例如,通过AJAX或XHR请求从后端获取数据并渲染),read_html在检查原始HTML时将无法找到这些表格,从而返回一个空列表。即使使用Selenium等工具获取渲染后的HTML,如果数据本身是通过JavaScript注入到空表格结构中的,get_attribute('outerHTML')也可能返回一个空的表格框架。识别动态加载的数据源
解决这类问题的关键在于找出JavaScript是从何处获取这些动态数据的。这通常涉及到监控浏览器的网络活动。
-
打开浏览器开发者工具: 在目标网页上,按下F12键(或右键点击页面选择“检查”),打开开发者工具。
-
切换到“网络”(Network)选项卡: 此选项卡显示了浏览器加载页面时发出的所有请求。
-
筛选XHR/Fetch请求: 在“网络”选项卡中,通常有一个筛选器,选择“XHR”或“Fetch/XHR”。这些是异步JavaScript和XML/HTTP请求,它们通常用于动态加载数据。
-
重新加载页面或触发数据加载: 刷新页面,或者执行任何会触发表格数据显示的操作(例如点击分页、筛选按钮),然后观察XHR请求列表。
-
检查可疑请求: 寻找那些看起来像是获取表格数据的请求。点击这些请求,查看其“标头”(Headers)、“负载”(Payload/Form Data)和“响应”(Response)。
-
请求URL: 这是数据实际发送到的API端点。
-
请求方法: 通常是GET或POST。
-
请求负载/表单数据: 如果是POST请求,这里会包含发送给服务器的参数。
-
响应: 这是服务器返回的数据,通常是JSON格式,也可能是XML或其他文本格式。
通过上述步骤,我们可以发现原始问题中的表格数据并非直接嵌入在HTML中,而是通过一个POST请求发送到https://anex.us/grades/getData/这个URL,并附带了dept和number等参数来获取特定课程的数据。
使用requests库获取动态数据
一旦确定了数据的API端点、请求方法和所需参数,我们就可以使用Python的requests库来模拟这个请求,直接获取原始数据。
立即学习“前端免费学习笔记(深入)”;
import requests
import pandas as pd
# 目标API的URL,通过开发者工具的XHR请求中获取
url = 'https://anex.us/grades/getData/'
# 请求负载(payload),根据XHR请求的Form Data或Request Payload确定
# 这里模拟查询ENGR系102课程的数据
payload = {'dept': 'ENGR', 'number': '102'}
# 请求头(headers),模拟浏览器行为,特别是User-Agent,以避免被服务器识别为爬虫
# User-Agent可以从浏览器开发者工具的Request Headers中复制
headers = {
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:120.0) Gecko/20100101 Firefox/120.0'
}
# 发送POST请求
# 对于GET请求,应使用 requests.get(url, params=payload, headers=headers)
response = requests.post(url, data=payload, headers=headers)
# 检查请求是否成功(状态码200)
response.raise_for_status() # 如果请求失败,会抛出HTTPError
# 解析JSON响应
# 大多数动态数据API会返回JSON格式
data = response.json()
# 将JSON数据转换为Pandas DataFrame
# 根据JSON结构,数据通常嵌套在某个键下,例如这里的'classes'
df = pd.DataFrame(data['classes'])
# 打印DataFrame的前几行以验证数据
print(df.head())登录后复制
输出示例:
dept number section A B C D F I S U Q X prof year semester gpa
0 ENGR 102 20 18 17 8 2 3 0 0 0 1 0 AMINI N 2018 FALL 2.9375
1 ENGR 102 21 18 31 15 4 1 0 0 0 0 0 KOOLA P 2018 FALL 2.88405797101449
2 ENGR 102 22 10 28 16 2 3 0 0 0 0 0 SHAW S 2018 FALL 2.67796610169492
3 ENGR 102 26 9 24 10 4 6 0 0 0 0 0 SUBRAMANIAN R 2018 FALL 2.49056603773585
4 ENGR 102 201 21 12 1 1 0 0 0 0 0 0 IJAZ M 2018 FALL 3.51428571428571
登录后复制
注意事项与最佳实践
-
User-Agent的重要性: 在headers中设置User-Agent可以模拟真实的浏览器请求,这对于避免某些网站的反爬机制非常重要。
-
请求方法(GET vs. POST): 根据开发者工具中XHR请求的“方法”字段,选择requests.get()或requests.post()。GET请求的参数通常通过params字典传递,而POST请求的参数通过data字典(或json字典,如果发送JSON数据)传递。
-
响应数据格式: 大多数现代Web API返回JSON格式的数据,可以直接使用response.json()解析。如果响应是其他格式(如XML、CSV、纯文本),则需要使用相应的库或方法进行解析。
-
错误处理: 始终添加错误处理机制,例如使用response.raise_for_status()检查HTTP状态码,或者使用try-except块处理网络请求或JSON解析错误。
-
网站使用条款: 在抓取任何网站数据之前,请务必查阅其robots.txt文件和使用条款,确保您的行为符合规定,避免对网站服务器造成不必要的负担。
-
何时使用无头浏览器: 如果通过XHR请求仍然无法获取到完整或正确的数据,或者数据在客户端经过复杂的JavaScript处理才最终呈现,那么使用无头浏览器(如Selenium配合Chrome/Firefox)可能是唯一的选择。然而,直接模拟API请求通常效率更高、资源消耗更少。
总结
当pandas.read_html无法正常工作时,通常意味着数据是动态加载的。通过熟练运用浏览器开发者工具,我们可以“窥探”到网页背后数据流动的秘密,识别出数据源的API请求。随后,利用requests库模拟这些请求,直接获取原始数据(通常是JSON),并结合pandas进行数据清洗和结构化,就能高效、精准地抓取到所需信息。这种方法不仅解决了read_html的局限性,也为处理更复杂的动态网页数据提供了强大的解决方案。
以上就是解决Pandas read_html无法识别动态加载表格的问题的详细内容,更多请关注php中文网其它相关文章!