使用BeautifulSoup4获取img标签src返回空数组问题求助
问题背景
需要从如下HTML片段中提取img标签的src链接地址:
<a href="https://i.sstatic.net/SvJzr.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/SvJzr.png" alt="enter image description here" /></a>
实际编写代码抓取目标站点的公司logo链接时,所有查找结果均返回空数组[],BeautifulSoup4似乎无法读取class为lazyload-wrapper的div标签内部的内容,原实现代码如下:
from urllib.request import Request from bs4 import BeautifulSoup from urllib.request import Request, urlopen url = 'https://growjo.com/industry/Cannabis' request = Request( url, headers={'User-Agent': 'Mozilla/5.0'} ) page = urlopen(request) page_content_bytes = page.read() page_html = page_content_bytes.decode("utf-8") soup = BeautifulSoup(page_html, "html.parser") company_rows = soup.find_all("table",{"class":"jss31"})[0].find_all("tbody")[0].find_all("tr") for company in company_rows: company_data = company.find_all("td") logo = company_data[1].find_all("div",{"class":"lazyload-wrapper"})[0].find_all("a") name = company_data[1].text print(logo) break
问题原因
- 代码里用来定位表格的
jss31是CSS-in-JS生成的动态类名,这类类名会随版本发布、页面渲染状态变化随机变更,不是稳定的元素定位标识 - 目标站点的公司列表、logo内容是前端JavaScript动态渲染的,
urllib只能拿到页面初始的静态HTML骨架,JS执行完成后才会往lazyload-wrapper节点里填充a、img等内容,静态HTML中这部分节点本身就是空的,自然无法通过BeautifulSoup解析到 - 站点对logo做了懒加载处理,就算JS渲染完成,初始状态下img标签的
src属性也可能是占位图,真实logo地址一般存放在data-src、data-lazy这类自定义属性中,等图片滚动到可视区域才会替换到src上
解决方案
方案1:使用支持JS渲染的抓取工具
替换urllib为可驱动浏览器执行页面JS的工具,等页面完全渲染、接口数据加载完成后再解析DOM,以Playwright为例的实现代码:
from playwright.sync_api import sync_playwright from bs4 import BeautifulSoup with sync_playwright() as p: # 启动无头浏览器 browser = p.chromium.launch(headless=True) page = browser.new_page(user_agent='Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36') page.goto('https://growjo.com/industry/Cannabis', wait_until='networkidle') # 等待表格行加载完成 page.wait_for_selector('table tbody tr') page_html = page.content() browser.close() soup = BeautifulSoup(page_html, "html.parser") # 避开动态类名,直接通过标签结构定位表格行 company_rows = soup.select("table tbody tr") for company in company_rows: company_data = company.find_all("td") if len(company_data) < 2: continue logo_wrapper = company_data[1].select_one(".lazyload-wrapper") if not logo_wrapper: continue logo_img = logo_wrapper.find("img") # 优先读取懒加载属性,再读默认src logo_url = logo_img.get("data-src", logo_img.get("src")) company_name = company_data[1].text.strip() print(company_name, logo_url) break
方案2:直接调用站点数据接口
打开浏览器开发者工具,切换到网络面板筛选XHR/Fetch请求,可以找到页面加载时拉取公司列表的后端接口,接口返回的是结构化JSON数据,直接包含logo地址、公司名称等字段,不需要解析HTML,抓取效率更高,也不会被前端渲染逻辑影响。
注意事项
- 定位页面元素时不要使用
jss、css-开头的动态类名,这类类名随时可能变化,优先使用固定id、角色属性、稳定的标签层级结构做定位 - 解析懒加载图片时,不要只读取
src属性,注意检查元素上的自定义懒加载属性
内容的提问来源于stack exchange,提问作者MaxxABillion
相关产品推荐
相关产品推荐

