使用 Scrapy 框架定制爬虫中间件接入淘宝 API 采集商品数据

一、引言

在电商数据分析、市场调研等领域,获取淘宝平台上的商品数据是一项常见需求。淘宝提供了 API 接口,允许开发者通过授权的方式获取商品信息。本文将介绍如何使用 Scrapy 框架定制爬虫中间件,实现对淘宝 API 的接入,从而高效地采集商品数据。

二、淘宝 API 概述

淘宝提供了丰富的 API 接口,涵盖商品、交易、用户、营销等多个领域。对于商品数据采集,常用的 API 包括:

  • taobao.search:搜索商品列表
  • taobao.item.get:获取单个商品详情
  • taobao.cats.get:获取商品分类
  • taobao.props.get:获取商品属性

使用淘宝 API 需要先注册账号并获取 ApiKey和 ApiSecret。同时,API 调用有频率限制,需要合理控制请求速度。

三、Scrapy 框架与中间件
import logging
import time
import random
import hashlib
import hmac
import json
from urllib.parse import urlencode
import requests
from scrapy import signals
from scrapy.exceptions import NotConfigured, IgnoreRequestclass TaobaoAPIMiddleware:"""淘宝API爬虫中间件,处理API请求和响应"""def __init__(self, app_key, app_secret, api_url, rate_limit, retry_times):self.app_key = app_keyself.app_secret = app_secretself.api_url = api_urlself.rate_limit = rate_limitself.retry_times = retry_timesself.request_count = 0self.last_reset_time = time.time()self.logger = logging.getLogger(__name__)@classmethoddef from_crawler(cls, crawler):"""从配置中获取中间件设置"""app_key = crawler.settings.get('TAOBAO_APP_KEY')app_secret = crawler.settings.get('TAOBAO_APP_SECRET')api_url = crawler.settings.get('TAOBAO_API_URL', 'https://eco.taobao.com/router/rest')rate_limit = crawler.settings.getint('TAOBAO_RATE_LIMIT', 500)  # 默认500次/小时retry_times = crawler.settings.getint('TAOBAO_RETRY_TIMES', 3)  # 默认重试3次if not app_key or not app_secret:raise NotConfigured("淘宝API配置缺失:TAOBAO_APP_KEY 和 TAOBAO_APP_SECRET")middleware = cls(app_key, app_secret, api_url, rate_limit, retry_times)crawler.signals.connect(middleware.spider_closed, signal=signals.spider_closed)return middlewaredef process_request(self, request, spider):"""处理API请求,生成签名并发送"""# 检查是否为淘宝API请求if not request.meta.get('taobao_api', False):return None# 检查速率限制self._check_rate_limit()# 构建API请求参数method = request.meta.get('taobao_method')if not method:self.logger.error("淘宝API请求缺少方法名:taobao_method")raise IgnoreRequestparams = self._build_common_params()params.update({'method': method,**request.meta.get('taobao_params', {})})# 生成签名params['sign'] = self._generate_sign(params)try:# 发送API请求response = requests.post(self.api_url,data=params,timeout=30)response.raise_for_status()# 解析JSON响应result = response.json()request.meta['api_result'] = result# 检查API返回状态if not self._check_api_success(result):error_code = result.get('error_response', {}).get('code')error_msg = result.get('error_response', {}).get('msg')self.logger.warning(f"淘宝API返回错误: {error_code} - {error_msg}")# 如果是限流错误,暂停一段时间if error_code in ('isp.over-quota', 'isp.access-control'):self.logger.warning("API请求达到限流阈值,暂停60秒")time.sleep(60)# 重试机制retry_times = request.meta.get('taobao_retry_times', 0)if retry_times < self.retry_times:self.logger.info(f"准备重试API请求,当前重试次数: {retry_times + 1}")new_request = request.copy()new_request.dont_filter = Truenew_request.meta['taobao_retry_times'] = retry_times + 1# 随机延迟后重试time.sleep(random.uniform(1, 3))return new_requestelse:self.logger.error("API请求重试次数已达上限")raise IgnoreRequestexcept requests.exceptions.RequestException as e:self.logger.error(f"API请求发生异常: {str(e)}")# 异常情况下的重试逻辑retry_times = request.meta.get('taobao_retry_times', 0)if retry_times < self.retry_times:self.logger.info(f"准备重试API请求,当前重试次数: {retry_times + 1}")new_request = request.copy()new_request.dont_filter = Truenew_request.meta['taobao_retry_times'] = retry_times + 1# 指数退避策略time.sleep(2 ** retry_times + random.random())return new_requestelse:self.logger.error("API请求重试次数已达上限")raise IgnoreRequest# 处理正常响应return Nonedef _build_common_params(self):"""构建API公共参数"""return {'app_key': self.app_key,'format': 'json','v': '2.0','sign_method': 'hmac','timestamp': time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())}def _generate_sign(self, params):"""生成API请求签名"""# 排序参数sorted_params = sorted(params.items(), key=lambda x: x[0])# 拼接参数string_to_sign = self.app_secretfor k, v in sorted_params:string_to_sign += f"{k}{v}"string_to_sign += self.app_secret# HMAC-SHA1加密sign = hmac.new(self.app_secret.encode('utf-8'),string_to_sign.encode('utf-8'),hashlib.sha1).hexdigest().upper()return signdef _check_api_success(self, result):"""检查API响应是否成功"""if 'error_response' in result:return False# 根据具体API调整检查逻辑method_name = result.get('method')if method_name:# 例如:taobao.items.list.get 返回值检查if method_name == 'taobao.items.list.get' and 'items_list_response' in result:return True# 其他API方法的检查逻辑...return Truedef _check_rate_limit(self):"""检查API请求速率限制"""current_time = time.time()# 如果已经过了1小时,重置计数器if current_time - self.last_reset_time > 3600:self.request_count = 0self.last_reset_time = current_time# 检查是否超过速率限制if self.request_count >= self.rate_limit:wait_time = 3600 - (current_time - self.last_reset_time)self.logger.warning(f"达到API速率限制,等待{wait_time:.2f}秒")time.sleep(wait_time)# 重置计数器self.request_count = 0self.last_reset_time = current_time# 增加请求计数self.request_count += 1def spider_closed(self, spider):"""爬虫关闭时的清理工作"""self.logger.info("淘宝API中间件: 爬虫已关闭")    

