You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用lxml的XPath抓取网页所有同路径价格元素

XPath抓取新蛋商品价格索引越界问题解决

问题现象

使用XPath抓取新蛋网GPU搜索列表页商品价格时,手写的绝对路径仅索引[0]对应的第一个价格元素可正常输出,将索引修改为1获取第二个元素时,程序返回out of range索引越界错误。需求为循环遍历全部价格元素,计算商品价格平均值。

原问题代码

最初测试代码:

webpage = requests.get(URL, headers=HEADERS)
soup = BeautifulSoup(webpage.content, "html.parser")
dom = etree.HTML(str(soup))
print(dom.xpath('/html/body/div[1]/div[5]/div/div/div/div[1]/ul/li[1]/article/div[1]/div[2]/div')[0].text)

完整可复现代码:

from bs4 import BeautifulSoup
from lxml import etree
import requests

URL = "https://www.newegg.com/p/pl?d=GPU&N=601357247%20100007709"
#HEADERS = you'll need to add your own headers here, won't let post.
webpage = requests.get(URL, headers=HEADERS)
soup = BeautifulSoup(webpage.content, "html.parser")
dom = etree.HTML(str(soup))
print(dom.xpath('/html/body/div[10]/div[4]/section/div/div/div[2]/div/div/div/div[2]/div/div[2]/div[2]/div[1]/div/div[2]/ul/li[3]/strong')[0].text)

故障原因

  • 所用XPath为从<html>根节点开始逐层写死位置索引的绝对路径,路径本身仅匹配单个商品的价格节点,返回的结果列表长度只有1,取索引1自然触发越界。
  • 先将响应传给BeautifulSoup解析再转字符串给lxml的流程属于冗余操作,BeautifulSoup自动修正DOM结构时可能改动节点层级,进一步导致路径匹配偏差。
  • 全路径硬编码索引的写法容错率极低,页面只要插入一个广告位、调整一个容器层级,所有索引都会失效。

修复方案

放弃硬编码全层级索引的绝对路径写法,通过公共class属性定位所有商品卡片容器,再逐个遍历容器内部的价格节点即可,参考实现代码:

from lxml import etree
import requests

URL = "https://www.newegg.com/p/pl?d=GPU&N=601357247%20100007709"
# 替换为自身环境可用的请求头,需携带合法User-Agent避免被反爬拦截
HEADERS = {
    "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"
}

webpage = requests.get(URL, headers=HEADERS)
# 直接用lxml解析原始响应文本,去掉BeautifulSoup中转的冗余步骤
dom = etree.HTML(webpage.text)

price_list = []
# 匹配所有商品卡片的公共容器,不硬编码单个节点的位置索引
items = dom.xpath('//div[contains(@class, "list-items")]//div[contains(@class, "item-cell")]')
for item in items:
    # 查找当前商品卡片下的价格标签,路径前加.表示从当前商品节点向下查找
    price_tag = item.xpath('.//li[contains(@class, "price-current")]/strong')
    if not price_tag:
        # 跳过无价格的广告位、无货商品
        continue
    # 拼接价格的整数部分和小数部分,转为数值格式
    price_int = price_tag[0].text.strip()
    price_decimal = price_tag[0].xpath('./following-sibling::sup')[0].text.strip()
    full_price = float(f"{price_int}{price_decimal}")
    price_list.append(full_price)

# 计算平均价格
if price_list:
    avg_price = sum(price_list) / len(price_list)
    print(f"共抓取{len(price_list)}个有效商品价格,平均价格为:${avg_price:.2f}")
else:
    print("未抓取到有效价格,请检查请求头是否被站点反爬拦截")

注意事项

  • 编写XPath优先通过//匹配具有标识性class/id的节点,不要写从根节点开始的全层级硬编码路径
  • 在遍历到的单个节点下做子查询时,XPath必须以.开头,否则会从整个DOM根节点全局匹配,导致结果错位
  • 列表页存在广告位、无货商品等无价格的特殊项,遍历过程必须加判空逻辑,避免触发新的索引越界错误

内容的提问来源于stack exchange,提问作者z0x01z

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.03 07:21:55