×

开山网 item_search 接口对接全攻略:从入门到精通

万邦科技Lex 万邦科技Lex 发表于2025-10-28 11:05:34 浏览155 评论0

抢沙发发表评论

              注册账号免费测试开山网API数据接口

开山网(kaishan.com)作为国内头部女鞋批发电商平台,聚焦温州、广州等源头鞋类货源,其商品搜索功能(对应item_search接口,非官方命名)是通过关键词、分类、价格等条件批量获取女鞋货源的核心工具,广泛应用于鞋类零售商选品、电商卖家货源对比、供应链分析等场景。由于开山网无公开官方 API,开发者需通过合规的页面解析或第三方服务实现对接。本文将系统讲解item_search接口的对接逻辑、参数解析、技术实现及反爬应对,帮助开发者构建稳定高效的女鞋商品搜索数据获取系统。

一、接口基础认知(核心功能与场景)

  1. 核心功能开山网item_search接口通过多维度筛选条件(关键词、分类、价格区间等)返回符合条件的女鞋商品列表,核心数据包括:
    • 基础信息:商品 ID(item_id)、标题、主图、类目(如 “单鞋”“凉鞋”)、详情页 URL、上架时间

    • 价格信息:批发价、起批量(如 “3 双起批”)、价格梯度标识(如 “10 + 双享低价”)

    • 规格信息:可选颜色、鞋码范围(如 “35-40 码”)、库存状态(充足 / 预售)

    • 供应商信息:供应商名称、所在地(如 “温州鞋城”“广州石井”)、供货等级

    • 交易数据:拿货人数(如 “800 + 人已拿”)、回头率(如 “38% 回头客”)

    • 筛选标识:是否支持混批、是否实拍、是否当季新款

  2. 典型应用场景
    • 鞋类零售商选品:按 “夏季凉鞋 + 价格 50-80 元 + 温州货源” 筛选高性价比女鞋

    • 电商卖家货源对比:批量获取 “高跟鞋” 类目商品,对比不同供应商的价格、起批量及材质

    • 供应链分析:统计 “平底鞋” 类目的价格分布、起批量区间、核心供应商地域占比

    • 爆款监控:跟踪 “抖音同款女鞋”“2024 新款凉鞋” 等关键词下的商品热度变化,及时跟进货源

  3. 接口特性
    • 非官方性:无公开 API,依赖页面解析,受页面结构变更影响较大

    • 垂直属性:聚焦女鞋批发,数据包含大量鞋类特有字段(鞋码、材质、工艺)

    • 多条件筛选:支持关键词、分类、价格、地区、鞋码、材质等 10 + 维度组合筛选

    • 分页机制:默认每页 30 条,最多支持 20 页(约 600 条结果)

    • 反爬机制:包含 IP 限制(高频请求封锁)、User-Agent 校验、Cookie 验证,搜索接口反爬严于详情页