Scrapy 是一个为了爬取网站数据、提取结构性数据而编写的应用框架。它可以应用在数据挖掘、信息处理或存储历史数据等一系列的程序中。

Scrapy 的架构中,中间件是一个很重要的组件,分为下载中间件 (Downloader Middleware) 和爬虫中间件 (Spider Middleware)。下载中间件可以拦截请求和响应,进行预处理;爬虫中间件则可以处理爬虫的输入 (响应) 和输出 (请求)。

在接入淘宝 API 的场景中,我们可以定制下载中间件,专门处理 API 请求的签名生成、速率控制、错误重试等逻辑,使爬虫代码更加简洁和可维护。

四、定制淘宝 API 中间件

下面是一个完整的淘宝 API 中间件实现,它负责处理 API 请求的签名生成、速率控制和错误重试:

[中间件代码见上面 doubaocanvas 中的 taobao_middleware.py]

这个中间件具有以下功能:

  1. 参数处理:自动构建 API 请求的公共参数,并根据不同 API 方法添加特定参数
  2. 签名生成:按照淘宝 API 的要求,生成 HMAC-SHA1 签名
  3. 速率控制:根据 API 的 QPS 限制,自动控制请求频率,避免被限流
  4. 错误处理:捕获网络异常和 API 返回的错误,实现智能重试
  5. 数据解析:解析 API 返回的 JSON 数据,并传递给爬虫处理
五、创建淘宝商品爬虫

有了中间件之后,我们可以创建一个简单的爬虫来使用这个中间件:

[爬虫代码见上面 doubaocanvas 中的 taobao_spider.py]

这个爬虫的工作流程是:

  1. 初始化多个搜索关键词,每个关键词生成多页请求
  2. 通过中间件发送 API 请求获取商品列表
  3. 解析 API 返回的商品数据,提取需要的字段
  4. 生成 Item 对象传递给管道处理
六、数据模型与处理管道

为了存储爬取到的商品数据,我们需要定义数据模型和处理管道:

[数据模型和管道代码见上面 doubaocanvas 中的 items.py 和 pipelines.py]

这里我们使用 MongoDB 作为数据存储,管道会将商品数据去重并存储到 MongoDB 中。你也可以根据需要扩展管道,添加数据清洗、验证或导出到其他存储系统的功能。

七、项目配置

最后,我们需要在 Scrapy 项目的设置文件中配置中间件和其他参数:

[配置代码见上面 doubaocanvas 中的 settings.py]

在配置文件中,需要填入你的淘宝 API 的 ApiKey 和 ApiSecret,以及 MongoDB 的连接信息。同时,可以根据 API 的访问权限和性能要求,调整请求并发数、下载延迟等参数。

