在当今的电商时代,获取商品的实时数据对于市场分析、竞品监控和价格策略制定至关重要。本文将带您从零开始,开发一个淘宝商品实时数据采集接口,通过这个接口可以获取商品的基本信息、价格、销量等关键数据。
技术选型
淘宝商品数据采集接口,我们将使用以下技术栈:
Python:作为主要开发语言,简洁高效
Requests:处理 HTTP 请求
BeautifulSoup:解析 HTML 页面
Flask:搭建 API 服务
Redis:缓存数据,减轻服务器压力
实现思路
分析淘宝商品页面结构,确定需要采集的数据字段
编写爬虫代码,模拟浏览器请求并解析页面
实现数据缓存机制,避免频繁请求
搭建 API 服务,提供统一的数据访问接口
添加异常处理和反爬措施
代码实现
1. 项目结构
taobao-crawler/ ├── app.py # Flask应用主文件 ├── crawler.py # 爬虫核心逻辑 ├── cache.py # 缓存相关操作 ├── config.py # 配置文件 └── requirements.txt # 依赖包列表
2. 依赖安装
首先创建 requirements.txt 文件:
flask==2.0.1 requests==2.26.0 beautifulsoup4==4.10.0 redis==3.5.3 python-dotenv==0.19.0 fake_useragent==0.1.11
安装依赖:
pip install -r requirements.txt
3. 配置文件
import os from dotenv import load_dotenv # 加载环境变量 load_dotenv() # 爬虫配置 TIMEOUT = 10 RETRY_TIMES = 3 CACHE_EXPIRE = 300 # 缓存过期时间,单位秒 # Redis配置 REDIS_HOST = os.getenv('REDIS_HOST', 'localhost') REDIS_PORT = int(os.getenv('REDIS_PORT', 6379)) REDIS_DB = int(os.getenv('REDIS_DB', 0)) # API配置 API_HOST = os.getenv('API_HOST', '0.0.0.0') API_PORT = int(os.getenv('API_PORT', 5000))
4. 缓存模块
import redis import json from config import REDIS_HOST, REDIS_PORT, REDIS_DB, CACHE_EXPIRE # 初始化Redis连接 redis_client = redis.Redis( host=REDIS_HOST, port=REDIS_PORT, db=REDIS_DB, decode_responses=True ) def get_cache(key): """获取缓存数据""" data = redis_client.get(key) if data: return json.loads(data) return None def set_cache(key, data, expire=CACHE_EXPIRE): """设置缓存数据""" redis_client.setex(key, expire, json.dumps(data)) def delete_cache(key): """删除缓存数据""" redis_client.delete(key)
5. 爬虫核心逻辑
import requests from bs4 import BeautifulSoup import re import json from fake_useragent import UserAgent from config import TIMEOUT, RETRY_TIMES from cache import get_cache, set_cache # 初始化UserAgent ua = UserAgent() def get_taobao_item(item_id): """ 获取淘宝商品信息 :param item_id: 商品ID :return: 商品信息字典 """ # 先从缓存获取 cache_key = f"taobao:item:{item_id}" cached_data = get_cache(cache_key) if cached_data: return cached_data # 构建商品详情页URL url = f"https://item.taobao.com/item.htm?id={item_id}" # 设置请求头,模拟浏览器 headers = { "User-Agent": ua.random, "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", "Accept-Language": "zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3", "Connection": "keep-alive", "Upgrade-Insecure-Requests": "1" } # 发送请求,带重试机制 for _ in range(RETRY_TIMES): try: response = requests.get(url, headers=headers, timeout=TIMEOUT) response.encoding = "gbk" # 淘宝页面通常使用gbk编码 if response.status_code == 200: # 解析页面 data = parse_item_page(response.text, item_id) if data: # 存入缓存 set_cache(cache_key, data) return data except Exception as e: print(f"获取商品信息失败: {str(e)}") return None def parse_item_page(html, item_id): """ 解析商品详情页HTML :param html: 页面HTML内容 :param item_id: 商品ID :return: 解析后的商品信息 """ soup = BeautifulSoup(html, 'lxml') # 提取商品基本信息 result = { "item_id": item_id, "title": "", "price": "", "sales": 0, "shop_name": "", "shop_url": "", "category": "", "images": [], "specifications": {} } # 获取标题 title_tag = soup.find('h3', class_='tb-main-title') if title_tag: result["title"] = title_tag.get_text(strip=True) # 获取价格 price_tag = soup.find('em', class_='tb-rmb-num') if price_tag: result["price"] = price_tag.get_text(strip=True) # 获取销量(淘宝商品详情页销量可能通过JS加载,这里采用另一种方式) sales_script = re.search(r'aucNumId:"(\d+)",.*?viewSales:"(.*?)"', html) if sales_script and sales_script.group(2): sales_text = sales_script.group(2) # 提取数字 sales_num = re.search(r'\d+', sales_text) if sales_num: result["sales"] = int(sales_num.group(0)) # 获取店铺信息 shop_name_tag = soup.find('a', class_='s-logo-shopname') if shop_name_tag: result["shop_name"] = shop_name_tag.get_text(strip=True) result["shop_url"] = shop_name_tag.get('href', '') # 获取商品图片 image_tags = soup.find_all('img', class_='J_ItemImg') for img in image_tags: img_url = img.get('src') if img_url and img_url.startswith('//'): img_url = 'https:' + img_url if img_url: result["images"].append(img_url) # 获取商品规格信息(简化版) spec_script = re.search(r'var g_config = (.*?);\n', html) if spec_script: try: spec_data = json.loads(spec_script.group(1)) if "item" in spec_data and "category" in spec_data["item"]: result["category"] = spec_data["item"]["category"] except: pass return result def search_taobao(keyword, page=1): """ 搜索淘宝商品 :param keyword: 搜索关键词 :param page: 页码 :return: 商品列表 """ # 先从缓存获取 cache_key = f"taobao:search:{keyword}:{page}" cached_data = get_cache(cache_key) if cached_data: return cached_data # 构建搜索URL url = f"https://s.taobao.com/search?q={keyword}&s={(page-1)*44}" # 设置请求头 headers = { "User-Agent": ua.random, "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", "Accept-Language": "zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3", "Connection": "keep-alive", "Upgrade-Insecure-Requests": "1", "Referer": "https://www.taobao.com/" } # 发送请求 try: response = requests.get(url, headers=headers, timeout=TIMEOUT) response.encoding = "utf-8" if response.status_code == 200: # 解析搜索结果 items = parse_search_result(response.text) # 存入缓存 set_cache(cache_key, items) return items except Exception as e: print(f"搜索商品失败: {str(e)}") return [] def parse_search_result(html): """解析搜索结果页面""" # 从脚本中提取商品数据 pattern = re.compile(r'g_page_config = (.*?);\n') match = pattern.search(html) if not match: return [] try: data = json.loads(match.group(1)) if "mods" in data and "itemlist" in data["mods"] and "data" in data["mods"]["itemlist"]: items = data["mods"]["itemlist"]["data"]["auctions"] # 提取需要的字段 result = [] for item in items: result.append({ "item_id": item.get("nid", ""), "title": item.get("title", ""), "price": item.get("view_price", ""), "sales": item.get("view_sales", ""), "location": item.get("item_loc", ""), "shop_name": item.get("nick", ""), "shop_url": item.get("shopLink", ""), "pic_url": item.get("pic_url", "").replace("//", "https://") if item.get("pic_url") else "" }) return result except Exception as e: print(f"解析搜索结果失败: {str(e)}") return []
6. API 服务实现
from flask import Flask, request, jsonify from crawler import get_taobao_item, search_taobao from config import API_HOST, API_PORT app = Flask(__name__) @app.route('/api/item/<item_id>', methods=['GET']) def get_item(item_id): """获取单个商品详情""" try: data = get_taobao_item(item_id) if data: return jsonify({ "code": 200, "message": "success", "data": data }) else: return jsonify({ "code": 404, "message": "商品不存在或获取失败", "data": None }) except Exception as e: return jsonify({ "code": 500, "message": f"服务器错误: {str(e)}", "data": None }) @app.route('/api/search', methods=['GET']) def search(): """搜索商品""" try: keyword = request.args.get('keyword', '') page = int(request.args.get('page', 1)) if not keyword: return jsonify({ "code": 400, "message": "请提供搜索关键词", "data": None }) data = search_taobao(keyword, page) return jsonify({ "code": 200, "message": "success", "data": { "items": data, "page": page, "count": len(data) } }) except Exception as e: return jsonify({ "code": 500, "message": f"服务器错误: {str(e)}", "data": None }) @app.route('/api/health', methods=['GET']) def health_check(): """健康检查接口""" return jsonify({ "code": 200, "message": "service is running", "timestamp": int(request.args.get('timestamp', 0)) or None }) if __name__ == '__main__': app.run(host=API_HOST, port=API_PORT, debug=True)
接口使用示例
1. 获取单个商品详情
请求:
GET /api/item/586722645217
响应示例:
{ "code": 200, "message": "success", "data": { "item_id": "586722645217", "title": "示例商品标题", "price": "199.00", "sales": 1256, "shop_name": "示例店铺", "shop_url": "https://shop12345678.taobao.com", "category": "服饰鞋包 > 女装", "images": [ "https://img.alicdn.com/imgextra/i1/abc.jpg", "https://img.alicdn.com/imgextra/i2/def.jpg" ], "specifications": {} } }
反爬措施与优化
User-Agent 随机化:使用 fake_useragent 库生成不同的浏览器标识,避免被识别为爬虫
请求频率控制:可以在实际应用中添加请求间隔控制
IP 代理池:对于大规模采集,可以使用 IP 代理池避免 IP 被封禁
数据缓存:使用 Redis 缓存减轻目标服务器压力,同时提高接口响应速度
异常处理:完善的异常处理机制,提高程序稳定性
注意事项
本接口仅用于学习和研究目的,使用时请遵守淘宝的 robots 协议和相关规定
频繁的请求可能会导致 IP 被封禁,建议合理控制请求频率
淘宝页面结构可能会发生变化,需要定期维护爬虫代码
商业用途请联系淘宝官方获取合法的数据接口
通过本文的实战教程,我们实现了一个简单但功能完整的淘宝商品数据采集接口。您可以根据实际需求扩展更多功能,如批量采集、数据导出、定时更新等。在实际应用中,还需要考虑更多的反爬策略和性能优化,以确保接口的稳定运行。