如何从JavaScript渲染页面中用BeautifulSoup获取图片?
解决JS渲染页面的图片抓取问题
针对你遇到的requests和Selenium都无法获取到图片内容的问题,给出以下两种可行方案:
方案一:优化Selenium等待逻辑,确保页面完全渲染
你之前用Selenium只拿到初始HTML,大概率是因为没有等待JavaScript完成页面渲染。SPA(单页应用)的初始HTML只有空容器,内容全靠后续JS动态加载,所以必须等待元素加载完成后再获取源码。
示例代码:
from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from bs4 import BeautifulSoup import base64 import os # 初始化浏览器驱动(确保ChromeDriver路径正确) driver = webdriver.Chrome() target_url = "https://air.ifpshare.com/documentPreview.html?s_id=8ec97e16-51c4-4a77-9f64-7d5dccd9bb41#/detail/561f0184-384c-4ca1-91a4-b2e687865408/record" driver.get(target_url) try: # 显式等待图片元素出现(根据实际元素调整选择器) # 假设图片是带有data:image开头src的img标签 WebDriverWait(driver, 15).until( EC.presence_of_element_located((By.CSS_SELECTOR, "img[src^='data:image']")) ) except Exception as e: print(f"等待图片加载超时: {str(e)}") driver.quit() exit() # 获取渲染后的完整页面源码 page_source = driver.page_source driver.quit() # 解析页面提取Base64图片并保存 soup = BeautifulSoup(page_source, "html.parser") img_elements = soup.select("img[src^='data:image']") div_elements = soup.select("div[style*='data:image']") # 处理背景图形式的Base64图片 # 创建保存目录 os.makedirs("downloaded_images", exist_ok=True) # 处理img标签的图片 for idx, img in enumerate(img_elements): src = img["src"] # 分离Base64编码部分 img_data = src.split(",")[1] # 确定图片格式 img_format = src.split(";")[0].split("/")[1] # 解码并保存 with open(f"downloaded_images/img_{idx}.{img_format}", "wb") as f: f.write(base64.b64decode(img_data)) # 处理div背景图的图片 for idx, div in enumerate(div_elements): style = div["style"] # 提取Base64部分 img_data = style.split("url(data:image/")[1].split(";base64,")[1].split(")")[0] img_format = style.split("url(data:image/")[1].split(";base64")[0] with open(f"downloaded_images/div_bg_{idx}.{img_format}", "wb") as f: f.write(base64.b64decode(img_data))
方案二:直接抓取API接口(更高效)
SPA页面的图片数据几乎都是通过后端API获取的,你可以通过Chrome开发者工具抓包找到对应的接口,直接用requests请求接口拿到图片数据,比模拟浏览器更高效。
操作步骤:
- 打开Chrome浏览器,访问目标页面,按F12打开开发者工具。
- 切换到Network标签,勾选XHR/Fetch过滤选项。
- 刷新页面,观察所有请求,找到返回数据包含Base64图片或图片相关字段的接口(通常是带有
detail、record等关键词的接口)。 - 点击该接口,查看Request URL、Request Method(GET/POST)、Headers(尤其是Cookie、User-Agent、Authorization等)、Request Payload(如果是POST请求)。
- 用requests模拟该请求,直接获取图片数据。
示例代码(假设抓包到的API是GET请求):
import requests import base64 import os headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36", "Cookie": "这里替换成你抓包到的Cookie" } # 替换成抓包到的API地址 api_url = "https://air.ifpshare.com/api/document/detail" params = { "s_id": "8ec97e16-51c4-4a77-9f64-7d5dccd9bb41", "record_id": "561f0184-384c-4ca1-91a4-b2e687865408" } response = requests.get(api_url, headers=headers, params=params) data = response.json() # 假设返回的JSON里有images字段,每个元素包含base64数据和格式 os.makedirs("downloaded_images", exist_ok=True) for idx, img_info in enumerate(data["images"]): img_data = img_info["base64"] img_format = img_info["format"] with open(f"downloaded_images/api_img_{idx}.{img_format}", "wb") as f: f.write(base64.b64decode(img_data))
注意事项:
- 接口请求可能需要携带有效的Cookie或Token,这些信息会随着会话过期,所以要在链接有效期内抓取。
- 如果接口有签名验证,可能需要分析JS代码生成签名,这种情况优先用方案一。
内容的提问来源于stack exchange,提问作者realreal
相关产品推荐
相关产品推荐

