
本文揭示了使用 selenium + beautifulsoup 解析动态网页时图片 url 随机缺失的根本原因,并提供一种稳定、高效、无需浏览器渲染的替代方案——直接调用网站隐藏的 ajax 接口获取结构化数据。
本文揭示了使用 selenium + beautifulsoup 解析动态网页时图片 url 随机缺失的根本原因,并提供一种稳定、高效、无需浏览器渲染的替代方案——直接调用网站隐藏的 ajax 接口获取结构化数据。
在开发房产信息爬虫时,你可能遇到一个令人困惑的现象:同一套 HTML 结构、相同 CSS 类名、甚至完全一致的 <img alt="解决网页解析器随机丢失图片 URL 的根本方法:绕过前端渲染,直连后端 API" > 标签写法,却在部分公寓条目中始终无法提取 src 属性——这并非代码逻辑错误,而是典型的「前端异步渲染陷阱」。
回顾原始代码,问题根源清晰可见:
- 你依赖
driver.page_source获取 HTML,但该快照仅包含当前 DOM 状态; - 目标网站(etalongroup.ru)使用 Vue.js 构建,公寓卡片中的图片由 JavaScript 懒加载(lazy-loaded)或条件渲染(v-if/v-show) 动态插入;
- 即使页面已“滚动到底部”并点击多次“加载更多”,某些
<img alt="解决网页解析器随机丢失图片 URL 的根本方法:绕过前端渲染,直连后端 API" >元素可能因网络延迟、资源未触发加载、或 Vue 组件未完成挂载而尚未被注入 DOM; -
BeautifulSoup是静态解析器,它无法等待 JS 执行完毕——一旦page_source被读取,缺失即成定局。
更关键的是:你已在调试中验证——纯 HTML 字符串用 BeautifulSoup 可完美提取该图片。这彻底排除了选择器错误或 HTML 差异的可能,将问题锁定在 Selenium 捕获时机与前端渲染节奏不同步 上。
✅ 正确解法:跳过渲染层,直连后端 API
深入分析网站网络请求(通过浏览器开发者工具 → Network → XHR),可发现其真实数据来源是:
立即学习“前端免费学习笔记(深入)”;
前端设计与 UI/UX 全方位优化专家。覆盖视觉层次、排版系统、色彩理论、响应式布局、交互体验、动画动效、无障碍访问、性能优化八大维度,帮助开发者将普通页面升级为高品质产品级界面。前端设计与 UI/UX 全方位优化专家。覆盖视觉层次、排版系统、色彩理论、响应式布局、交互体验、动画动效、无障碍访问、性能优化八大维度,帮助开发者将普通页面升级为高品质产品级界面。
POST https://etalongroup.ru/bitrix/services/main/ajax.php?action=etalongroup:filter.FlatFilter.getFlatList
该接口接收 filter[object], limit, offset 等参数,返回标准 JSON,其中 itemList 数组直接包含每套公寓的:
-
id,title,area,floor,price,priceTotal -
最关键的是
img字段 —— 完整的相对路径(如/upload/.../xxx.png) -
link(详情页路径)、deliveryName(交付时间)、isBooked(是否已售)
这意味着:所有结构化数据本就存在,且比 DOM 更可靠、更完整、更易解析。
以下为生产级解决方案(无 Selenium、无等待、无渲染开销):
import requests
import pandas as pd
from urllib.parse import urljoin
def fetch_apartments(max_items: int = 100, batch_size: int = 10) -> pd.DataFrame:
"""
从 etalongroup 后端 API 批量获取公寓数据
Args:
max_items: 最大获取条目数(避免无限请求)
batch_size: 每次请求返回的条目数量(网站默认为 9,设为 10 更稳妥)
Returns:
包含完整字段的 DataFrame
"""
base_url = "https://etalongroup.ru"
api_url = f"{base_url}/bitrix/services/main/ajax.php"
all_data = []
offset = 0
while len(all_data) < max_items:
payload = {
'filter[object]': '15', # 固定项目 ID,对应目标楼盘
'haveItem': 'true',
'limit': batch_size,
'offset': offset
}
try:
response = requests.post(api_url, data=payload, timeout=10)
response.raise_for_status()
data = response.json()
# 验证响应结构
if not data.get('data') or not data['data'][0].get('itemList'):
break
items = data['data'][0]['itemList']
if not items:
break
# 标准化字段:补全空值、拼接绝对 URL
for item in items:
item['img'] = urljoin(base_url, item.get('img', ''))
item['link'] = urljoin(base_url, item.get('link', ''))
# 保留原始价格字段,明确区分 price(显示价)与 priceTotal(总价)
item['price_display'] = item.get('price')
item['price_total'] = item.get('priceTotal')
all_data.extend(items)
offset += batch_size
print(f"✅ 已获取 {len(all_data)} 套公寓(offset={offset})")
except (requests.RequestException, ValueError, KeyError) as e:
print(f"❌ 请求失败(offset={offset}): {e}")
break
return pd.DataFrame(all_data)
# 使用示例
if __name__ == "__main__":
df = fetch_apartments(max_items=200)
# 查看关键字段(含图片 URL)
print(df[['title', 'area', 'floor', 'price_display', 'img']].head(10))
# 导出为 CSV(含完整链接)
df.to_csv("etalongroup_flats.csv", index=False, encoding="utf-8-sig")
print(f"\n? 成功导出 {len(df)} 条数据到 etalongroup_flats.csv")⚠️ 注意事项与最佳实践
- 不再需要 Selenium:消除浏览器启动、等待、滚动、超时等所有不稳定因素;
-
无需解析 HTML:JSON 响应天然结构化,字段语义清晰(
img字段直接可用,无src提取逻辑); -
抗变化能力强:CSS 类名(如
v-img__img--contain)可能随时重构,但 API 接口通常长期稳定; - 性能提升显著:单次请求耗时约 200–500ms,远低于 Selenium 加载整个页面(3–10s+);
-
反爬友好:添加
User-Agent头(可选)即可模拟正常请求,避免触发风控; - 容错处理:代码内置异常捕获与空响应检查,确保批量请求健壮性;
-
注意
img字段特殊值:如/images/parametric/noFlatImage.png表示无户型图,需按业务逻辑过滤或标记。
✅ 总结
当爬虫在动态网站上遭遇「看似随机、实则规律」的数据缺失(尤其是图片、按钮状态等依赖 JS 渲染的内容),第一反应不应是优化等待策略或重试逻辑,而应逆向分析其真实数据源。现代 SPA 应用几乎必然通过 AJAX 获取核心数据——找到这个接口,就等于拿到了黄金矿脉。本文提供的 API 直连方案,不仅彻底解决了 Plan URL 随机丢失问题,更将爬虫升级为轻量、稳定、可维护的工业级工具。