八、使用与优化建议
  1. 运行爬虫:在项目根目录下执行命令 scrapy crawl taobao 即可启动爬虫

  2. API 权限:不同的 API 需要不同的权限,需要申请相应的权限

  3. 速率控制:中间件已经实现了基本的速率控制,但不同 API 的 QPS 限制不同,需要根据实际情况调整

  4. 数据量控制:淘宝 API 通常对单次请求返回的数据量有限制,可以通过分页获取更多数据

  5. 异常处理:中间件已经包含了基本的异常处理和重试机制,但在实际使用中可能需要根据具体情况调整

  6. 数据存储:MongoDB 适合存储结构灵活的商品数据,也可以根据需要改用其他数据库

通过以上步骤,你可以建立一个高效、稳定的淘宝商品数据采集系统。定制的中间件使 API 请求处理逻辑与爬虫业务逻辑分离,提高了代码的可维护性和复用性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/91348.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/91348.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Jmeter全局变量跨线程组的使用

一、线程组1中从数据库中查询到字段值二、BeanShell取样器中设置为全局变量#为什么说props.put("Out1",Out);其实是设置Out1为Jmeter的属性了呢&#xff1f; 因为在后面的调试取样器运行结果中&#xff0c;会发现如果只打开显示变量开关&#xff0c;是看不到Out1运行…

前端技术栈详解

前端技术栈是指构建现代Web应用程序所需的一系列技术和工具的集合。以下是当前主流前端技术栈的详细解析&#xff1a; 一、核心基础技术 1. HTML5 作用&#xff1a;网页内容的结构化标记关键特性&#xff1a; 语义化标签&#xff08;<header>, <section>, <arti…

Git Pull 时遇到 Apply 和 Abort 选项?详解它们的含义与应对策略

在使用 Git 进行团队协作时&#xff0c;git pull 是最常用的命令之一&#xff0c;用于拉取远程仓库的最新代码并合并到本地分支。但有时执行 git pull 后&#xff0c;Git 会提示 ​Apply&#xff08;应用&#xff09;​​ 和 ​Abort&#xff08;中止&#xff09;​​ 两个选项…

暑期算法训练.11

目录 47. 力扣203 移除链表元素 47.1 题目解析&#xff1a; ​编辑 47.2 算法思路&#xff1a; 47.3 代码演示&#xff1a; ​编辑 48. 力扣2.两数相加 48.1 题目解析&#xff1a; ​编辑 48.2 算法思路; 48.3 代码演示&#xff1a; 48.4 总结反思&#xff1a; …

nl2sql grpo强化学习训练,加大数据量和轮数后,准确率没提升,反而下降了,如何调整

在NL2SQL任务中使用GRPO强化学习训练时&#xff0c;增加数据量和训练轮数后准确率下降&#xff0c;通常是由过拟合、训练不稳定、奖励函数设计不合理、数据质量问题或探索-利用失衡等原因导致的。以下是具体的诊断思路和调整策略&#xff0c;帮助定位问题并优化性能&#xff1a…

PHP/Java/Python实现:如何有效防止恶意文件上传

