
本文介绍一种不依赖 selenium 的高效方案:直接解析页面内嵌的 json 数据,彻底规避因 css 截断(如 text-overflow: ellipsis)导致长商品名为空的问题,确保 name、price 等关键字段 100% 完整可靠。
本文介绍一种不依赖 selenium 的高效方案:直接解析页面内嵌的 json 数据,彻底规避因 css 截断(如 text-overflow: ellipsis)导致长商品名为空的问题,确保 name、price 等关键字段 100% 完整可靠。
在使用 Selenium 抓取 Nguyen Kim 商品列表时,你可能会遇到一个典型陷阱:当商品标题过长(例如“Máy tính để bàn HP 205 Pro G4 AIO R5-4500U/8GB/256GB/Win10 31Y21PA”),前端通过 CSS 强制截断显示(white-space: nowrap; overflow: hidden; text-overflow: ellipsis),导致 .text 属性返回空字符串——而链接、图片等属性却能正常获取。这并非元素未加载或定位错误,而是视觉渲染与 DOM 文本内容的天然分离。
此时,强行优化 Selenium 的等待策略或改用 get_attribute('textContent') 仍可能失败,因为被截断的文本根本未在可见 DOM 节点中完整存在。真正的解决方案是:绕过渲染层,直取原始数据源。
观察 Nguyen Kim 页面源码可发现,所有商品信息实际以结构化 JSON 形式内嵌在 <script class="script-render"> 标签中,由前端 JavaScript 动态注入。这意味着完整商品数据(含全量 name、final_price、link、image_url 等)始终存在于 HTML 响应体中,无需浏览器渲染即可提取。</script>
以下为推荐的稳定、轻量、高性能实现方案(基于 requests + BeautifulSoup + json):
前端设计与 UI/UX 全方位优化专家。覆盖视觉层次、排版系统、色彩理论、响应式布局、交互体验、动画动效、无障碍访问、性能优化八大维度,帮助开发者将普通页面升级为高品质产品级界面。前端设计与 UI/UX 全方位优化专家。覆盖视觉层次、排版系统、色彩理论、响应式布局、交互体验、动画动效、无障碍访问、性能优化八大维度,帮助开发者将普通页面升级为高品质产品级界面。
import requests
from bs4 import BeautifulSoup as bs
import pandas as pd
import json
# 配置请求头,模拟真实浏览器
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
}
s = requests.Session()
s.headers.update(headers)
all_products = []
# 分页抓取(示例:前2页)
for page in range(1, 3):
url = f'https://www.nguyenkim.com/tim-kiem.html?tu-khoa=may+tinh&trang={page}'
response = s.get(url)
response.raise_for_status() # 检查HTTP错误
soup = bs(response.text, 'lxml')
# 定位所有包含商品数据的 script 标签
script_tags = soup.select('script.script-render')
for script in script_tags:
try:
# 提取 JSON 字符串(格式固定:dataRenderProduct.push({...});)
raw_js = script.string
if not raw_js or 'dataRenderProduct.push(' not in raw_js:
continue
# 解析出 JSON 对象部分
json_str = raw_js.split('dataRenderProduct.push(', 1)[1].split(');', 1)[0]
product_data = json.loads(json_str)
# 提取关键字段(字段名参考实际JSON结构)
item = {
'link': product_data.get('link', ''),
'name': product_data.get('name', '').strip(), # 全量名称,无截断
'current_price': product_data.get('final_price', ''),
'original_price': product_data.get('origin_price', ''),
'img': product_data.get('image_url', ''),
'product_id': product_data.get('id', '')
}
all_products.append(item)
except (json.JSONDecodeError, IndexError, AttributeError) as e:
continue # 跳过解析异常项,保证鲁棒性
# 转为 DataFrame 便于查看与导出
df = pd.DataFrame(all_products)
print(f"成功提取 {len(all_products)} 条商品数据")
print(df[['name', 'current_price', 'link']].head())
✅ 优势总结:
- 100% 规避截断问题:直接读取服务端下发的原始 JSON,不受 CSS 或 JS 渲染限制;
- 速度快、资源省:无需启动浏览器,单页请求耗时通常
- 稳定性高:不依赖元素可见性、动画状态或动态加载时机;
- 字段更丰富:除基础字段外,还可轻松获取 origin_price、discount_percent、short_desc 等隐藏信息。
⚠️ 注意事项:
- 若网站未来修改 JSON 注入方式(如更换 class 名或 JS 变量名),需微调 split() 逻辑,建议结合 re.search(r'dataRenderProduct\.push\((\{.*?\})\);', script.string) 提升健壮性;
- 遵守 robots.txt 与网站爬虫政策,添加合理延时(如 time.sleep(1));
- 生产环境建议加入重试机制(tenacity 库)和 User-Agent 轮换。
该方法不仅解决了当前长名称抓取难题,更代表了一种更优的网页数据采集范式:优先挖掘结构化数据源,而非依赖脆弱的 UI 层面解析。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










