南网商城(隶属于南方电网旗下,专注电力行业物资采购)是电力系统内重要的 B2B 电商平台,聚焦电力设备、电工材料、安防用品等工业品类。其商品详情数据(如型号规格、技术参数、供应商资质、交货周期等)对电力行业供应链分析、比价采购、供应商评估等场景具有极高价值。由于南网商城无公开官方 API,开发者需通过页面解析实现商品详情(item_get)的获取。本文系统讲解接口对接逻辑、技术实现、反爬应对及数据解析要点,帮助开发者构建稳定的电力行业商品数据获取系统。
一、接口基础认知(核心功能与场景)
核心功能南网商城item_get接口(非官方命名)通过商品 ID(item_id)获取目标商品的全量信息,核心字段聚焦电力行业特性:
基础信息:商品 ID、标题(含型号)、主图、品牌、类目(如 “高压设备”“电线电缆”)、详情页 URL
价格信息:含税单价、最小起订量、批量折扣(如 “100 件以上享 95 折”)、运费政策(工业物流配送)
技术参数:规格型号(如 “YJV-0.6/1kV-4×120”)、材质(如 “铜芯”)、执行标准(如 “GB/T 12706”)、适用场景(如 “户外高压输电”)
供应商信息:企业名称、资质认证(如 “ISO9001”“电力行业准入”)、所在地(如 “广东广州”)、联系方式
交易数据:成交记录(如 “已售 500 件”)、评价数、供货能力(如 “日产能 1000 件”)
服务信息:质保期(如 “2 年质保”)、交货周期(如 “7 天内发货”)、售后政策(如 “免费安装指导”)
典型应用场景
电力物资采购:获取 “高压电缆” 的技术参数与多家供应商报价,辅助招标决策
供应链分析:统计 “开关柜” 类目的主流品牌、价格区间、核心供应商分布
供应商评估:通过资质认证、成交记录筛选符合电力行业标准的优质供应商
市场监控:跟踪新型电力设备(如新能源充电桩)的上架信息与价格波动
接口特性
行业专业性:数据高度聚焦电力行业,包含大量专业技术参数与行业标准
非官方性:无公开 API,依赖页面 HTML 解析,页面结构稳定性较高(工业平台更新频率低)
反爬机制:包含 IP 限制(高频请求封锁)、Session 验证(部分页面需登录)、User-Agent 校验
静态为主:核心数据(价格、参数、供应商)嵌入静态 HTML,动态加载内容少(主要为库存)
二、对接前置准备(环境与 URL 结构)
开发环境
开发语言:Python(推荐,适合快速处理 HTML 解析与反爬)
核心库:
网络请求:requests(同步请求)、aiohttp(异步批量获取)
页面解析:BeautifulSoup(静态 HTML 解析)、lxml(XPath 提取,处理表格类技术参数)
反爬工具:fake_useragent(随机 User-Agent)、proxy_pool(代理 IP 池管理)
数据处理:re(正则提取型号、标准)、pandas(解析技术参数表格)
商品 ID 与 URL 结构南网商城商品详情页 URL 格式为:https://www.nwmall.com/product/{item_id}.html,其中item_id为商品唯一标识(数字 + 字母组合,如P123456)。示例:某高压电缆详情页 https://www.nwmall.com/product/P123456.html,商品 ID 为P123456。
页面结构分析通过浏览器开发者工具(F12)分析详情页结构,核心数据位置:
基础信息:标题在
,价格在
技术参数:多以表格形式呈现(
供应商信息:在
交易数据:成交记录在
三、接口调用流程(基于页面解析)
以 “获取某高压开关柜商品详情” 为例,核心流程为URL 构建→静态数据解析→动态数据补充→数据结构化:
URL 与请求头构建
目标 URL: https://www.nwmall.com/product/{item_id}.html(替换item_id为实际值);
请求头:模拟浏览器行为,需包含User-Agent、Referer,部分页面需携带登录态Cookie(未登录可能隐藏价格):
python
运行
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",
"Referer": " https://www.nwmall.com/category/electric-equipment.html",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9, /;q=0.8",
"Cookie": "SESSION=xxx; user_token=xxx" # 从登录后浏览器获取
}
静态数据解析(HTML 提取)从静态 HTML 中提取核心信息,重点关注电力行业特有字段:
字段 解析方式(CSS 选择器 / XPath) 示例值
商品标题 h1.product-title(CSS 选择器) “KYN28-12 型高压开关柜 固定式”
主图列表 div.product-img img的src属性 [" https://img.nwmall.com/xxx.jpg", ...]
含税单价 div.price-current的文本(去除 “¥” 和 “含税”) “12500.00”(元 / 台)
起订量 div.min-order的文本(提取数字) “1”(台)
技术参数 table.param-table tr(提取每行th与td文本) {"规格型号": "KYN28-12", "额定电压": "12kV"}
执行标准 从参数表中筛选 “执行标准” 行 “GB/T 11022”
供应商名称 div.supplier-name a的文本 “南方电网物资有限公司”
资质认证 div.qualification-tags span的文本列表 ["ISO9001", "电力行业准入"]
动态数据补充(AJAX 接口)实时库存、最新成交记录等数据可能通过内部接口加载,需抓包定位:
库存接口示例: https://www.nwmall.com/ajax/product/{item_id}/stock;
响应示例(库存接口):
json
{
"stock": 50, # 库存数量
"locked": 5, # 已锁定数量(待发货)
"available": 45 # 可售数量
}
数据整合与结构化合并静态与动态数据,形成标准化字典,突出电力行业特性:
python
运行
standardized_data = {
"item_id": item_id,
"title": title,
"price": {
"tax_included": tax_included_price, # 含税单价
"min_order": min_order, # 起订量
"batch_discount": batch_discount # 批量折扣规则
},
"technical_params": technical_params, # 技术参数字典
"execution_standard": execution_standard, # 执行标准
"supplier": {
"name": supplier_name,
"qualifications": qualifications, # 资质列表
"location": supplier_location
},
"trade": {
"sales": sales_count, # 累计销量
"stock": available_stock, # 可售库存
"delivery_cycle": delivery_cycle # 交货周期
},
"service": {
"warranty": warranty_period, # 质保期
"after_sale": after_sale_policy # 售后政策
},
"images": image_list,
"url": detail_url
}
四、代码实现示例(Python)
以下是item_get接口的完整实现,包含静态 HTML 解析、动态接口调用、反爬处理及数据结构化:
import requests
import time
import random
import re
from bs4 import BeautifulSoup
from fake_useragent import UserAgent
from typing import Dict, List
class NwmallItemApi:
def init(self, proxy_pool: List[str] = None, cookie: str = ""):
self.base_url = "https://www.nwmall.com/product/{item_id}.html"
self.stock_api = "https://www.nwmall.com/ajax/product/{item_id}/stock" # 库存接口
self.ua = UserAgent()
self.proxy_pool = proxy_pool # 代理池列表,如["http://ip:port", ...]
self.cookie = cookie # 登录态Cookie(部分页面需登录查看价格)
def _get_headers(self) -> Dict[str, str]:
"""生成随机请求头"""
headers = {
"User-Agent": self.ua.random,
"Referer": "https://www.nwmall.com/category/",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
}
if self.cookie:
headers["Cookie"] = self.cookie
return headers
def _get_proxy(self) -> Dict[str, str]:
"""随机获取代理"""
if self.proxy_pool and len(self.proxy_pool) > 0:
proxy = random.choice(self.proxy_pool)
return {"http": proxy, "https": proxy}
return None
def _clean_price(self, price_str: str) -> float:
"""清洗价格字符串(去除¥、含税、逗号等)"""
if not price_str:
return 0.0
price_str = re.sub(r"[^\d.]", "", price_str)
return float(price_str) if price_str else 0.0
def _parse_technical_params(self, table_soup) -> Dict[str, str]:
"""解析技术参数表格(电力商品核心字段)"""
params = {}
if not table_soup:
return params
for row in table_soup.select("tr"):
th = row.select_one("th")
td = row.select_one("td")
if th and td:
key = th.text.strip()
value = td.text.strip()
params[key] = value
return params
def _parse_static_data(self, html: str) -> Dict[str, str]:
"""解析静态HTML中的基础信息"""
soup = BeautifulSoup(html, "lxml")
# 提取技术参数表格
param_table = soup.select_one("table.param-table")
technical_params = self._parse_technical_params(param_table)
# 提取执行标准(从技术参数中筛选)
execution_standard = ""
for key in ["执行标准", "标准编号", "依据标准"]:
if key in technical_params:
execution_standard = technical_params[key]
break
# 提取批量折扣(如“100+件 95折”)
discount_str = soup.select_one("div.batch-discount")?.text.strip() or ""
return {
"title": soup.select_one("h1.product-title")?.text.strip() or "",
"images": [img.get("src") for img in soup.select("div.product-img img") if img.get("src")],
"price": {
"tax_included": self._clean_price(soup.select_one("div.price-current")?.text or ""),
"original": self._clean_price(soup.select_one("div.price-original")?.text or ""),
"min_order": int(re.search(r"\d+", soup.select_one("div.min-order")?.text or "1")?.group()) or 1,
"batch_discount": discount_str
},
"technical_params": technical_params,
"execution_standard": execution_standard,
"supplier": {
"name": soup.select_one("div.supplier-name a")?.text.strip() or "",
"qualifications": [tag.text.strip() for tag in soup.select("div.qualification-tags span")],
"location": soup.select_one("div.supplier-location")?.text.strip() or ""
},
"trade": {
"sales": int(re.search(r"\d+", soup.select_one("div.sales-count")?.text or "0")?.group()) or 0,
"delivery_cycle": soup.select_one("div.delivery-cycle")?.text.strip() or ""
},
"service": {
"warranty": soup.select_one("div.warranty-period")?.text.strip() or "",
"after_sale": soup.select_one("div.after-sale-policy")?.text.strip() or ""
},
"url": soup.select_one("link[rel='canonical']")?.get("href") or ""
}
def _fetch_dynamic_data(self, item_id: str, headers: Dict[str, str], proxy: Dict[str, str]) -> Dict:
"""调用动态接口获取库存"""
dynamic_data = {"stock": 0, "available": 0}
try:
stock_url = self.stock_api.format(item_id=item_id)
resp = requests.get(stock_url, headers=headers, proxies=proxy, timeout=10)
stock_data = resp.json()
dynamic_data["stock"] = stock_data.get("stock", 0)
dynamic_data["available"] = stock_data.get("available", 0)
except Exception as e:
print(f"动态库存获取失败: {str(e)}")
return dynamic_data
def item_get(self, item_id: str, timeout: int = 10) -> Dict:
"""
获取南网商城商品详情
:param item_id: 商品ID(如P123456)
:param timeout: 超时时间
:return: 标准化商品数据
"""
try:
# 1. 构建URL并发送请求
url = self.base_url.format(item_id=item_id)
headers = self._get_headers()
proxy = self._get_proxy()
# 随机延迟,避免反爬
time.sleep(random.uniform(2, 4))
response = requests.get(
url=url,
headers=headers,
proxies=proxy,
timeout=timeout
)
response.raise_for_status()
html = response.text
# 2. 解析静态数据
static_data = self._parse_static_data(html)
if not static_data["title"]:
return {"success": False, "error_msg": "未找到商品信息,可能item_id错误或商品已下架"}
# 3. 获取并合并动态数据
dynamic_data = self._fetch_dynamic_data(item_id, headers, proxy)
static_data["trade"]["stock"] = dynamic_data["available"] # 覆盖可售库存
# 4. 整合结果
result = {
"success": True,
"data": {
"item_id": item_id,** static_data,
"update_time": time.strftime("%Y-%m-%d %H:%M:%S")
}
}
return result
except requests.exceptions.HTTPError as e:
if "403" in str(e):
return {"success": False, "error_msg": "触发反爬,建议更换代理或Cookie", "code": 403}
if "401" in str(e):
return {"success": False, "error_msg": "需要登录,请提供有效Cookie", "code": 401}
return {"success": False, "error_msg": f"HTTP错误: {str(e)}", "code": response.status_code}
except Exception as e:
return {"success": False, "error_msg": f"获取失败: {str(e)}", "code": -1}
使用示例
if name == "main":
# 代理池(替换为有效代理)
PROXIES = [
"http://123.45.67.89:8888",
"http://98.76.54.32:8080"
]
# 登录态Cookie(从浏览器获取,部分页面需登录)
COOKIE = "SESSION=xxx; user_token=xxx"
# 初始化API客户端
api = NwmallItemApi(proxy_pool=PROXIES, cookie=COOKIE)
# 获取商品详情(示例item_id)
item_id = "P123456" # 替换为实际商品ID
result = api.item_get(item_id)
if result["success"]:
data = result["data"]
print(f"商品标题: {data['title']}")
print(f"含税单价: ¥{data['price']['tax_included']} | 起订量: {data['price']['min_order']}件 | 批量折扣: {data['price']['batch_discount']}")
print(f"执行标准: {data['execution_standard']}")
print(f"供应商: {data['supplier']['name']}({data['supplier']['location']})")
print(f"资质认证: {','.join(data['supplier']['qualifications'])}")
print(f"交易数据: 累计销量{data['trade']['sales']}件 | 可售库存{data['trade']['stock']}件 | 交货周期{data['trade']['delivery_cycle']}")
print(f"核心技术参数:")
# 打印前5条关键参数
key_params = ["规格型号", "额定电压", "材质", "适用场景", "防护等级"]
for key in key_params:
if key in data["technical_params"]:
print(f" {key}: {data['technical_params'][key]}")
print(f"售后服务: 质保期{data['service']['warranty']} | {data['service']['after_sale']}")
else:
print(f"获取失败: {result['error_msg']}(错误码: {result.get('code')})")
五、关键技术难点与解决方案
电力行业技术参数解析
问题:南网商城商品技术参数以表格形式呈现(如 “规格型号”“额定电压”),字段专业且格式多样,提取难度大。
解决方案:
针对表格结构,通过BeautifulSoup遍历
重点筛选电力行业核心参数(如 “执行标准”“额定电压”),通过关键词匹配确保关键信息不遗漏;
示例代码中_parse_technical_params函数专门处理表格解析,适配不同商品的参数格式。
登录态与权限控制
问题:部分高价值电力设备(如高压开关柜)的价格、库存等信息需登录后可见,未登录状态下返回隐藏或占位文本。
解决方案:
提前通过浏览器登录南网商城,获取Cookie(含SESSION user_token等字段),在请求头中携带;
检测响应中是否包含 “请登录查看” 等提示文本,若有则自动切换有效Cookie重试;
示例代码中_get_headers函数支持传入Cookie,确保有权限访问敏感数据。
反爬机制对抗
问题:南网商城作为工业采购平台,对异常访问敏感,高频请求会触发 IP 封锁(403 错误)或会话失效。
解决方案:
代理 IP 轮换:使用高匿代理池,每 3-5 次请求切换 IP,优先选择与电力行业相关地区的代理(如广东、云南);
请求频率控制:单 IP 每分钟请求≤1 次,两次请求间隔 4-6 秒(模拟采购人员缓慢浏览的行为);
会话保持:对同一item_id的重试请求,复用相同Cookie和代理,避免频繁更换标识;
异常处理:对 403 错误,延迟 10 秒后用新代理 + 新Cookie重试,最多 3 次。
数据标准化与行业适配
问题:不同供应商的参数命名不一致(如 “额定电压” vs “工作电压”),导致数据难以横向对比。
解决方案:
建立电力行业参数映射表,统一同义词(如将 “工作电压” 映射为 “额定电压”);
对关键参数(如 “执行标准”)进行正则清洗,提取标准编号(如从 “符合 GB/T 11022-2020” 中提取 “GB/T 11022-2020”);
示例代码中通过key_params列表定义核心参数,确保输出数据的一致性。
六、最佳实践与合规要点
系统架构设计采用 “低频率精准采集” 架构,适配工业平台特性:
采集层:集成代理池、Cookie 池,控制单 IP 请求频率(≤1 次 / 分钟),避免触发反爬;
解析层:分离基础信息与技术参数解析逻辑,重点处理表格数据与行业术语标准化;
存储层:用 Redis 缓存热门商品(24 小时过期,工业商品价格变动极慢),MySQL 存储历史数据(用于供应商评估);
监控层:实时监控请求成功率、登录态有效性,异常时通过邮件告警。
性能优化策略
批量异步获取:使用aiohttp并发处理多个item_id(控制并发数≤1),适配低频率限制;
按需解析:优先提取标题、价格、核心技术参数,详情页 HTML 等非必要信息可选择性存储;
增量更新:仅更新价格、库存有变化的商品(通过对比缓存的历史数据),减少无效请求。
合规性与风险控制
访问限制:单 IP 日请求量≤50 次,避免对平台服务器造成压力,符合工业平台的访问规范;
数据使用边界:不得将数据用于恶意竞价、商业售卖或泄露供应商商业机密,需注明数据来源 “南网商城”;
行业合规:电力行业数据涉及安全生产标准,使用时需遵守《电力安全生产条例》等法规,确保参数准确性。
七、总结
南网商城item_get接口的对接核心在于电力行业技术参数的精准解析(表格处理、术语标准化)与登录态权限的有效管理。开发者需重点关注:
表格类技术参数的结构化提取(适配多样表头格式);
登录态 Cookie 的维护与动态切换(确保敏感数据可见);
低频率、高稳定性的采集策略(符合工业平台反爬特性)。
通过本文的技术方案,可构建稳定的商品详情获取系统,为电力行业采购、供应链分析等场景提供可靠数据支持。实际应用中,需根据平台最新页面结构动态调整解析规则,平衡数据获取效率与合规性。