文章目录 木马病毒防范:文件上传如何彻底防止伪造文件类型 引言 一、文件类型伪造的原理与危害 1.1 常见伪造手段 1.2 潜在危害 二、防御体系设计 2.1 防御架构 三、核心防御技术实现 3.1 服务端验证实现 3.1.1 文件内容检测(Python示例) 3.1.2 扩展名与内容双重验证(Java示…

SpringBoot系列之基于Redis的分布式限流器

SpringBoot系列之基于Redis的分布式限流器 SpringBoot 系列之基于 Redis 的分布式限流器 图文并茂,代码即拷即用,支持 4 种算法(固定窗口 / 滑动窗口 / 令牌桶 / 漏桶) 一、为什么要用分布式限流? 单机 Guava-RateLimiter 在集群下会 各玩各的,流量漂移,无法全局控量。…

面试遇到的问题2

Redisson的看门狗相关问题 首先要明确一点&#xff0c;看门狗机制的使用方式是&#xff1a;在加锁的时候不加任何参数&#xff0c;也就是&#xff1a; RLock lock redisson.getLock("myLock"); try {lock.lock(); // 阻塞式加锁// 业务逻辑... } finally {lock.unl…

Linux—进程概念与理解

目录 1.冯诺依曼体系结构 小结&#xff1a; 2.操作系统 概念&#xff1a; 结构示意图&#xff1a; 理解操作系统&#xff1a; 用户使用底层硬件层次图&#xff1a;​编辑 3.进程 概念 结构示意图 task_ struct内容分类 典型用法示例 观察进程: 了解 PID PPID 查…

LeetCode 面试经典 150_数组/字符串_买卖股票的最佳时机(7_121_C++_简单)(贪心)

LeetCode 面试经典 150_数组/字符串_买卖股票的最佳时机&#xff08;7_121_C_简单&#xff09;题目描述&#xff1a;输入输出样例&#xff1a;题解&#xff1a;解题思路&#xff1a;思路一&#xff08;贪心算法&#xff09;&#xff1a;代码实现代码实现&#xff08;思路一&…

Ubuntu 18.04 repo sync报错:line 0: Bad configuration option: setenv

repo sync时报 line 0: Bad configuration option: setenv因为 Ubuntu 18.04 默认的 openssh-client 是 7.6p1&#xff0c;还不支持 setenv&#xff0c;但是.repo/repo/ssh.py 脚本中明确地传入了 SetEnv 参数给 ssh&#xff0c;而你的 OpenSSH 7.6 不支持这个参数。需要按如下…

bug记录-stylelint

BUG1不支持Vue文件内联style样式解决&#xff1a; "no-invalid-position-declaration": null

前端开发(HTML,CSS,VUE,JS)从入门到精通!第一天(HTML5)

一、HTML5 简介1&#xff0e;HTML全称是 Hyber Text Markup Language&#xff0c;超文本标记语言&#xff0c;它是互联网上应用最广泛的标记语言&#xff0c;简单说&#xff0c;HTML 页面就等于“普通文本HTML标记&#xff08;HTML标签&#xff09;“。2&#xff0e;HTML 总共经…

智慧收银系统开发进销存:便利店、水果店、建材与家居行业的—仙盟创梦IDE

在数字化转型的浪潮中&#xff0c;收银系统已不再局限于简单的收款功能&#xff0c;而是成为企业进销存管理的核心枢纽。从便利店的快消品管理到建材家居行业的大宗商品调度&#xff0c;现代收银系统通过智能化技术重塑了传统商业模式。本文将深入探讨收银系统在不同行业进销存…

三维扫描相机:工业自动化的智慧之眼——迁移科技赋能智能制造新纪元

在当今工业4.0时代&#xff0c;自动化技术正重塑生产流程&#xff0c;而核心工具如三维扫描相机已成为关键驱动力。作为工业自动化领域的“智慧之眼”&#xff0c;三维扫描相机通过高精度三维重建能力&#xff0c;解决了传统制造中的效率瓶颈和精度痛点。迁移科技&#xff0c;自…

Jmeter的元件使用介绍:(九)监听器详解

监听器主要是用来监听脚本执行的取样器结果。Jmeter的默认监听器有&#xff1a;查看结果树、聚合报告、汇总报告、用表格查看结果&#xff0c;断言结果、图形结果、Beanshell监听器、JSR223监听器、比较断言可视化器、后端监听器、邮件观察器&#xff0c;本文介绍最常用的监听器…

联通元景万悟 开源,抢先体验!!!

简介&#xff1a; 元景万悟智能体平台是一款面向企业级场景的一站式、商用license友好的智能体开发平台&#xff0c;是业界第一款go语言&#xff08;后端&#xff09;开发的智能体开发平台&#xff08;7月19日&#xff09;&#xff0c;coze studio开源是7月26日&#xff0c;同时…

Git之本地仓库管理

一.什么是Git在学习工作中&#xff0c;我们经常会遇到改文档的场景。一个文档可能会被我们修改多次&#xff0c;而最终真正使用的可能是最先的几版。而如果我们直接在原文档上修改&#xff0c;就会导致无法找到最先的几次。这也就导致我们要对我们所有的版本进行维护&#xff0…

Go再进阶:结构体、接口与面向对象编程

&#x1f680; Go再进阶&#xff1a;结构体、接口与面向对象编程 大家好&#xff01;在前两篇文章中&#xff0c;我们深入学习了Go语言的流程控制语句以及数组和切片的使用并且还对Go 语言的核心知识点进行了补充讲解&#xff0c;这些知识让我们能够编写出更为复杂和灵活的程序…

Python入门第六课:现代开发与前沿技术

异步编程(asyncio) 1. 协程基础 import asyncio import time# 定义协程函数 async def say_after(delay, message):await asyncio.sleep(delay)print(message)# 主协程 async def main():print(f"开始时间: {time.strftime(%X)}")# 顺序执行await say_after(2, 你…