在进行网页数据抓取时,开发者常会遇到一个普遍问题:尽管通过requests库成功获取了网页的html内容,但使用beautifulsoup等解析库却无法找到页面上明显存在的元素。这通常是因为目标网站采用了javascript动态加载内容的技术。这意味着当您使用requests.get()请求页面时,服务器返回的html文档可能只包含一个基础框架,而实际的数据(例如uniprot的条目id列表)是在浏览器端通过javascript执行异步请求(ajax/fetch)后才填充到页面中的。
对于UniProt网站,当我们尝试使用以下代码来提取条目ID时:
import requests from bs4 import BeautifulSoup url = "https://www.uniprot.org/uniprotkb?query=wound+healing" res = requests.get(url) res.raise_for_status() soup = BeautifulSoup(res.text, "html.parser") links = soup.find_all("a", class_="BqBnJ") # 此时 links 将是一个空列表,因为包含 ID 的内容尚未加载
尽管print(res.text)能够显示HTML文本,但其中并不包含那些动态加载的<a class="BqBnJ" ...>标签。这是因为requests库只获取了服务器的原始响应,并未执行任何JavaScript代码。因此,BeautifulSoup在解析这个初始HTML时,自然无法找到动态生成的内容。
解决方案:利用UniProt REST API面对动态加载内容,最稳健且推荐的解决方案是使用网站提供的官方API(Application Programming Interface)。API是网站为了方便开发者程序化访问其数据而设计的一套接口。UniProt提供了一个功能强大的REST API,允许用户直接查询和获取蛋白质数据,而无需进行网页解析。
1. 通过REST API进行基本搜索和ID提取UniProt REST API的/uniprotkb/search端点允许我们根据查询条件搜索蛋白质条目,并指定需要返回的字段。这比模拟浏览器行为抓取网页要高效和稳定得多。
以下代码演示了如何使用UniProt REST API来搜索“wound healing”相关的条目,并提取它们的“primaryAccession”(即UniProt ID):
import requests import json # 用于处理JSON响应 api_url = "https://rest.uniprot.org/uniprotkb/search" # 定义查询参数 params = { "fields": "accession,id,protein_name,gene_names,organism_name,length", # 指定需要返回的字段 "query": "(wound healing)", # 查询字符串 "size": 5 # 限制返回结果的数量,便于演示 } try: # 发送GET请求到API response = requests.get(api_url, params=params) response.raise_for_status() # 检查请求是否成功(状态码200) # 解析JSON响应 data = response.json() print("--- 提取的UniProt条目ID ---") if "results" in data and data["results"]: for r in data["results"]: print(r["primaryAccession"]) else: print("未找到匹配的条目。") except requests.exceptions.RequestException as e: print(f"请求失败: {e}") except json.JSONDecodeError: print("无法解析API响应为JSON。")
代码解析:
- api_url: UniProt搜索API的基地址。
- params: 一个字典,包含了API请求的各种参数。
- fields: 指定您希望从每个条目中获取哪些信息,例如accession(主登录号,即ID)、id(条目ID)、protein_name等。
- query: 您的搜索关键词。
- size: 可选参数,用于限制返回结果的数量。
- requests.get(api_url, params=params): 发送带有指定参数的GET请求。
- response.raise_for_status(): 如果HTTP请求返回了错误状态码(如4xx或5xx),将抛出HTTPError异常。
- response.json(): 将API返回的JSON格式数据解析为Python字典。
- data["results"]: UniProt API的响应通常包含一个results列表,其中每个元素代表一个匹配的蛋白质条目。
- r["primaryAccession"]: 从每个条目字典中提取primaryAccession字段,这就是我们需要的UniProt ID。
示例输出:
--- 提取的UniProt条目ID --- O00622 Q15746 Q04912 P08581 Q611762. 模拟“下载”功能进行批量数据流式获取
UniProt API还提供了/uniprotkb/stream端点,它更适合于批量下载大量数据,类似于网站上的“下载”按钮功能。通过这个端点,您可以指定下载格式(如JSON、FASTA、TXT等)和是否压缩。
以下代码展示了如何使用/stream端点来获取“wound healing”查询的所有结果,并以JSON格式返回:
import requests import json api_url_stream = "https://rest.uniprot.org/uniprotkb/stream" # 定义流式下载参数 params_stream = { "compressed": "false", # 不压缩 "download": "true", # 模拟下载行为 "format": "json", # 指定下载格式为JSON "query": "(wound healing)", "size": 5 # 限制返回结果的数量,便于演示 } try: # 发送GET请求到API response_stream = requests.get(api_url_stream, params=params_stream) response_stream.raise_for_status() # 解析JSON响应 data_stream = response_stream.json() print("\n--- 通过流式API提取的UniProt条目ID ---") if "results" in data_stream and data_stream["results"]: for r in data_stream["results"]: print(r["primaryAccession"]) else: print("未通过流式API找到匹配的条目。") except requests.exceptions.RequestException as e: print(f"流式请求失败: {e}") except json.JSONDecodeError: print("无法解析流式API响应为JSON。")
代码解析:
- api_url_stream: UniProt流式API的基地址。
- params_stream:
- compressed: 是否压缩返回数据。
- download: 设为true以模拟下载。
- format: 指定输出格式,这里是json。
- 其余部分与基本搜索类似,都是处理JSON响应并提取primaryAccession。
- 优先使用官方API: 当目标网站提供API时,始终优先选择API而非网页抓取。API通常更稳定、数据结构化、且不易受到网站UI变动的影响。
- 查阅API文档: 在使用任何API之前,务必详细阅读其官方文档。文档会说明可用的端点、参数、返回格式、认证方式(如果需要)、以及重要的速率限制(Rate Limit)。了解速率限制对于避免IP被封锁至关重要。
- 错误处理: 在实际应用中,务必添加健壮的错误处理机制,例如使用try-except块来捕获网络请求失败、JSON解析失败等异常。
- 识别动态内容: 如果您不确定某个网站的内容是否是动态加载的,可以使用浏览器的开发者工具。在“Network”(网络)选项卡中,刷新页面并观察是否有XHR或Fetch请求加载了您所需的数据。这些请求的URL通常就是您可以直接调用的API端点。
- 遵守服务条款: 在进行任何数据抓取或API调用时,请务必遵守网站的服务条款和使用政策。
通过本教程,我们理解了传统网页抓取方法在面对JavaScript动态加载内容时的局限性,并掌握了利用UniProt REST API高效、稳定地获取蛋白质条目ID的方法。这种方法不仅解决了动态内容的问题,还提供了更结构化、更易于处理的数据。在未来的数据获取任务中,识别动态内容并优先考虑使用官方API将是您提升效率和代码鲁棒性的关键。
以上就是高效获取UniProt数据库条目ID:应对动态加载与API应用实践的详细内容,更多请关注知识资源分享宝库其它相关文章!
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。