二、对接前置准备(环境与参数解析)

  1. 开发环境
    • 网络请求:requests(同步请求)、aiohttp(异步批量搜索,效率更高)

    • 页面解析:BeautifulSoup(HTML 静态解析)、lxml(支持 XPath,高效提取)

    • 反爬工具:fake_useragent(随机 User-Agent)、proxy_pool(代理 IP 池管理)

    • 数据处理:re(正则提取动态数据)、pandas(列表数据清洗)

    • 开发语言:Python(推荐,生态丰富,适合快速迭代与解析工具集成)

    • 核心库:

  2. 搜索 URL 结构与核心参数开山网搜索页基础 URL 为:https://www.kaishan.com/search,核心参数如下(通过 URL 查询字符串传递):
    筛选条件参数名示例值说明
    关键词keyword夏季凉鞋 高跟鞋支持中文、组合词(如 “粗跟 罗马鞋”)
    分类 IDcate_id101(凉鞋)、102(单鞋)分类 ID 需通过解析首页分类导航获取
    价格区间(始)price_min50最低价格(元),如50表示≥50 元
    价格区间(终)price_max80最高价格(元),如80表示≤80 元
    地区area温州 广州供应商所在地筛选(核心鞋类批发产地)
    起批量min_buy1 3 10最低起批量(双),如3表示≥3 双起批
    鞋码shoe_size35-39 40支持鞋码范围筛选(如 “35-39” 表示包含该区间)
    排序方式sortsale_desc(销量降序)见 “排序参数表”
    分页page1 2 ... 20页码,默认 1,最大 20
    特色筛选is_mix1(支持混批)1 - 仅显示支持混批的商品
  3. 排序参数表开山网搜索支持多种排序方式,对应sort参数值如下:
    排序方式sort参数值适用场景
    综合推荐default默认排序,平衡销量与供应商资质
    销量降序sale_desc筛选热门商品(高拿货量优先)
    价格升序price_asc低价货源筛选
    价格降序price_desc高端女鞋筛选
    最新上架new_desc新款监控(如当季新款凉鞋)
  4. 分类 ID 获取分类 ID(cate_id)需通过解析开山网首页分类导航获取,示例步骤:
    • 凉鞋:101;单鞋:102;高跟鞋:103;运动鞋:104

    • 访问开山网首页(https://www.kaishan.com/),通过浏览器开发者工具查看分类菜单 HTML;

    • 提取a标签的href(如/search?cate_id=101中的101即为凉鞋分类 ID);

    • 常用分类 ID(示例):

三、接口调用流程(基于页面解析)

以 “搜索温州地区的夏季凉鞋,价格 50-80 元,支持混批,按销量降序排序” 为例,核心流程为参数组装→URL 构建→请求发送→列表解析→分页遍历
  1. URL 构建示例结合参数生成目标搜索 URL:
    python
    运行
    keyword = "夏季凉鞋"cate_id = "101"  # 凉鞋分类price_min = 50price_max = 80area = "温州"is_mix = 1  # 支持混批sort = "sale_desc"  # 销量降序page = 1url = f"https://www.kaishan.com/search?keyword={keyword}&cate_id={cate_id}&price_min={price_min}&price_max={price_max}&area={area}&is_mix={is_mix}&sort={sort}&page={page}"
  2. 请求头与反爬伪装需模拟浏览器请求头,关键字段包括User-AgentRefererCookie(提升可信度):
    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.kaishan.com/",
        "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
        "Cookie": "PHPSESSID=xxx; user_id=anonymous; Hm_lvt_xxx=xxx"  # 从浏览器获取匿名Cookie}
  3. 页面解析与数据提取搜索结果列表通常在 HTML 的<div class="goods-list">标签内,每条商品信息包含以下核心字段:
    字段解析方式(CSS 选择器示例)说明
    商品 IDa标签的href中提取(如/product/123.html123唯一标识
    标题.goods-title的文本如 “2024 夏季粗跟凉鞋 露趾罗马风”
    主图.goods-img imgsrc属性商品主图 URL
    批发价.price的文本(去除 “¥”)如 “65”(元 / 双)
    起批量.min-buy的文本如 “3 双起批”
    拿货人数.buy-count的文本(提取数字)如 “800 + 人已拿” 提取 “800”
    供应商名称.supplier-name的文本如 “温州鞋城批发部”
    所在地.area的文本如 “温州”
    特色标签.tag的文本(多个标签)如 “混批”“实拍”“新款”
    鞋码范围.shoe-size的文本如 “35-40 码”
  4. 动态加载与分页处理
    • 开山网搜索结果分页采用静态 URL + 参数方式,前 20 页均通过page参数控制,无单独动态接口;

    • 分页终止条件:当前页商品数量 < 30(表示为最后一页)或页码超过 20;

    • 分页间隔:每页请求间隔 3-7 秒(随机波动),鞋类批发平台对高频访问敏感,需严格控制频率。

四、代码实现示例(Python)

以下是item_search接口的完整实现,包含多条件筛选、分页遍历、数据解析及反爬处理:

import requests
import time
import random
import re
from urllib.parse import quote
from bs4 import BeautifulSoup
from fake_useragent import UserAgent
from typing import List, Dict

class KaishanSearchApi:
    def __init__(self, proxy_pool: List[str] = None):
        self.base_url = "https://www.kaishan.com/search"
        self.ua = UserAgent()
        self.proxy_pool = proxy_pool  # 代理池列表,如["http://ip:port", ...]
        self.cate_id_map = self._load_category_map()  # 分类ID映射表

    def _load_category_map(self) -> Dict[str, str]:
        """加载分类名称-ID映射表(简化版)"""
        return {
            "凉鞋": "101",
            "单鞋": "102",
            "高跟鞋": "103",
            "运动鞋": "104"
        }

    def _get_headers(self) -> Dict[str, str]:
        """生成随机请求头"""
        return {
            "User-Agent": self.ua.random,
            "Referer": "https://www.kaishan.com/",
            "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
            "Cookie": "PHPSESSID=xxx; user_id=anonymous; Hm_lvt_xxx=xxx"  # 替换为实际Cookie
        }

    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 _clean_buyers(self, buyers_str: str) -> int:
        """清洗拿货人数字符串(提取数字)"""
        if not buyers_str:
            return 0
        buyers_num = re.search(r"\d+", buyers_str)
        return int(buyers_num.group()) if buyers_num else 0

    def _parse_item(self, item_soup) -> Dict[str, str]:
        """解析单条商品数据"""
        # 提取商品ID
        link = item_soup.select_one("a.goods-link")["href"]
        item_id = re.search(r"/product/(\d+)\.html", link).group(1) if link else ""

        # 提取核心字段
        return {
            "item_id": item_id,
            "title": item_soup.select_one(".goods-title")?.text.strip() or "",
            "main_image": item_soup.select_one(".goods-img img")?.get("src") or "",
            "url": f"https://www.kaishan.com{link}" if link.startswith("/") else link,
            "price": self._clean_price(item_soup.select_one(".price")?.text.strip() or ""),
            "min_buy": item_soup.select_one(".min-buy")?.text.strip() or "",
            "buyers": self._clean_buyers(item_soup.select_one(".buy-count")?.text.strip() or ""),
            "shoe_size": item_soup.select_one(".shoe-size")?.text.strip() or "",  # 鞋码范围
            "supplier": {
                "name": item_soup.select_one(".supplier-name")?.text.strip() or "",
                "area": item_soup.select_one(".area")?.text.strip() or ""
            },
            "tags": [tag.text.strip() for tag in item_soup.select(".tag")]  # 特色标签
        }

    def _parse_page(self, html: str) -> List[Dict]:
        """解析页面的商品列表"""
        soup = BeautifulSoup(html, "lxml")
        item_list = soup.select("div.goods-list > div.goods-item")
        return [self._parse_item(item) for item in item_list if item]

    def item_search(self, 
                   keyword: str = "", 
                   cate: str = "", 
                   price_min: float = None, 
                   price_max: float = None, 
                   area: str = "", 
                   min_buy: int = None, 
                   shoe_size: str = "", 
                   is_mix: int = 0, 
                   sort: str = "default", 
                   page_limit: int = 5) -> Dict:
        """
        搜索开山网商品列表
        :param keyword: 搜索关键词
        :param cate: 分类名称(如“凉鞋”)或分类ID
        :param price_min: 起始价格(元)
        :param price_max: 结束价格(元)
        :param area: 供应商地区(如“温州”)
        :param min_buy: 最低起批量(双)
        :param shoe_size: 鞋码范围(如“35-39”)
        :param is_mix: 是否支持混批(1-是,0-否)
        :param sort: 排序方式(default/sale_desc/price_asc等)
        :param page_limit: 最大页数(默认5)
        :return: 标准化搜索结果
        """
        try:
            # 1. 参数预处理
            if not keyword and not cate:
                return {"success": False, "error_msg": "关键词(keyword)和分类(cate)至少需提供一个"}
            # 转换分类名称为ID
            if cate in self.cate_id_map:
                cate_id = self.cate_id_map[cate]
            else:
                cate_id = cate if cate else ""  # 若为ID则直接使用,为空则全类目搜索
            # 编码关键词、地区、鞋码(支持中文和特殊符号)
            encoded_keyword = quote(keyword, encoding="utf-8") if keyword else ""
            encoded_area = quote(area, encoding="utf-8") if area else ""
            encoded_shoe_size = quote(shoe_size, encoding="utf-8") if shoe_size else ""

            all_items = []
            current_page = 1

            while current_page <= page_limit:
                # 构建参数
                params = {
                    "keyword": encoded_keyword,
                    "sort": sort,
                    "page": current_page,
                    "is_mix": is_mix
                }
                if cate_id:
                    params["cate_id"] = cate_id
                if price_min is not None:
                    params["price_min"] = price_min
                if price_max is not None:
                    params["price_max"] = price_max
                if encoded_area:
                    params["area"] = encoded_area
                if min_buy is not None:
                    params["min_buy"] = min_buy
                if encoded_shoe_size:
                    params["shoe_size"] = encoded_shoe_size

                # 发送请求(带随机延迟)
                time.sleep(random.uniform(3, 7))  # 鞋类平台间隔需适中,3-7秒
                headers = self._get_headers()
                proxy = self._get_proxy()

                response = requests.get(
                    url=self.base_url,
                    params=params,
                    headers=headers,
                    proxies=proxy,
                    timeout=10
                )
                response.raise_for_status()
                items = self._parse_page(response.text)

                if not items:
                    break  # 无数据,终止分页

                all_items.extend(items)
                # 若当前页商品数<30,说明是最后一页
                if len(items) < 30:
                    break

                current_page += 1

            # 去重(基于item_id)
            seen_ids = set()
            unique_items = []
            for item in all_items:
                if item["item_id"] not in seen_ids:
                    seen_ids.add(item["item_id"])
                    unique_items.append(item)

            return {
                "success": True,
                "total": len(unique_items),
                "page_processed": current_page - 1,
                "items": unique_items
            }

        except requests.exceptions.HTTPError as e:
            if "403" in str(e):
                return {"success": False, "error_msg": "触发反爬,建议更换代理或Cookie", "code": 403}
            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"
    ]

    # 初始化API客户端
    search_api = KaishanSearchApi(proxy_pool=PROXIES)

    # 搜索“夏季凉鞋”,分类“凉鞋”,价格50-80元,温州地区,支持混批,按销量降序,最多3页
    result = search_api.item_search(
        keyword="夏季凉鞋",
        cate="凉鞋",
        price_min=50,
        price_max=80,
        area="温州",
        is_mix=1,
        sort="sale_desc",
        page_limit=3
    )

    if result["success"]:
        print(f"搜索成功:共找到 {result['total']} 件商品,处理 {result['page_processed']} 页")
        for i, item in enumerate(result["items"][:5]):  # 打印前5条
            print(f"\n商品 {i+1}:")
            print(f"标题:{item['title'][:50]}...")  # 截断长标题
            print(f"价格:{item['price']} 元 | 起批量:{item['min_buy']} | 拿货人数:{item['buyers']}+人")
            print(f"鞋码:{item['shoe_size']} | 供应商:{item['supplier']['name']}({item['supplier']['area']})")
            print(f"标签:{','.join(item['tags'])} | 详情页:{item['url']}")
    else:
        print(f"搜索失败:{result['error_msg']}(错误码:{result.get('code')})")

五、关键技术难点与解决方案

  1. 鞋类特有筛选条件处理(鞋码、材质)
    • 鞋码参数shoe_size支持范围输入(如 “35-39”),需通过 URL 编码(quote函数)处理特殊符号 “-”;

    • 材质筛选(如 “PU 鞋面”)通常通过关键词附加实现(如keyword="凉鞋 PU"),结合分类筛选提升精准度;

    • 示例代码中encoded_shoe_size变量实现鞋码参数的正确编码,适配鞋类选品需求。

    • 问题:开山网作为女鞋批发平台,筛选条件包含 “鞋码范围”“材质” 等鞋类特有维度,参数传递需精准映射。

    • 解决方案

  2. 分页终止条件判断
    • 若当前页商品数量 < 30(默认每页条数),则判定为最后一页,终止分页;

    • 同时设置page_limit上限(如 20 页),避免因异常情况导致无限循环;

    • 示例代码中if len(items) < 30: break逻辑实现了动态终止分页。

    • 问题:开山网分页无明确的 “总页数” 标识,需通过商品数量判断是否为最后一页。

    • 解决方案

  3. 反爬机制对抗
    • 代理 IP 轮换:每 1-2 页切换一次代理,使用高匿代理(避免透明代理被识别),代理存活周期≥15 分钟;

    • 请求间隔严格控制:单 IP 每页请求间隔 3-7 秒(随机波动),模拟人工浏览节奏(鞋类选品通常需仔细对比);

    • Cookie 池策略:通过多个浏览器会话获取匿名 Cookie(无需登录),随机携带以模拟多用户搜索行为;

    • 验证码处理:若触发验证码,暂停当前代理并加入黑名单,24 小时后重试(鞋类平台验证码出现频率中等)。

    • 问题:鞋类批发平台用户行为相对固定(低频高批量采购),高频搜索易触发 IP 封锁(403 错误)或验证码。

    • 解决方案

  4. 商品数据去重与清洗
    • 基于item_id去重:用集合存储已获取的item_id,过滤重复数据(示例代码中unique_items逻辑);

    • 清洗无效数据:过滤item_id为空、标题含 “已下架”“缺货” 等关键词的异常商品。

    • 问题:同一商品可能被供应商重复发布(如不同链接但相同item_id)或因排序波动重复出现。

    • 解决方案

六、最佳实践与合规要点

  1. 系统架构设计采用 “分布式低频率采集” 架构,适配鞋类批发平台特性:
    • 任务分发层:通过消息队列(如 RabbitMQ)分发搜索任务,控制单任务并发数≤2(避免高频访问);

    • 采集层:多节点并行采集,每个节点绑定独立代理池,节点间请求间隔≥10 秒;

    • 存储层:用 Redis 缓存热门搜索结果(1 小时过期,鞋类价格变动较慢),MySQL 存储历史数据(用于款式趋势分析);

    • 监控层:实时监控代理存活率、请求成功率、反爬触发次数,异常时通过企业微信告警。

  2. 性能优化策略
    • 异步批量搜索:使用aiohttp并发处理多个关键词(如同时搜索 “凉鞋”“单鞋”),控制并发数≤2;

    • 按需解析:列表页优先提取item_id、价格、起批量、鞋码等核心字段,详情页信息通过后续item_get接口补充;

    • 热点抑制:对同一关键词 + 条件的搜索请求,30 分钟内仅处理 1 次(返回缓存结果)。

  3. 合规性与风险控制
    • 频率限制:单 IP 日搜索请求≤150 次,单关键词日搜索≤30 次,避免对开山网服务器造成压力;

    • 数据使用边界:不得将搜索结果用于恶意比价、虚假宣传或商业售卖,需注明数据来源 “开山网”;

    • 遵守 robots 协议:检查https://www.kaishan.com/robots.txt,不爬取禁止路径(如/member/*用户中心页面)。

  4. 反爬适应性调整
    • 定期(每 2 周)检查搜索页结构变化,更新解析规则(鞋类平台页面变更频率低于综合电商);

    • 当反爬机制升级(如新增 JS 加密参数),快速切换至备用方案(如 Selenium 驱动浏览器渲染,适合低频场景);

    • 建立反爬特征库(如 403 页面特征、验证码页面特征),自动识别并触发应对策略(如切换代理、延长间隔)。

七、总结

开山网item_search接口的对接核心在于鞋类特有筛选条件的精准映射低频率高稳定性的采集策略女鞋行业数据的针对性解析。开发者需重点关注:
  1. 搜索参数的灵活组合(鞋码、混批等鞋类特有维度),提升货源筛选精准度;

  2. 分页终止条件的动态判断(基于商品数量),避免无效请求;

  3. 代理池与请求频率的严格控制(适配鞋类批发平台用户行为特征)。

通过本文的技术方案,可构建稳定的商品搜索系统,为鞋类零售商选品、电商卖家货源监控等场景提供可靠数据支持。实际应用中,需根据开山网的反爬策略动态调整方案,平衡数据获取效率与合规性。


群贤毕至

访客