
1. 项目背景与核心价值做电商数据抓取和分析的朋友应该都遇到过这样的场景需要批量获取商品详情数据但官方没有提供完整的API文档。这时候就需要通过技术手段解析网页接口构建自己的数据采集方案。最近我在做得物App的商品数据采集时就完整走通了这套流程。得物作为国内领先的潮流电商平台其商品数据对市场分析、价格监控、竞品研究都有重要价值。但官方并未开放完整的开发者接口这就需要我们通过技术手段获取数据。本文将分享从接口发现、参数逆向到数据结构解析的全过程包含大量实战中积累的经验技巧。2. 接口发现与请求构造2.1 接口定位方法首先需要在App或网页端抓包找到目标接口。我推荐使用Charles或Fiddler这类专业抓包工具配置手机代理后在得物App浏览商品时就能捕获到相关请求。关键识别点接口路径通常包含/product/detail这类关键词请求方法多为GET或POST响应数据为JSON格式且包含完整商品信息典型得物商品详情接口示例https://app.dewu.com/api/v1/product/detail?productId1234562.2 关键请求参数解析通过分析多个请求样本我总结出以下核心参数参数名类型必填说明示例值productIdString是商品唯一IDA123456platformString否平台标识androidversionString否App版本号5.9.0signString是签名参数a1b2c3d4e5特别注意sign参数是接口验证的关键需要通过逆向工程分析其生成算法。根据我的分析得物采用的是常见的MD5加密方式将多个参数按特定顺序拼接后加密生成。2.3 请求头设置技巧除了URL参数请求头也需要特别注意以下字段headers { User-Agent: Mozilla/5.0 (Linux; Android 10) Dewu/5.9.0, X-Requested-With: com.shizhuang.duapp, Authorization: Bearer xxxxxxx, # 登录态令牌 Accept-Encoding: gzip }实测发现得物服务端会校验User-Agent和X-Requested-With字段如果缺失或格式不正确会返回403错误。Authorization字段在获取某些敏感数据如库存、价格走势时需要提供。3. 响应数据结构深度解析3.1 基础商品信息结构典型响应数据采用多层嵌套的JSON结构。以下是核心字段的解析{ code: 0, message: success, data: { productId: A123456, title: Nike Air Force 1 纯白, subTitle: 2023新款 经典复刻, price: 899, originalPrice: 1299, discount: 6.9折, mainImages: [ https://img.dewu.com/xxx1.jpg, https://img.dewu.com/xxx2.jpg ], specs: [ { name: 颜色, values: [纯白, 米白] }, { name: 尺码, values: [38, 39, 40] } ], stock: 128, sales: 5600, brand: { id: 1001, name: Nike }, seller: { shopId: S888, shopName: 潮流正品专营店, rating: 4.9 } } }3.2 特殊字段处理技巧价格字段得物采用整数存储价格单位分需要除以100转换。但要注意某些促销价可能直接是元单位需根据priceType字段判断。图片URL图片链接有时会返回相对路径需要拼接域名前缀。实测发现CDN地址有多个建议统一替换为https://img.dewu.com。规格参数specs数组中的值可能存在HTML标签需要做清洗处理。例如import re clean_text re.sub(r[^], , dirty_text)3.3 嵌套数据提取对于复杂的嵌套数据建议使用JSONPath或递归函数处理。例如获取所有规格组合def extract_specs(data): specs {} for item in data[data][specs]: specs[item[name]] item[values] return specs4. 反爬机制与应对策略4.1 常见反爬手段根据我的实测经验得物主要采用以下防护措施请求频率限制单IP超过30次/分钟会触发验证码签名验证sign参数错误直接返回403设备指纹通过HTTP头检测异常设备行为验证连续访问会弹出滑动验证码4.2 实战解决方案IP代理池建议使用优质住宅代理按1-2秒间隔请求proxies { http: http://user:passproxy_ip:port, https: https://user:passproxy_ip:port }请求随机化随机User-Agent准备至少20个常见手机UA随机请求间隔0.5-3秒随机添加无关参数如timestampxxx签名破解通过逆向App分析sign生成算法核心逻辑通常是def generate_sign(params): secret 得物密钥 # 需要逆向获取 param_str .join([f{k}{v} for k,v in sorted(params.items())]) return md5(param_str secret).hexdigest()5. 数据存储与清洗建议5.1 数据库设计推荐使用MongoDB存储非结构化数据关键字段建立索引db.products.createIndex({ productId: 1, brand.id: 1, price: 1 })关系型数据库设计参考CREATE TABLE products ( id VARCHAR(20) PRIMARY KEY, title VARCHAR(200), price INT, original_price INT, discount VARCHAR(10), stock INT, sales INT, brand_id INT, shop_id VARCHAR(20), created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP );5.2 数据清洗要点价格异常值过滤priceoriginal_price的异常记录图片去重使用MD5校验去除重复图片URL规格标准化将38码/US7等文本统一转换为数字时间处理将时间戳转换为标准datetime格式6. 常见问题排查实录6.1 接口返回403错误可能原因签名计算错误检查参数顺序和密钥请求头缺失特别是User-AgentIP被封禁更换代理测试调试方法print(response.request.headers) # 检查发送的请求头 print(response.url) # 检查完整请求URL6.2 数据字段缺失解决方案检查接口版本有些字段只在特定版本返回添加登录态部分数据需要认证确认商品状态下架商品返回字段较少6.3 验证码触发后处理建议流程立即停止当前IP的请求更换IP和设备指纹降低请求频率至5次/分钟考虑使用自动化验证码识别服务7. 性能优化实践7.1 并发控制策略使用异步请求提升效率但要注意得物的频率限制import aiohttp import asyncio async def fetch(session, url): async with session.get(url) as response: return await response.json() async def main(): conn aiohttp.TCPConnector(limit5) # 控制并发数 async with aiohttp.ClientSession(connectorconn) as session: tasks [fetch(session, url) for url in urls] return await asyncio.gather(*tasks)7.2 缓存机制实现对静态数据使用本地缓存from diskcache import Cache cache Cache(tmp/dewu_cache) cache.memoize(expire3600) def get_product_detail(product_id): # 接口请求代码8. 法律合规提醒在进行数据采集时请特别注意遵守得物的Robots协议不采集用户隐私数据控制请求频率避免影响正常服务数据仅用于个人分析不进行商业售卖建议在夜间低谷期凌晨1-6点进行大规模采集并将请求间隔设置为3秒以上。