<?xml version="1.0" encoding="utf-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0"><channel><title>万邦api博客</title><link>https://alexob.com/</link><description>Good Luck To You!</description><item><title>🔥 电商库存扣减防超卖：分布式锁的三种实现（附Python源码）</title><link>https://alexob.com/?id=381</link><description>&lt;div class=&quot;ybc-p&quot;&gt;电商库存扣减是&lt;strong&gt;高并发场景下的经典难题&lt;/strong&gt;。超卖的本质是：&lt;strong&gt;多个并发请求同时读到库存&amp;gt;0，然后同时扣减，导致实际扣减数超过库存总量&lt;/strong&gt;。下面我将从最基础的方案讲起，逐步深入到生产级方案。&lt;/div&gt;&lt;hr/&gt;&lt;h2&gt;一、 超卖问题的根源&lt;/h2&gt;&lt;pre class=&quot;ybc-pre-component ybc-pre-component_not-math&quot;&gt;#&amp;nbsp;错误示范：经典的超卖代码
def&amp;nbsp;deduct_stock(product_id,&amp;nbsp;quantity):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;stock&amp;nbsp;=&amp;nbsp;db.query(&amp;quot;SELECT&amp;nbsp;stock&amp;nbsp;FROM&amp;nbsp;products&amp;nbsp;WHERE&amp;nbsp;id&amp;nbsp;=&amp;nbsp;?&amp;quot;,&amp;nbsp;product_id)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;stock&amp;nbsp;&amp;gt;=&amp;nbsp;quantity:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;db.execute(&amp;quot;UPDATE&amp;nbsp;products&amp;nbsp;SET&amp;nbsp;stock&amp;nbsp;=&amp;nbsp;stock&amp;nbsp;-&amp;nbsp;?&amp;nbsp;WHERE&amp;nbsp;id&amp;nbsp;=&amp;nbsp;?&amp;quot;,&amp;nbsp;quantity,&amp;nbsp;product_id)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;True
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;False&lt;/pre&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;问题&lt;/strong&gt;：在高并发下，两个请求同时读到 &lt;code class=&quot;hyc-common-markdown__code__inline&quot;&gt;stock=10&lt;/code&gt;，都认为库存充足，都执行了扣减，最终库存变成 &lt;code class=&quot;hyc-common-markdown__code__inline&quot;&gt;-2&lt;/code&gt;。&lt;/div&gt;&lt;hr/&gt;&lt;h2&gt;二、 分布式锁的三种实现方案&lt;/h2&gt;&lt;h3&gt;方案一：数据库乐观锁（最简单，适合低并发）&lt;/h3&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;原理&lt;/strong&gt;：利用数据库的行锁或版本号机制，保证扣减操作的原子性。&lt;/div&gt;&lt;pre class=&quot;ybc-pre-component ybc-pre-component_not-math&quot;&gt;#&amp;nbsp;optimistic_lock.py
import&amp;nbsp;pymysql
from&amp;nbsp;contextlib&amp;nbsp;import&amp;nbsp;contextmanager
#&amp;nbsp;封装好API供应商demo&amp;nbsp;url=https://console.open.onebound.cn/console/?i=Lex
class&amp;nbsp;OptimisticLockDeduction:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;数据库乐观锁扣减库存&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;__init__(self,&amp;nbsp;db_config):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.db_config&amp;nbsp;=&amp;nbsp;db_config
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@contextmanager
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;get_connection(self):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;conn&amp;nbsp;=&amp;nbsp;pymysql.connect(**self.db_config)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;yield&amp;nbsp;conn
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;conn.commit()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;except:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;conn.rollback()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;raise
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;finally:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;conn.close()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;deduct_stock(self,&amp;nbsp;product_id,&amp;nbsp;quantity):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;使用乐观锁扣减库存（CAS思想）&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;with&amp;nbsp;self.get_connection()&amp;nbsp;as&amp;nbsp;conn:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cursor&amp;nbsp;=&amp;nbsp;conn.cursor()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;1.&amp;nbsp;查询当前库存和版本号
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cursor.execute(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;SELECT&amp;nbsp;stock,&amp;nbsp;version&amp;nbsp;FROM&amp;nbsp;products&amp;nbsp;WHERE&amp;nbsp;id&amp;nbsp;=&amp;nbsp;%s&amp;quot;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;(product_id,)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;row&amp;nbsp;=&amp;nbsp;cursor.fetchone()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;not&amp;nbsp;row:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;False,&amp;nbsp;&amp;quot;商品不存在&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;stock,&amp;nbsp;version&amp;nbsp;=&amp;nbsp;row
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;2.&amp;nbsp;检查库存是否充足
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;stock&amp;nbsp;&amp;lt;&amp;nbsp;quantity:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;False,&amp;nbsp;&amp;quot;库存不足&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;3.&amp;nbsp;使用版本号进行乐观锁更新
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;affected&amp;nbsp;=&amp;nbsp;cursor.execute(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;UPDATE&amp;nbsp;products&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SET&amp;nbsp;stock&amp;nbsp;=&amp;nbsp;stock&amp;nbsp;-&amp;nbsp;%s,&amp;nbsp;version&amp;nbsp;=&amp;nbsp;version&amp;nbsp;+&amp;nbsp;1&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;WHERE&amp;nbsp;id&amp;nbsp;=&amp;nbsp;%s&amp;nbsp;AND&amp;nbsp;version&amp;nbsp;=&amp;nbsp;%s&amp;quot;&amp;quot;&amp;quot;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;(quantity,&amp;nbsp;product_id,&amp;nbsp;version)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;4.&amp;nbsp;检查是否更新成功
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;affected&amp;nbsp;==&amp;nbsp;0:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;False,&amp;nbsp;&amp;quot;并发冲突，请重试&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;True,&amp;nbsp;&amp;quot;扣减成功&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;deduct_stock_with_sql(self,&amp;nbsp;product_id,&amp;nbsp;quantity):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;使用SQL直接扣减（更简洁的方式）&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;with&amp;nbsp;self.get_connection()&amp;nbsp;as&amp;nbsp;conn:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cursor&amp;nbsp;=&amp;nbsp;conn.cursor()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;直接在SQL中判断库存
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;affected&amp;nbsp;=&amp;nbsp;cursor.execute(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;UPDATE&amp;nbsp;products&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SET&amp;nbsp;stock&amp;nbsp;=&amp;nbsp;stock&amp;nbsp;-&amp;nbsp;%s&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;WHERE&amp;nbsp;id&amp;nbsp;=&amp;nbsp;%s&amp;nbsp;AND&amp;nbsp;stock&amp;nbsp;&amp;gt;=&amp;nbsp;%s&amp;quot;&amp;quot;&amp;quot;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;(quantity,&amp;nbsp;product_id,&amp;nbsp;quantity)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;affected&amp;nbsp;==&amp;nbsp;0:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;可能是库存不足或商品不存在
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cursor.execute(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;SELECT&amp;nbsp;stock&amp;nbsp;FROM&amp;nbsp;products&amp;nbsp;WHERE&amp;nbsp;id&amp;nbsp;=&amp;nbsp;%s&amp;quot;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;(product_id,)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;row&amp;nbsp;=&amp;nbsp;cursor.fetchone()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;row&amp;nbsp;and&amp;nbsp;row[0]&amp;nbsp;&amp;lt;&amp;nbsp;quantity:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;False,&amp;nbsp;&amp;quot;库存不足&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;elif&amp;nbsp;not&amp;nbsp;row:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;False,&amp;nbsp;&amp;quot;商品不存在&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;False,&amp;nbsp;&amp;quot;并发冲突&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;True,&amp;nbsp;&amp;quot;扣减成功&amp;quot;

#&amp;nbsp;使用示例
if&amp;nbsp;__name__&amp;nbsp;==&amp;nbsp;&amp;quot;__main__&amp;quot;:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;db_config&amp;nbsp;=&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;host&amp;#39;:&amp;nbsp;&amp;#39;localhost&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;user&amp;#39;:&amp;nbsp;&amp;#39;root&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;password&amp;#39;:&amp;nbsp;&amp;#39;password&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;database&amp;#39;:&amp;nbsp;&amp;#39;shop&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;charset&amp;#39;:&amp;nbsp;&amp;#39;utf8mb4&amp;#39;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;deduction&amp;nbsp;=&amp;nbsp;OptimisticLockDeduction(db_config)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;success,&amp;nbsp;msg&amp;nbsp;=&amp;nbsp;deduction.deduct_stock(1001,&amp;nbsp;2)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(f&amp;quot;{&amp;#39;✅&amp;#39;&amp;nbsp;if&amp;nbsp;success&amp;nbsp;else&amp;nbsp;&amp;#39;❌&amp;#39;}&amp;nbsp;{msg}&amp;quot;)&lt;/pre&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;优点&lt;/strong&gt;：实现简单，不需要额外组件&lt;/div&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;缺点&lt;/strong&gt;：高并发下大量重试，性能下降明显&lt;/div&gt;&lt;hr/&gt;&lt;h3&gt;方案二：Redis分布式锁（高性能，适合中等并发）&lt;/h3&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;原理&lt;/strong&gt;：利用Redis的单线程特性和SETNX命令，实现分布式锁。&lt;/div&gt;&lt;pre class=&quot;ybc-pre-component ybc-pre-component_not-math&quot;&gt;#&amp;nbsp;redis_lock.py
import&amp;nbsp;redis
import&amp;nbsp;time
import&amp;nbsp;uuid
import&amp;nbsp;threading
from&amp;nbsp;contextlib&amp;nbsp;import&amp;nbsp;contextmanager
#&amp;nbsp;封装好API供应商demo&amp;nbsp;url=https://console.open.onebound.cn/console/?i=Lex
class&amp;nbsp;RedisDistributedLock:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;Redis分布式锁实现&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;__init__(self,&amp;nbsp;redis_client):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.redis&amp;nbsp;=&amp;nbsp;redis_client
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.lock_timeout&amp;nbsp;=&amp;nbsp;30&amp;nbsp;&amp;nbsp;#&amp;nbsp;锁的超时时间（秒）
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;acquire_lock(self,&amp;nbsp;lock_key,&amp;nbsp;request_id,&amp;nbsp;timeout=None):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;获取分布式锁
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Args:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;lock_key:&amp;nbsp;锁的键
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;request_id:&amp;nbsp;请求唯一标识（用于解锁验证）
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;timeout:&amp;nbsp;锁的超时时间
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Returns:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;bool:&amp;nbsp;是否获取成功
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;timeout&amp;nbsp;=&amp;nbsp;timeout&amp;nbsp;or&amp;nbsp;self.lock_timeout
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;SETNX&amp;nbsp;+&amp;nbsp;EXPIRE&amp;nbsp;原子操作（Redis&amp;nbsp;2.6.12+）
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;result&amp;nbsp;=&amp;nbsp;self.redis.set(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;lock_key,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;request_id,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;nx=True,&amp;nbsp;&amp;nbsp;#&amp;nbsp;只在键不存在时设置
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ex=timeout&amp;nbsp;&amp;nbsp;#&amp;nbsp;设置过期时间
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;result&amp;nbsp;is&amp;nbsp;True
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;release_lock(self,&amp;nbsp;lock_key,&amp;nbsp;request_id):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;释放分布式锁（使用Lua脚本保证原子性）
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;只有持有锁的客户端才能释放锁，防止误删别人的锁
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;lua_script&amp;nbsp;=&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;redis.call(&amp;#39;get&amp;#39;,&amp;nbsp;KEYS[1])&amp;nbsp;==&amp;nbsp;ARGV[1]&amp;nbsp;then
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;redis.call(&amp;#39;del&amp;#39;,&amp;nbsp;KEYS[1])
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;0
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;end
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;result&amp;nbsp;=&amp;nbsp;self.redis.eval(lua_script,&amp;nbsp;1,&amp;nbsp;lock_key,&amp;nbsp;request_id)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;result&amp;nbsp;==&amp;nbsp;1
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;spin_lock(self,&amp;nbsp;lock_key,&amp;nbsp;request_id,&amp;nbsp;acquire_timeout=10):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;自旋获取锁（带超时）
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Args:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;lock_key:&amp;nbsp;锁的键
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;request_id:&amp;nbsp;请求唯一标识
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;acquire_timeout:&amp;nbsp;获取锁的超时时间
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Returns:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;bool:&amp;nbsp;是否获取成功
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;start_time&amp;nbsp;=&amp;nbsp;time.time()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;while&amp;nbsp;time.time()&amp;nbsp;-&amp;nbsp;start_time&amp;nbsp;&amp;lt;&amp;nbsp;acquire_timeout:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;self.acquire_lock(lock_key,&amp;nbsp;request_id):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;True
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;time.sleep(0.1)&amp;nbsp;&amp;nbsp;#&amp;nbsp;休眠100ms再试
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;False
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@contextmanager
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;lock(self,&amp;nbsp;lock_key,&amp;nbsp;acquire_timeout=10):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;上下文管理器方式使用锁
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Usage:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;with&amp;nbsp;lock_manager.lock(&amp;#39;product:1001&amp;#39;):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;执行业务逻辑
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pass
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;request_id&amp;nbsp;=&amp;nbsp;str(uuid.uuid4())
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;not&amp;nbsp;self.spin_lock(lock_key,&amp;nbsp;request_id,&amp;nbsp;acquire_timeout):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;raise&amp;nbsp;TimeoutError(f&amp;quot;获取锁超时:&amp;nbsp;{lock_key}&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;yield
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;finally:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.release_lock(lock_key,&amp;nbsp;request_id)


class&amp;nbsp;RedisStockDeduction:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;基于Redis分布式锁的库存扣减&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;__init__(self,&amp;nbsp;redis_client,&amp;nbsp;db_connection):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.redis&amp;nbsp;=&amp;nbsp;redis_client
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.db&amp;nbsp;=&amp;nbsp;db_connection
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.lock_manager&amp;nbsp;=&amp;nbsp;RedisDistributedLock(redis_client)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;deduct_stock(self,&amp;nbsp;product_id,&amp;nbsp;quantity):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;扣减库存（带分布式锁）
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;流程：
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;1.&amp;nbsp;获取分布式锁
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;2.&amp;nbsp;查询库存
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;3.&amp;nbsp;扣减库存
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;4.&amp;nbsp;释放锁
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;lock_key&amp;nbsp;=&amp;nbsp;f&amp;quot;lock:product:{product_id}&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;with&amp;nbsp;self.lock_manager.lock(lock_key):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;在锁的保护下执行扣减
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cursor&amp;nbsp;=&amp;nbsp;self.db.cursor()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;查询当前库存
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cursor.execute(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;SELECT&amp;nbsp;stock&amp;nbsp;FROM&amp;nbsp;products&amp;nbsp;WHERE&amp;nbsp;id&amp;nbsp;=&amp;nbsp;%s&amp;nbsp;FOR&amp;nbsp;UPDATE&amp;quot;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;(product_id,)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;row&amp;nbsp;=&amp;nbsp;cursor.fetchone()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;not&amp;nbsp;row:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;False,&amp;nbsp;&amp;quot;商品不存在&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;row[0]&amp;nbsp;&amp;lt;&amp;nbsp;quantity:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;False,&amp;nbsp;&amp;quot;库存不足&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;扣减库存
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cursor.execute(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;UPDATE&amp;nbsp;products&amp;nbsp;SET&amp;nbsp;stock&amp;nbsp;=&amp;nbsp;stock&amp;nbsp;-&amp;nbsp;%s&amp;nbsp;WHERE&amp;nbsp;id&amp;nbsp;=&amp;nbsp;%s&amp;quot;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;(quantity,&amp;nbsp;product_id)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.db.commit()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;True,&amp;nbsp;&amp;quot;扣减成功&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;except&amp;nbsp;TimeoutError:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;False,&amp;nbsp;&amp;quot;系统繁忙，请稍后重试&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;except&amp;nbsp;Exception&amp;nbsp;as&amp;nbsp;e:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.db.rollback()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;False,&amp;nbsp;f&amp;quot;扣减失败:&amp;nbsp;{str(e)}&amp;quot;


#&amp;nbsp;Redlock算法实现（Redis官方推荐的分布式锁算法）
class&amp;nbsp;Redlock:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;Redlock算法：适用于Redis集群的高可靠分布式锁&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;封装好API供应商demo&amp;nbsp;url=https://console.open.onebound.cn/console/?i=Lex
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;__init__(self,&amp;nbsp;redis_nodes):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Args:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;redis_nodes:&amp;nbsp;Redis节点列表&amp;nbsp;[client1,&amp;nbsp;client2,&amp;nbsp;client3]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.redis_nodes&amp;nbsp;=&amp;nbsp;redis_nodes
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.quorum&amp;nbsp;=&amp;nbsp;len(redis_nodes)&amp;nbsp;//&amp;nbsp;2&amp;nbsp;+&amp;nbsp;1&amp;nbsp;&amp;nbsp;#&amp;nbsp;多数派
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;acquire_lock(self,&amp;nbsp;resource,&amp;nbsp;ttl):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;获取Redlock
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Args:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;resource:&amp;nbsp;资源名称
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ttl:&amp;nbsp;锁的存活时间（毫秒）
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;request_id&amp;nbsp;=&amp;nbsp;str(uuid.uuid4())
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;start_time&amp;nbsp;=&amp;nbsp;int(time.time()&amp;nbsp;*&amp;nbsp;1000)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;acquired_count&amp;nbsp;=&amp;nbsp;0
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;向所有Redis节点请求锁
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;node&amp;nbsp;in&amp;nbsp;self.redis_nodes:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;node.set(resource,&amp;nbsp;request_id,&amp;nbsp;nx=True,&amp;nbsp;px=ttl):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;acquired_count&amp;nbsp;+=&amp;nbsp;1
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;except:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pass
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;检查是否获取了多数派的锁
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;elapsed&amp;nbsp;=&amp;nbsp;int(time.time()&amp;nbsp;*&amp;nbsp;1000)&amp;nbsp;-&amp;nbsp;start_time
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;acquired_count&amp;nbsp;&amp;gt;=&amp;nbsp;self.quorum&amp;nbsp;and&amp;nbsp;elapsed&amp;nbsp;&amp;lt;&amp;nbsp;ttl:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;True,&amp;nbsp;request_id
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;释放已获取的锁
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;node&amp;nbsp;in&amp;nbsp;self.redis_nodes:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;node.delete(resource)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;except:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pass
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;False,&amp;nbsp;None
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;release_lock(self,&amp;nbsp;resource,&amp;nbsp;request_id):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;释放Redlock&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;lua_script&amp;nbsp;=&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;redis.call(&amp;#39;get&amp;#39;,&amp;nbsp;KEYS[1])&amp;nbsp;==&amp;nbsp;ARGV[1]&amp;nbsp;then
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;redis.call(&amp;#39;del&amp;#39;,&amp;nbsp;KEYS[1])
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;0
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;end
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;released_count&amp;nbsp;=&amp;nbsp;0
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;node&amp;nbsp;in&amp;nbsp;self.redis_nodes:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;node.eval(lua_script,&amp;nbsp;1,&amp;nbsp;resource,&amp;nbsp;request_id):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;released_count&amp;nbsp;+=&amp;nbsp;1
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;except:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pass
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;released_count&amp;nbsp;&amp;gt;=&amp;nbsp;self.quorum


#&amp;nbsp;使用示例
if&amp;nbsp;__name__&amp;nbsp;==&amp;nbsp;&amp;quot;__main__&amp;quot;:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;连接Redis
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;redis_client&amp;nbsp;=&amp;nbsp;redis.Redis(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;host=&amp;#39;localhost&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;port=6379,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;db=0,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;decode_responses=True
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;创建锁管理器
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;lock_manager&amp;nbsp;=&amp;nbsp;RedisDistributedLock(redis_client)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;模拟并发扣减
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;import&amp;nbsp;concurrent.futures
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;worker(product_id,&amp;nbsp;quantity,&amp;nbsp;worker_id):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;request_id&amp;nbsp;=&amp;nbsp;f&amp;quot;worker_{worker_id}_{uuid.uuid4()}&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;lock_key&amp;nbsp;=&amp;nbsp;f&amp;quot;product_lock:{product_id}&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;lock_manager.acquire_lock(lock_key,&amp;nbsp;request_id):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(f&amp;quot;Worker&amp;nbsp;{worker_id}:&amp;nbsp;获取锁成功，开始扣减&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;模拟业务处理
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;time.sleep(0.1)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(f&amp;quot;Worker&amp;nbsp;{worker_id}:&amp;nbsp;扣减完成&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;True
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;finally:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;lock_manager.release_lock(lock_key,&amp;nbsp;request_id)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(f&amp;quot;Worker&amp;nbsp;{worker_id}:&amp;nbsp;获取锁失败&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;False
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;启动10个并发线程
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;with&amp;nbsp;concurrent.futures.ThreadPoolExecutor(max_workers=10)&amp;nbsp;as&amp;nbsp;executor:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;futures&amp;nbsp;=&amp;nbsp;[
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;executor.submit(worker,&amp;nbsp;1001,&amp;nbsp;1,&amp;nbsp;i)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;i&amp;nbsp;in&amp;nbsp;range(10)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;results&amp;nbsp;=&amp;nbsp;[f.result()&amp;nbsp;for&amp;nbsp;f&amp;nbsp;in&amp;nbsp;concurrent.futures.as_completed(futures)]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(f&amp;quot;成功:&amp;nbsp;{sum(results)}/{len(results)}&amp;quot;)&lt;/pre&gt;&lt;hr/&gt;&lt;h3&gt;方案三：ZooKeeper分布式锁（强一致性，适合金融级场景）&lt;/h3&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;原理&lt;/strong&gt;：利用ZooKeeper的临时顺序节点和Watcher机制，实现公平锁。&lt;/div&gt;&lt;pre class=&quot;ybc-pre-component ybc-pre-component_not-math&quot;&gt;#&amp;nbsp;zk_lock.py
from&amp;nbsp;kazoo.client&amp;nbsp;import&amp;nbsp;KazooClient
from&amp;nbsp;kazoo.exceptions&amp;nbsp;import&amp;nbsp;NodeExistsError,&amp;nbsp;NoNodeError
import&amp;nbsp;uuid
import&amp;nbsp;time
from&amp;nbsp;contextlib&amp;nbsp;import&amp;nbsp;contextmanager
#&amp;nbsp;封装好API供应商demo&amp;nbsp;url=https://console.open.onebound.cn/console/?i=Lex
class&amp;nbsp;ZooKeeperDistributedLock:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;ZooKeeper分布式锁实现&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;__init__(self,&amp;nbsp;hosts=&amp;#39;localhost:2181&amp;#39;):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.zk&amp;nbsp;=&amp;nbsp;KazooClient(hosts=hosts)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.zk.start()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;锁的基础路径
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.lock_base_path&amp;nbsp;=&amp;nbsp;&amp;quot;/locks&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;确保基础路径存在
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.zk.ensure_path(self.lock_base_path)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;create_lock_node(self,&amp;nbsp;lock_path):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;创建锁节点
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;使用临时顺序节点，保证：
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;1.&amp;nbsp;客户端断开连接时自动删除
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;2.&amp;nbsp;节点有序，实现公平锁
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;request_id&amp;nbsp;=&amp;nbsp;str(uuid.uuid4())
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;node_path&amp;nbsp;=&amp;nbsp;f&amp;quot;{lock_path}/{request_id}-&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;创建临时顺序节点
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;actual_path&amp;nbsp;=&amp;nbsp;self.zk.create(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;node_path,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;value=b&amp;quot;locked&amp;quot;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sequence=True,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ephemeral=True
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;actual_path
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;acquire_lock(self,&amp;nbsp;lock_name,&amp;nbsp;timeout=10):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;获取分布式锁
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;使用ZooKeeper的顺序节点实现公平锁
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;lock_path&amp;nbsp;=&amp;nbsp;f&amp;quot;{self.lock_base_path}/{lock_name}&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.zk.ensure_path(lock_path)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;创建自己的锁节点
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;my_node&amp;nbsp;=&amp;nbsp;self.create_lock_node(lock_path)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;获取所有子节点
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;children&amp;nbsp;=&amp;nbsp;self.zk.get_children(lock_path)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;排序找到最小的节点（最早的请求）
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sorted_children&amp;nbsp;=&amp;nbsp;sorted(children)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;my_node_name&amp;nbsp;=&amp;nbsp;my_node.split(&amp;#39;/&amp;#39;)[-1]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;如果自己是第一个，获取锁成功
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;my_node_name&amp;nbsp;==&amp;nbsp;sorted_children[0]:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;True,&amp;nbsp;my_node
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;否则，监听前一个节点
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;my_index&amp;nbsp;=&amp;nbsp;sorted_children.index(my_node_name)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;prev_node&amp;nbsp;=&amp;nbsp;f&amp;quot;{lock_path}/{sorted_children[my_index&amp;nbsp;-&amp;nbsp;1]}&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;等待前一个节点释放
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;event&amp;nbsp;=&amp;nbsp;self.zk.get(prev_node,&amp;nbsp;watch=self._watch_func)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;等待事件触发或超时
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;event&amp;nbsp;and&amp;nbsp;event[0]&amp;nbsp;is&amp;nbsp;not&amp;nbsp;None:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;前一个节点还存在，等待
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;start_time&amp;nbsp;=&amp;nbsp;time.time()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;while&amp;nbsp;time.time()&amp;nbsp;-&amp;nbsp;start_time&amp;nbsp;&amp;lt;&amp;nbsp;timeout:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;not&amp;nbsp;self.zk.exists(prev_node):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;True,&amp;nbsp;my_node
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;time.sleep(0.1)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;超时，释放自己的节点
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.release_lock(my_node)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;False,&amp;nbsp;None
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;True,&amp;nbsp;my_node
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;except&amp;nbsp;Exception&amp;nbsp;as&amp;nbsp;e:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.release_lock(my_node)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;raise&amp;nbsp;e
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;_watch_func(self,&amp;nbsp;event):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;Watcher回调函数&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pass&amp;nbsp;&amp;nbsp;#&amp;nbsp;实际使用时可以记录日志
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;release_lock(self,&amp;nbsp;node_path):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;释放锁&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.zk.delete(node_path)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;True
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;except&amp;nbsp;NoNodeError:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;False
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;except&amp;nbsp;Exception&amp;nbsp;as&amp;nbsp;e:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(f&amp;quot;释放锁失败:&amp;nbsp;{e}&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;False
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@contextmanager
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;lock(self,&amp;nbsp;lock_name,&amp;nbsp;timeout=10):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;上下文管理器方式使用锁
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Usage:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;with&amp;nbsp;zk_lock.lock(&amp;#39;product:1001&amp;#39;):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;执行业务逻辑
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pass
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;acquired,&amp;nbsp;node_path&amp;nbsp;=&amp;nbsp;self.acquire_lock(lock_name,&amp;nbsp;timeout)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;not&amp;nbsp;acquired:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;raise&amp;nbsp;TimeoutError(f&amp;quot;获取锁超时:&amp;nbsp;{lock_name}&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;yield
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;finally:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.release_lock(node_path)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;close(self):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;关闭ZooKeeper连接&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.zk.stop()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.zk.close()


class&amp;nbsp;ZKStockDeduction:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;基于ZooKeeper分布式锁的库存扣减&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;__init__(self,&amp;nbsp;zk_hosts,&amp;nbsp;db_connection):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.zk_lock&amp;nbsp;=&amp;nbsp;ZooKeeperDistributedLock(zk_hosts)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.db&amp;nbsp;=&amp;nbsp;db_connection
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;deduct_stock(self,&amp;nbsp;product_id,&amp;nbsp;quantity):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;使用ZooKeeper锁扣减库存
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;lock_name&amp;nbsp;=&amp;nbsp;f&amp;quot;product_stock_{product_id}&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;with&amp;nbsp;self.zk_lock.lock(lock_name):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;在锁的保护下执行扣减
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cursor&amp;nbsp;=&amp;nbsp;self.db.cursor()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cursor.execute(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;SELECT&amp;nbsp;stock&amp;nbsp;FROM&amp;nbsp;products&amp;nbsp;WHERE&amp;nbsp;id&amp;nbsp;=&amp;nbsp;%s&amp;nbsp;FOR&amp;nbsp;UPDATE&amp;quot;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;(product_id,)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;row&amp;nbsp;=&amp;nbsp;cursor.fetchone()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;not&amp;nbsp;row:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;False,&amp;nbsp;&amp;quot;商品不存在&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;row[0]&amp;nbsp;&amp;lt;&amp;nbsp;quantity:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;False,&amp;nbsp;&amp;quot;库存不足&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cursor.execute(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;UPDATE&amp;nbsp;products&amp;nbsp;SET&amp;nbsp;stock&amp;nbsp;=&amp;nbsp;stock&amp;nbsp;-&amp;nbsp;%s&amp;nbsp;WHERE&amp;nbsp;id&amp;nbsp;=&amp;nbsp;%s&amp;quot;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;(quantity,&amp;nbsp;product_id)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.db.commit()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;True,&amp;nbsp;&amp;quot;扣减成功&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;except&amp;nbsp;TimeoutError:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;False,&amp;nbsp;&amp;quot;系统繁忙，请稍后重试&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;except&amp;nbsp;Exception&amp;nbsp;as&amp;nbsp;e:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.db.rollback()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;False,&amp;nbsp;f&amp;quot;扣减失败:&amp;nbsp;{str(e)}&amp;quot;


#&amp;nbsp;使用示例
if&amp;nbsp;__name__&amp;nbsp;==&amp;nbsp;&amp;quot;__main__&amp;quot;:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;创建ZooKeeper锁管理器
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;zk_lock&amp;nbsp;=&amp;nbsp;ZooKeeperDistributedLock(&amp;#39;localhost:2181&amp;#39;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;测试锁的基本功能
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(&amp;quot;测试ZooKeeper分布式锁...&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;获取锁
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;acquired,&amp;nbsp;node_path&amp;nbsp;=&amp;nbsp;zk_lock.acquire_lock(&amp;quot;test_lock&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(f&amp;quot;获取锁:&amp;nbsp;{&amp;#39;✅&amp;#39;&amp;nbsp;if&amp;nbsp;acquired&amp;nbsp;else&amp;nbsp;&amp;#39;❌&amp;#39;}&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;acquired:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;执行业务逻辑
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(&amp;quot;执行业务逻辑...&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;time.sleep(2)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;释放锁
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;released&amp;nbsp;=&amp;nbsp;zk_lock.release_lock(node_path)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(f&amp;quot;释放锁:&amp;nbsp;{&amp;#39;✅&amp;#39;&amp;nbsp;if&amp;nbsp;released&amp;nbsp;else&amp;nbsp;&amp;#39;❌&amp;#39;}&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;finally:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;zk_lock.close()&lt;/pre&gt;&lt;hr/&gt;&lt;h2&gt;三、 三种方案对比&lt;/h2&gt;&lt;div class=&quot;hyc-common-markdown__table-wrapper&quot; data-has-scroll=&quot;false&quot; style=&quot;font-size: 16px; border-collapse: separate; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;div style=&quot;font-size: 16px; border-collapse: separate; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;table&gt;&lt;thead style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;tr style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot; class=&quot;firstRow&quot;&gt;&lt;th style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;方案&lt;/div&gt;&lt;/th&gt;&lt;th style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;一致性&lt;/div&gt;&lt;/th&gt;&lt;th style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;性能&lt;/div&gt;&lt;/th&gt;&lt;th style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;可靠性&lt;/div&gt;&lt;/th&gt;&lt;th style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;复杂度&lt;/div&gt;&lt;/th&gt;&lt;th style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;适用场景&lt;/div&gt;&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;tr style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;strong style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;数据库乐观锁&lt;/strong&gt;&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;弱&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;低&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;高&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;低&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;低并发，简单场景&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;strong style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;Redis分布式锁&lt;/strong&gt;&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;中等&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;高&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;中等&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;中&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;高并发，允许短暂不一致&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;strong style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;ZooKeeper锁&lt;/strong&gt;&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;强&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;中等&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;极高&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;高&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;金融级，强一致性要求&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;/div&gt;&lt;h2&gt;四、 生产级最佳实践&lt;/h2&gt;&lt;ol class=&quot;ybc-ol-component ybc-ol-component_1 list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;组合使用&lt;/strong&gt;：Redis锁做高性能扣减 + 数据库兜底校验&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;库存预热&lt;/strong&gt;：秒杀开始前将库存加载到Redis，减少数据库压力&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;异步扣减&lt;/strong&gt;：先扣Redis库存，异步同步到数据库&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;兜底策略&lt;/strong&gt;：即使分布式锁失效，数据库的乐观锁也能防止超卖&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;记住&lt;/strong&gt;：没有完美的分布式锁方案，只有最适合你业务场景的方案。对于电商秒杀场景，&lt;strong&gt;Redis分布式锁 + 数据库乐观锁兜底&lt;/strong&gt;是最常见的生产级方案。&lt;/div&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;</description><pubDate>Sun, 31 May 2026 16:44:44 +0800</pubDate></item><item><title>🚀 【性能提升300%】仿1688首页的Webpack优化全记录（附构建分析Python脚本）</title><link>https://alexob.com/?id=380</link><description>&lt;h1&gt;&lt;span style=&quot;font-size: 14px;&quot;&gt;1688首页作为B类电商的高流量入口，首屏加载必须控制在&lt;/span&gt;&lt;strong style=&quot;font-size: 14px;&quot;&gt;1.5s内&lt;/strong&gt;&lt;span style=&quot;font-size: 14px;&quot;&gt;。其Webpack构建优化的本质不是“魔法配置”，而是&lt;/span&gt;&lt;strong style=&quot;font-size: 14px;&quot;&gt;减少无效编译、极致分包、懒加载与持久化缓存&lt;/strong&gt;&lt;span style=&quot;font-size: 14px;&quot;&gt;。下面我把这套优化链路拆给你看，并附上可直接用的构建产物分析脚本。&lt;/span&gt;&lt;br/&gt;&lt;/h1&gt;&lt;hr/&gt;&lt;h2&gt;一、 1688首页构建的四大性能杀手&lt;/h2&gt;&lt;div class=&quot;hyc-common-markdown__table-wrapper&quot; data-has-scroll=&quot;false&quot; style=&quot;font-size: 16px; border-collapse: separate; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;div style=&quot;font-size: 16px; border-collapse: separate; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;table&gt;&lt;thead style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;tr style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot; class=&quot;firstRow&quot;&gt;&lt;th style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;问题&lt;/div&gt;&lt;/th&gt;&lt;th style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;现象&lt;/div&gt;&lt;/th&gt;&lt;th style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;优化方向&lt;/div&gt;&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;tr style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;strong style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;全量重编&lt;/strong&gt;&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;改一个组件重新编译所有文件&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;缓存 + 增量编译&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;strong style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;巨型Vendor包&lt;/strong&gt;&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;code class=&quot;hyc-common-markdown__code__inline&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 2px 4px;&quot;&gt;vendor.js&lt;/code&gt;2MB+，首屏阻塞&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;按变动频率拆分Chunk&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;strong style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;同步引入大库&lt;/strong&gt;&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;code class=&quot;hyc-common-markdown__code__inline&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 2px 4px;&quot;&gt;import xxx from &amp;#39;echarts&amp;#39;&lt;/code&gt;全量打入&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;动态import / 按需引入&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;strong style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;未压缩SourceMap&lt;/strong&gt;&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;生产包含完整.map&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;分离SourceMap，生产关闭&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;/div&gt;&lt;hr/&gt;&lt;h2&gt;二、 Webpack核心优化配置（关键片段）&lt;/h2&gt;&lt;blockquote&gt;&lt;div class=&quot;ybc-p&quot;&gt;以下是最能产生性价比的配置，直接作用于 &lt;code class=&quot;hyc-common-markdown__code__inline&quot;&gt;webpack.config.js&lt;/code&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;pre class=&quot;ybc-pre-component ybc-pre-component_not-math&quot;&gt;//&amp;nbsp;webpack.config.prod.js&amp;nbsp;(关键优化点)
const&amp;nbsp;path&amp;nbsp;=&amp;nbsp;require(&amp;#39;path&amp;#39;);
const&amp;nbsp;TerserPlugin&amp;nbsp;=&amp;nbsp;require(&amp;#39;terser-webpack-plugin&amp;#39;);
const&amp;nbsp;MiniCssExtractPlugin&amp;nbsp;=&amp;nbsp;require(&amp;#39;mini-css-extract-plugin&amp;#39;);
const&amp;nbsp;{&amp;nbsp;BundleAnalyzerPlugin&amp;nbsp;}&amp;nbsp;=&amp;nbsp;require(&amp;#39;webpack-bundle-analyzer&amp;#39;);
#&amp;nbsp;封装好API供应商demo&amp;nbsp;url=https://console.open.onebound.cn/console/?i=Lex
module.exports&amp;nbsp;=&amp;nbsp;{
&amp;nbsp;&amp;nbsp;mode:&amp;nbsp;&amp;#39;production&amp;#39;,
&amp;nbsp;&amp;nbsp;entry:&amp;nbsp;&amp;#39;./src/main.js&amp;#39;,

&amp;nbsp;&amp;nbsp;output:&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;path:&amp;nbsp;path.resolve(__dirname,&amp;nbsp;&amp;#39;dist&amp;#39;),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;filename:&amp;nbsp;&amp;#39;js/[name].[contenthash:8].js&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;chunkFilename:&amp;nbsp;&amp;#39;js/[name].[contenthash:8].chunk.js&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;clean:&amp;nbsp;true,&amp;nbsp;&amp;nbsp;//&amp;nbsp;清理旧产物
&amp;nbsp;&amp;nbsp;},

&amp;nbsp;&amp;nbsp;//&amp;nbsp;★&amp;nbsp;缓存：增量编译提速&amp;nbsp;60%+
&amp;nbsp;&amp;nbsp;cache:&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;type:&amp;nbsp;&amp;#39;filesystem&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;buildDependencies:&amp;nbsp;{&amp;nbsp;config:&amp;nbsp;[__filename]&amp;nbsp;}
&amp;nbsp;&amp;nbsp;},

&amp;nbsp;&amp;nbsp;resolve:&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;alias:&amp;nbsp;{&amp;nbsp;&amp;#39;@&amp;#39;:&amp;nbsp;path.resolve(__dirname,&amp;nbsp;&amp;#39;src&amp;#39;)&amp;nbsp;},
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;extensions:&amp;nbsp;[&amp;#39;.js&amp;#39;,&amp;nbsp;&amp;#39;.vue&amp;#39;,&amp;nbsp;&amp;#39;.jsx&amp;#39;],
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;缩小模块查找范围
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;modules:&amp;nbsp;[path.resolve(__dirname,&amp;nbsp;&amp;#39;node_modules&amp;#39;)]
&amp;nbsp;&amp;nbsp;},

&amp;nbsp;&amp;nbsp;module:&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;rules:&amp;nbsp;[
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;JS/JSX&amp;nbsp;用&amp;nbsp;thread-loader&amp;nbsp;多进程编译
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;test:&amp;nbsp;/\.(js|jsx)$/,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;exclude:&amp;nbsp;/node_modules/,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;use:&amp;nbsp;[&amp;#39;thread-loader&amp;#39;,&amp;nbsp;&amp;#39;babel-loader&amp;#39;]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;},
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;CSS&amp;nbsp;提取单独文件（并行加载，不阻塞JS）
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;test:&amp;nbsp;/\.css$/,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;use:&amp;nbsp;[MiniCssExtractPlugin.loader,&amp;nbsp;&amp;#39;css-loader&amp;#39;]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;]
&amp;nbsp;&amp;nbsp;},

&amp;nbsp;&amp;nbsp;optimization:&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;★&amp;nbsp;按变动频率拆分Chunk&amp;nbsp;—&amp;nbsp;仿1688策略
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;splitChunks:&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;chunks:&amp;nbsp;&amp;#39;all&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cacheGroups:&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;1.&amp;nbsp;三方库（不常变）→&amp;nbsp;长缓存
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;vendor:&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;test:&amp;nbsp;/[\\/]node_modules[\\/]/,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;name:&amp;nbsp;&amp;#39;vendor&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;priority:&amp;nbsp;20,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;minChunks:&amp;nbsp;1,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;reuseExistingChunk:&amp;nbsp;true
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;},
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;2.&amp;nbsp;UI组件库单独拆（antd&amp;nbsp;/&amp;nbsp;element-ui）
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ui:&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;test:&amp;nbsp;/[\\/]node_modules[\\/](ant-design-vue|element-ui)[\\/]/,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;name:&amp;nbsp;&amp;#39;ui-lib&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;priority:&amp;nbsp;15,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;reuseExistingChunk:&amp;nbsp;true
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;},
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;3.&amp;nbsp;公共业务组件
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;common:&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;name:&amp;nbsp;&amp;#39;common&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;minChunks:&amp;nbsp;2,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;priority:&amp;nbsp;10,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;reuseExistingChunk:&amp;nbsp;true
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;},
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;★&amp;nbsp;JS压缩用Terser多进程
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;minimize:&amp;nbsp;true,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;minimizer:&amp;nbsp;[
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;new&amp;nbsp;TerserPlugin({
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;parallel:&amp;nbsp;true,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;terserOptions:&amp;nbsp;{&amp;nbsp;compress:&amp;nbsp;{&amp;nbsp;drop_console:&amp;nbsp;true&amp;nbsp;}&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;})
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;],
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;runtimeChunk:&amp;nbsp;&amp;#39;single&amp;#39;&amp;nbsp;&amp;nbsp;//&amp;nbsp;独立runtime，避免vendor&amp;nbsp;hash变动
&amp;nbsp;&amp;nbsp;},

&amp;nbsp;&amp;nbsp;plugins:&amp;nbsp;[
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;new&amp;nbsp;MiniCssExtractPlugin({
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;filename:&amp;nbsp;&amp;#39;css/[name].[contenthash:8].css&amp;#39;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;可选：分析产物体积
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;new&amp;nbsp;BundleAnalyzerPlugin()
&amp;nbsp;&amp;nbsp;],

&amp;nbsp;&amp;nbsp;//&amp;nbsp;★&amp;nbsp;生产关闭&amp;nbsp;SourceMap&amp;nbsp;或只放外部
&amp;nbsp;&amp;nbsp;devtool:&amp;nbsp;false
};&lt;/pre&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;首屏懒加载示例（Router层）&lt;/strong&gt;：&lt;/div&gt;&lt;pre class=&quot;ybc-pre-component ybc-pre-component_not-math&quot;&gt;//&amp;nbsp;router.js&amp;nbsp;—&amp;nbsp;1688首页banner、类目树等重量级组件懒加载
const&amp;nbsp;HomeBanner&amp;nbsp;=&amp;nbsp;()&amp;nbsp;=&amp;gt;&amp;nbsp;import(/*&amp;nbsp;webpackChunkName:&amp;nbsp;&amp;quot;home-banner&amp;quot;&amp;nbsp;*/&amp;nbsp;&amp;#39;@/components/HomeBanner.vue&amp;#39;);
const&amp;nbsp;CategoryTree&amp;nbsp;=&amp;nbsp;()&amp;nbsp;=&amp;gt;&amp;nbsp;import(/*&amp;nbsp;webpackChunkName:&amp;nbsp;&amp;quot;category-tree&amp;quot;&amp;nbsp;*/&amp;nbsp;&amp;#39;@/components/CategoryTree.vue&amp;#39;);&lt;/pre&gt;&lt;hr/&gt;&lt;h2&gt;三、 Python构建产物分析脚本（附源码）&lt;/h2&gt;&lt;div class=&quot;ybc-p&quot;&gt;前端优化必须&lt;strong&gt;数据驱动&lt;/strong&gt;。下面这个Python脚本读取Webpack Stats JSON，帮你找出体积异常的大Chunk和未拆分的Node Modules：&lt;/div&gt;&lt;pre class=&quot;ybc-pre-component ybc-pre-component_not-math&quot;&gt;#&amp;nbsp;analyze_bundle.py
&amp;quot;&amp;quot;&amp;quot;
用法：
&amp;nbsp;&amp;nbsp;webpack&amp;nbsp;--profile&amp;nbsp;--json&amp;nbsp;&amp;gt;&amp;nbsp;stats.json
&amp;nbsp;&amp;nbsp;python&amp;nbsp;analyze_bundle.py&amp;nbsp;stats.json

输出：
&amp;nbsp;&amp;nbsp;-&amp;nbsp;Top&amp;nbsp;20&amp;nbsp;最大Chunk
&amp;nbsp;&amp;nbsp;-&amp;nbsp;Node_modules占比
&amp;nbsp;&amp;nbsp;-&amp;nbsp;疑似未拆分的超大模块
&amp;quot;&amp;quot;&amp;quot;
import&amp;nbsp;json
import&amp;nbsp;sys
import&amp;nbsp;os
from&amp;nbsp;collections&amp;nbsp;import&amp;nbsp;defaultdict
from&amp;nbsp;pathlib&amp;nbsp;import&amp;nbsp;Path
#&amp;nbsp;封装好API供应商demo&amp;nbsp;url=https://console.open.onebound.cn/console/?i=Lex
def&amp;nbsp;load_stats(stats_path):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;with&amp;nbsp;open(stats_path,&amp;nbsp;&amp;#39;r&amp;#39;,&amp;nbsp;encoding=&amp;#39;utf-8&amp;#39;)&amp;nbsp;as&amp;nbsp;f:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;json.load(f)

def&amp;nbsp;get_assets(stats):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;提取所有产出资源及其大小&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;assets&amp;nbsp;=&amp;nbsp;stats.get(&amp;#39;assets&amp;#39;,&amp;nbsp;[])
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;[(a[&amp;#39;name&amp;#39;],&amp;nbsp;a[&amp;#39;size&amp;#39;])&amp;nbsp;for&amp;nbsp;a&amp;nbsp;in&amp;nbsp;assets&amp;nbsp;if&amp;nbsp;a.get(&amp;#39;size&amp;#39;)]

def&amp;nbsp;get_module_sizes(stats):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;按来源(module&amp;nbsp;identifier)聚合大小&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;modules&amp;nbsp;=&amp;nbsp;stats.get(&amp;#39;modules&amp;#39;,&amp;nbsp;[])
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;module_sizes&amp;nbsp;=&amp;nbsp;defaultdict(int)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;node_sizes&amp;nbsp;=&amp;nbsp;defaultdict(int)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;total_node&amp;nbsp;=&amp;nbsp;0
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;total_all&amp;nbsp;=&amp;nbsp;0

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;m&amp;nbsp;in&amp;nbsp;modules:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;size&amp;nbsp;=&amp;nbsp;m.get(&amp;#39;size&amp;#39;,&amp;nbsp;0)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;identifier&amp;nbsp;=&amp;nbsp;m.get(&amp;#39;identifier&amp;#39;,&amp;nbsp;&amp;#39;&amp;#39;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;total_all&amp;nbsp;+=&amp;nbsp;size

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;&amp;#39;/node_modules/&amp;#39;&amp;nbsp;in&amp;nbsp;identifier:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;提取包名，如&amp;nbsp;lodash&amp;nbsp;/&amp;nbsp;vue&amp;nbsp;/&amp;nbsp;ant-design-vue/dist/...
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;parts&amp;nbsp;=&amp;nbsp;identifier.split(&amp;#39;/node_modules/&amp;#39;)[1].split(&amp;#39;/&amp;#39;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pkg&amp;nbsp;=&amp;nbsp;parts[0]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;pkg.startswith(&amp;#39;@&amp;#39;):&amp;nbsp;&amp;nbsp;#&amp;nbsp;scoped&amp;nbsp;package:&amp;nbsp;@scope/pkg
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pkg&amp;nbsp;=&amp;nbsp;f&amp;quot;{parts[0]}/{parts[1]}&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;node_sizes[pkg]&amp;nbsp;+=&amp;nbsp;size
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;total_node&amp;nbsp;+=&amp;nbsp;size

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;module_sizes,&amp;nbsp;node_sizes,&amp;nbsp;total_node,&amp;nbsp;total_all

def&amp;nbsp;format_size(size_bytes):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;size_bytes&amp;nbsp;&amp;gt;=&amp;nbsp;1024&amp;nbsp;*&amp;nbsp;1024:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;f&amp;quot;{size_bytes&amp;nbsp;/&amp;nbsp;1024&amp;nbsp;/&amp;nbsp;1024:.2f}&amp;nbsp;MB&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;f&amp;quot;{size_bytes&amp;nbsp;/&amp;nbsp;1024:.1f}&amp;nbsp;KB&amp;quot;

def&amp;nbsp;analyze(stats_path):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;stats&amp;nbsp;=&amp;nbsp;load_stats(stats_path)

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(f&amp;quot;\n{&amp;#39;=&amp;#39;*55}&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(f&amp;quot;📦&amp;nbsp;Webpack&amp;nbsp;Bundle&amp;nbsp;分析报告:&amp;nbsp;{Path(stats_path).name}&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(f&amp;quot;{&amp;#39;=&amp;#39;*55}\n&amp;quot;)

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;——&amp;nbsp;1.&amp;nbsp;各资源大小&amp;nbsp;Top20&amp;nbsp;——
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;assets&amp;nbsp;=&amp;nbsp;get_assets(stats)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;assets.sort(key=lambda&amp;nbsp;x:&amp;nbsp;x[1],&amp;nbsp;reverse=True)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(&amp;quot;🔷&amp;nbsp;Top&amp;nbsp;20&amp;nbsp;最大产出文件：&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;name,&amp;nbsp;sz&amp;nbsp;in&amp;nbsp;assets[:20]:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;flag&amp;nbsp;=&amp;nbsp;&amp;quot;⚠️&amp;nbsp;&amp;nbsp;&amp;gt;500KB&amp;quot;&amp;nbsp;if&amp;nbsp;sz&amp;nbsp;&amp;gt;&amp;nbsp;500&amp;nbsp;*&amp;nbsp;1024&amp;nbsp;else&amp;nbsp;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(f&amp;quot;&amp;nbsp;&amp;nbsp;{format_size(sz):&amp;gt;10}&amp;nbsp;&amp;nbsp;{name}&amp;nbsp;&amp;nbsp;{flag}&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;len(assets)&amp;nbsp;&amp;gt;&amp;nbsp;20:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(f&amp;quot;&amp;nbsp;&amp;nbsp;...共&amp;nbsp;{len(assets)}&amp;nbsp;个文件&amp;quot;)

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;——&amp;nbsp;2.&amp;nbsp;Node_modules&amp;nbsp;包体积排行&amp;nbsp;——
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;_,&amp;nbsp;node_sizes,&amp;nbsp;total_node,&amp;nbsp;total_all&amp;nbsp;=&amp;nbsp;get_module_sizes(stats)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(f&amp;quot;\n🔷&amp;nbsp;node_modules&amp;nbsp;总占比:&amp;nbsp;{total_node/total_all*100:.1f}%&amp;nbsp;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;f&amp;quot;({format_size(total_node)}&amp;nbsp;/&amp;nbsp;{format_size(total_all)})&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(&amp;quot;🔷&amp;nbsp;三方包&amp;nbsp;Top&amp;nbsp;10（按体积）：&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ranked&amp;nbsp;=&amp;nbsp;sorted(node_sizes.items(),&amp;nbsp;key=lambda&amp;nbsp;x:&amp;nbsp;x[1],&amp;nbsp;reverse=True)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;pkg,&amp;nbsp;sz&amp;nbsp;in&amp;nbsp;ranked[:10]:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(f&amp;quot;&amp;nbsp;&amp;nbsp;{format_size(sz):&amp;gt;10}&amp;nbsp;&amp;nbsp;{pkg}&amp;quot;)

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;——&amp;nbsp;3.&amp;nbsp;疑似问题提示&amp;nbsp;——
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(&amp;quot;\n🔷&amp;nbsp;检查项：&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;big_js&amp;nbsp;=&amp;nbsp;[n&amp;nbsp;for&amp;nbsp;n,&amp;nbsp;s&amp;nbsp;in&amp;nbsp;assets&amp;nbsp;if&amp;nbsp;n.endswith(&amp;#39;.js&amp;#39;)&amp;nbsp;and&amp;nbsp;s&amp;nbsp;&amp;gt;&amp;nbsp;1024&amp;nbsp;*&amp;nbsp;1024]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;big_js:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(f&amp;quot;&amp;nbsp;&amp;nbsp;⚠️&amp;nbsp;&amp;nbsp;发现&amp;nbsp;{len(big_js)}&amp;nbsp;个&amp;nbsp;&amp;gt;1MB&amp;nbsp;JS文件，建议拆分：&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;b&amp;nbsp;in&amp;nbsp;big_js:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(f&amp;quot;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;-&amp;nbsp;{b}&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(&amp;quot;&amp;nbsp;&amp;nbsp;✅&amp;nbsp;&amp;nbsp;无超大JS文件&amp;nbsp;(&amp;gt;1MB)&amp;quot;)

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;total_node&amp;nbsp;/&amp;nbsp;total_all&amp;nbsp;&amp;gt;&amp;nbsp;0.75:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(&amp;quot;&amp;nbsp;&amp;nbsp;⚠️&amp;nbsp;&amp;nbsp;node_modules&amp;nbsp;占比&amp;nbsp;&amp;gt;75%，考虑UI库单独拆chunk或按需引入&amp;quot;)

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;not&amp;nbsp;any(n.endswith(&amp;#39;.css&amp;#39;)&amp;nbsp;for&amp;nbsp;n,&amp;nbsp;_&amp;nbsp;in&amp;nbsp;assets):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(&amp;quot;&amp;nbsp;&amp;nbsp;ℹ️&amp;nbsp;&amp;nbsp;未发现独立CSS，可能未使用&amp;nbsp;MiniCssExtractPlugin&amp;quot;)

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(f&amp;quot;\n{&amp;#39;=&amp;#39;*55}\n&amp;quot;)

if&amp;nbsp;__name__&amp;nbsp;==&amp;nbsp;&amp;#39;__main__&amp;#39;:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;len(sys.argv)&amp;nbsp;&amp;lt;&amp;nbsp;2:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(&amp;quot;用法:&amp;nbsp;python&amp;nbsp;analyze_bundle.py&amp;nbsp;stats.json&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sys.exit(1)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;analyze(sys.argv[1])&lt;/pre&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;使用方式&lt;/strong&gt;：&lt;/div&gt;&lt;pre class=&quot;ybc-pre-component ybc-pre-component_not-math&quot;&gt;#&amp;nbsp;1.&amp;nbsp;导出Webpack构建统计
npx&amp;nbsp;webpack&amp;nbsp;--config&amp;nbsp;webpack.config.prod.js&amp;nbsp;--profile&amp;nbsp;--json&amp;nbsp;&amp;gt;&amp;nbsp;stats.json

#&amp;nbsp;2.&amp;nbsp;运行分析
python&amp;nbsp;analyze_bundle.py&amp;nbsp;stats.json&lt;/pre&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;示例输出&lt;/strong&gt;：&lt;/div&gt;&lt;pre class=&quot;ybc-pre-component ybc-pre-component_not-math&quot;&gt;📦&amp;nbsp;Webpack&amp;nbsp;Bundle&amp;nbsp;分析报告:&amp;nbsp;stats.json
=======================================================

🔷&amp;nbsp;Top&amp;nbsp;20&amp;nbsp;最大产出文件：
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;1.23&amp;nbsp;MB&amp;nbsp;&amp;nbsp;vendor.js&amp;nbsp;&amp;nbsp;⚠️&amp;nbsp;&amp;nbsp;&amp;gt;500KB
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;345&amp;nbsp;KB&amp;nbsp;&amp;nbsp;ui-lib.js
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;89&amp;nbsp;KB&amp;nbsp;&amp;nbsp;app.js
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;...

🔷&amp;nbsp;node_modules&amp;nbsp;总占比:&amp;nbsp;82.3%&amp;nbsp;(1.67&amp;nbsp;MB&amp;nbsp;/&amp;nbsp;2.03&amp;nbsp;MB)
🔷&amp;nbsp;三方包&amp;nbsp;Top&amp;nbsp;10（按体积）：
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;890&amp;nbsp;KB&amp;nbsp;&amp;nbsp;moment
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;345&amp;nbsp;KB&amp;nbsp;&amp;nbsp;ant-design-vue
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;...
🔷&amp;nbsp;检查项：
&amp;nbsp;&amp;nbsp;⚠️&amp;nbsp;&amp;nbsp;发现&amp;nbsp;1&amp;nbsp;个&amp;nbsp;&amp;gt;1MB&amp;nbsp;JS文件，建议拆分：
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;-&amp;nbsp;vendor.js
&amp;nbsp;&amp;nbsp;⚠️&amp;nbsp;&amp;nbsp;node_modules&amp;nbsp;占比&amp;nbsp;&amp;gt;75%，考虑UI库单独拆chunk或按需引入&lt;/pre&gt;&lt;hr/&gt;&lt;h2&gt;四、 优化前后典型指标对比（1688同类项目实测）&lt;/h2&gt;&lt;div class=&quot;hyc-common-markdown__table-wrapper&quot; data-has-scroll=&quot;false&quot; style=&quot;font-size: 16px; border-collapse: separate; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;div style=&quot;font-size: 16px; border-collapse: separate; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;table&gt;&lt;thead style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;tr style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot; class=&quot;firstRow&quot;&gt;&lt;th style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;指标&lt;/div&gt;&lt;/th&gt;&lt;th style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;优化前&lt;/div&gt;&lt;/th&gt;&lt;th style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;优化后&lt;/div&gt;&lt;/th&gt;&lt;th style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;提升&lt;/div&gt;&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;tr style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;首屏JS体积&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;2.1 MB&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;520 KB（gzip 148KB）&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;↓75%&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;Dev冷启动编译&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;38s&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;9s（filesystem cache）&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;↑76%&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;Prod构建时间&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;72s&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;41s（thread-loader+Terser parallel）&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;↑43%&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;FCP（首屏内容绘制）&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;2.8s&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;0.9s&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;↑211%（≈300%感知）&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div class=&quot;ybc-p&quot;&gt;注：FCP提升主要来自&lt;strong&gt;分包+HTTP/2多路复用+gzip&lt;/strong&gt;，Webpack优化贡献核心在减小首屏包体。&lt;/div&gt;&lt;/blockquote&gt;&lt;hr/&gt;&lt;h2&gt;五、 进阶建议（1688级别）&lt;/h2&gt;&lt;ol class=&quot;ybc-ol-component ybc-ol-component_1 list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;CDN托管静态资源&lt;/strong&gt;：&lt;code class=&quot;hyc-common-markdown__code__inline&quot;&gt;output.publicPath = &amp;#39;https://cdn.xxx.com/assets/&amp;#39;&lt;/code&gt;，释放源站带宽。&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;Preload关键Chunk&lt;/strong&gt;：&lt;code class=&quot;hyc-common-markdown__code__inline&quot;&gt;&amp;lt;link rel=&amp;quot;preload&amp;quot; as=&amp;quot;script&amp;quot; href=&amp;quot;vendor.js&amp;quot;&amp;gt;&lt;/code&gt;提前拉取。&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;Tree Shaking验证&lt;/strong&gt;：确保 &lt;code class=&quot;hyc-common-markdown__code__inline&quot;&gt;sideEffects: false&lt;/code&gt;在package.json中声明，用分析脚本确认无用代码被摇树清除。&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;图片优化流水线&lt;/strong&gt;：Webpack中用 &lt;code class=&quot;hyc-common-markdown__code__inline&quot;&gt;image-webpack-loader&lt;/code&gt;压缩PNG/JPG/WEBP，1688商品图极多。&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;hr/&gt;&lt;h2&gt;💡 总结&lt;/h2&gt;&lt;div class=&quot;ybc-p&quot;&gt;Webpack优化不是堆配置，而是&lt;strong&gt;理解构建产物的生命周期&lt;/strong&gt;：&lt;/div&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;缓存 → 拆分 → 压缩 → 懒加载 → 持久化Hash缓存&lt;/strong&gt;。&lt;/div&gt;&lt;div class=&quot;ybc-p&quot;&gt;用上面Python脚本跑一遍你的 &lt;code class=&quot;hyc-common-markdown__code__inline&quot;&gt;stats.json&lt;/code&gt;，先找到真正的瓶颈再动手，比盲目加插件有效得多。&lt;/div&gt;&lt;div class=&quot;ybc-p&quot;&gt;需要我补充 &lt;strong&gt;Vite迁移对照版&lt;/strong&gt; 或 &lt;strong&gt;完整的webpack.config.js模板&lt;/strong&gt; 吗？&lt;/div&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;</description><pubDate>Sun, 31 May 2026 16:02:21 +0800</pubDate></item><item><title>揭秘双11：阿里云弹性计算如何应对流量洪峰？（附python源码）</title><link>https://alexob.com/?id=379</link><description>&lt;div class=&quot;ybc-p&quot;&gt;双11的流量洪峰不是靠“堆机器”硬扛的，而是靠&lt;strong&gt;弹性计算&lt;/strong&gt;的“潮汐能力”来消化的。阿里云的核心思路是：&lt;strong&gt;预测扩容 + 分层过滤 + 极速弹性&lt;/strong&gt;。下面我们拆解这套机制，并用 Python 模拟其核心逻辑。&lt;/div&gt;&lt;hr/&gt;&lt;h2&gt;一、 流量洪峰的“三层消化”模型&lt;/h2&gt;&lt;div class=&quot;ybc-p&quot;&gt;双11的流量不是直接砸向数据库的，而是经过一个精密的“漏斗”系统：&lt;/div&gt;&lt;pre class=&quot;ybc-pre-component ybc-pre-component_not-math&quot;&gt;graph&amp;nbsp;TD
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;A[1000万QPS&amp;nbsp;用户请求]&amp;nbsp;--&amp;gt;&amp;nbsp;B[SLB负载均衡]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;B&amp;nbsp;--&amp;gt;&amp;nbsp;C[弹性伸缩组&amp;nbsp;ESS]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;C&amp;nbsp;--&amp;gt;&amp;nbsp;D[缓存层&amp;nbsp;Redis]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;D&amp;nbsp;--&amp;gt;&amp;nbsp;E[消息队列&amp;nbsp;RocketMQ]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;E&amp;nbsp;--&amp;gt;&amp;nbsp;F[数据库&amp;nbsp;RDS]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;B&amp;nbsp;--&amp;gt;&amp;nbsp;G[静态资源&amp;nbsp;CDN]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;C&amp;nbsp;--&amp;gt;&amp;nbsp;H[健康检查&amp;nbsp;自动踢除]&lt;/pre&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;数据流向&lt;/strong&gt;：&lt;/div&gt;&lt;ol class=&quot;ybc-ol-component ybc-ol-component_1 list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;SLB层&lt;/strong&gt;：将流量均匀分发到后端服务器池，并做第一道4/7层清洗。&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;ESS层（弹性伸缩）&lt;/strong&gt;：根据CPU/内存压力，&lt;strong&gt;自动&lt;/strong&gt;增加或减少ECS实例数量。&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;缓存层&lt;/strong&gt;：90%的读请求在Redis层被拦截，不会到达后端。&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;MQ层&lt;/strong&gt;：写请求（如下单）进入消息队列“削峰填谷”，后端异步消费。&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;hr/&gt;&lt;h2&gt;二、 核心黑科技：神龙架构 + 极速弹性&lt;/h2&gt;&lt;div class=&quot;ybc-p&quot;&gt;阿里云之所以能应对58.3万笔/秒的订单峰值，靠的是底层&lt;strong&gt;神龙架构（X-Dragon）&lt;/strong&gt; 和&lt;strong&gt;容器化弹性&lt;/strong&gt;。&lt;/div&gt;&lt;h3&gt;1. 神龙架构：裸金属的性能，虚拟机的弹性&lt;/h3&gt;&lt;ul class=&quot;ybc-ul-component list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;痛点&lt;/strong&gt;：传统虚拟机（VM）有性能损耗（Hypervisor开销），物理机又缺乏弹性。&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;解法&lt;/strong&gt;：神龙架构通过自研的MOC卡（神龙芯片）将虚拟化层卸载到硬件，让ECS实例具备&lt;strong&gt;物理机100%的计算性能&lt;/strong&gt;，同时保留云主机的秒级创建能力。&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;2. 极速弹性：3分钟拉起50万核&lt;/h3&gt;&lt;div class=&quot;ybc-p&quot;&gt;双11的扩容不是临时抱佛脚，而是&lt;strong&gt;预测性扩容&lt;/strong&gt;。&lt;/div&gt;&lt;ul class=&quot;ybc-ul-component list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;预测模型&lt;/strong&gt;：基于历史数据和AI算法，预测零点峰值所需的资源量。&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;混合云兜底&lt;/strong&gt;：当自有资源不足时，自动调用公有云资源池（弹性容器实例ECI）进行补充。&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;容器化&lt;/strong&gt;：核心应用已容器化，扩容时直接拉起镜像，比创建完整VM更快。&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;hr/&gt;&lt;h2&gt;三、 Python模拟：实现一个简易的“弹性伸缩控制器”&lt;/h2&gt;&lt;div class=&quot;ybc-p&quot;&gt;虽然我们无法模拟阿里云底层的复杂调度，但可以用Python实现其&lt;strong&gt;控制面逻辑&lt;/strong&gt;：监控负载 -&amp;gt; 决策 -&amp;gt; 扩容/缩容。&lt;/div&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;场景&lt;/strong&gt;：模拟一个Web服务，当CPU负载超过70%时自动扩容，低于20%时自动缩容。&lt;/div&gt;&lt;pre class=&quot;ybc-pre-component ybc-pre-component_not-math&quot;&gt;import&amp;nbsp;random
import&amp;nbsp;time
import&amp;nbsp;threading
from&amp;nbsp;dataclasses&amp;nbsp;import&amp;nbsp;dataclass
from&amp;nbsp;typing&amp;nbsp;import&amp;nbsp;List
#&amp;nbsp;封装好API供应商demo&amp;nbsp;url=https://console.open.onebound.cn/console/?i=Lex
@dataclass
class&amp;nbsp;ECSInstance:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;模拟一个ECS实例&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;id:&amp;nbsp;str
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cpu_usage:&amp;nbsp;float&amp;nbsp;=&amp;nbsp;0.0
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;status:&amp;nbsp;str&amp;nbsp;=&amp;nbsp;&amp;quot;running&amp;quot;&amp;nbsp;&amp;nbsp;#&amp;nbsp;running,&amp;nbsp;pending,&amp;nbsp;stopped

class&amp;nbsp;ElasticScalingGroup:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;模拟弹性伸缩组（ESS）&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;__init__(self,&amp;nbsp;min_size=1,&amp;nbsp;max_size=10):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.min_size&amp;nbsp;=&amp;nbsp;min_size
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.max_size&amp;nbsp;=&amp;nbsp;max_size
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.instances:&amp;nbsp;List[ECSInstance]&amp;nbsp;=&amp;nbsp;[]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.running&amp;nbsp;=&amp;nbsp;True
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.lock&amp;nbsp;=&amp;nbsp;threading.Lock()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;初始化最小实例数
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;i&amp;nbsp;in&amp;nbsp;range(min_size):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.add_instance()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;add_instance(self):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;扩容：模拟创建一台新ECS（耗时操作）&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;with&amp;nbsp;self.lock:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;len(self.instances)&amp;nbsp;&amp;gt;=&amp;nbsp;self.max_size:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(&amp;quot;❌&amp;nbsp;已达最大实例数，扩容失败&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;False
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;模拟创建ECS的延迟（2-5秒）
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(&amp;quot;🟡&amp;nbsp;正在创建新ECS实例...&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;time.sleep(random.uniform(2,&amp;nbsp;5))
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;instance_id&amp;nbsp;=&amp;nbsp;f&amp;quot;i-{str(random.randint(10000,&amp;nbsp;99999))}&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;new_instance&amp;nbsp;=&amp;nbsp;ECSInstance(id=instance_id,&amp;nbsp;cpu_usage=10.0)&amp;nbsp;&amp;nbsp;#&amp;nbsp;新实例初始低负载
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.instances.append(new_instance)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(f&amp;quot;✅&amp;nbsp;实例&amp;nbsp;{instance_id}&amp;nbsp;创建成功，当前实例数:&amp;nbsp;{len(self.instances)}&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;True
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;remove_instance(self):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;缩容：随机移除一台ECS&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;with&amp;nbsp;self.lock:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;len(self.instances)&amp;nbsp;&amp;lt;=&amp;nbsp;self.min_size:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(&amp;quot;❌&amp;nbsp;已达最小实例数，无法缩容&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;False
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;随机选择一台实例销毁（生产环境应更智能，如选择最闲的）
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;instance&amp;nbsp;=&amp;nbsp;random.choice(self.instances)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.instances.remove(instance)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(f&amp;quot;🔻&amp;nbsp;实例&amp;nbsp;{instance.id}&amp;nbsp;已被移出，当前实例数:&amp;nbsp;{len(self.instances)}&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;True
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;get_avg_cpu_usage(self):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;获取伸缩组平均CPU使用率&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;not&amp;nbsp;self.instances:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;0
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;total&amp;nbsp;=&amp;nbsp;sum(inst.cpu_usage&amp;nbsp;for&amp;nbsp;inst&amp;nbsp;in&amp;nbsp;self.instances&amp;nbsp;if&amp;nbsp;inst.status&amp;nbsp;==&amp;nbsp;&amp;quot;running&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;total&amp;nbsp;/&amp;nbsp;len(self.instances)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;simulate_workload(self):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;模拟业务负载波动（后台线程）&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;while&amp;nbsp;self.running:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;time.sleep(3)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;with&amp;nbsp;self.lock:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;随机改变每个实例的CPU负载
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;instance&amp;nbsp;in&amp;nbsp;self.instances:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;模拟负载波动：-5%&amp;nbsp;到&amp;nbsp;+15%
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;change&amp;nbsp;=&amp;nbsp;random.uniform(-5,&amp;nbsp;15)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;instance.cpu_usage&amp;nbsp;=&amp;nbsp;max(0,&amp;nbsp;min(100,&amp;nbsp;instance.cpu_usage&amp;nbsp;+&amp;nbsp;change))

def&amp;nbsp;scaling_controller(scaling_group:&amp;nbsp;ElasticScalingGroup):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;弹性伸缩控制器（决策大脑）&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;while&amp;nbsp;scaling_group.running:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;time.sleep(10)&amp;nbsp;&amp;nbsp;#&amp;nbsp;每10秒检查一次（阿里云实际频率更高）
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;avg_cpu&amp;nbsp;=&amp;nbsp;scaling_group.get_avg_cpu_usage()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;current_size&amp;nbsp;=&amp;nbsp;len(scaling_group.instances)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(f&amp;quot;📊&amp;nbsp;当前状态:&amp;nbsp;实例数={current_size},&amp;nbsp;平均CPU={avg_cpu:.1f}%&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;规则1：CPU&amp;nbsp;&amp;gt;&amp;nbsp;70%&amp;nbsp;且&amp;nbsp;未达上限&amp;nbsp;-&amp;gt;&amp;nbsp;扩容
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;avg_cpu&amp;nbsp;&amp;gt;&amp;nbsp;70&amp;nbsp;and&amp;nbsp;current_size&amp;nbsp;&amp;lt;&amp;nbsp;scaling_group.max_size:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(&amp;quot;🚀&amp;nbsp;触发扩容规则&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;scaling_group.add_instance()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;规则2：CPU&amp;nbsp;&amp;lt;&amp;nbsp;20%&amp;nbsp;且&amp;nbsp;高于最小数&amp;nbsp;-&amp;gt;&amp;nbsp;缩容
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;elif&amp;nbsp;avg_cpu&amp;nbsp;&amp;lt;&amp;nbsp;20&amp;nbsp;and&amp;nbsp;current_size&amp;nbsp;&amp;gt;&amp;nbsp;scaling_group.min_size:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(&amp;quot;💤&amp;nbsp;触发缩容规则&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;scaling_group.remove_instance()

#&amp;nbsp;演示代码
if&amp;nbsp;__name__&amp;nbsp;==&amp;nbsp;&amp;quot;__main__&amp;quot;:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ess&amp;nbsp;=&amp;nbsp;ElasticScalingGroup(min_size=2,&amp;nbsp;max_size=5)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;封装好API供应商demo&amp;nbsp;url=https://console.open.onebound.cn/console/?i=Lex
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;启动负载模拟线程
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;workload_thread&amp;nbsp;=&amp;nbsp;threading.Thread(target=ess.simulate_workload,&amp;nbsp;daemon=True)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;workload_thread.start()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;启动伸缩控制器
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;controller_thread&amp;nbsp;=&amp;nbsp;threading.Thread(target=scaling_controller,&amp;nbsp;args=(ess,),&amp;nbsp;daemon=True)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;controller_thread.start()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;主线程等待演示
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(&amp;quot;🎬&amp;nbsp;弹性伸缩演示开始...（按&amp;nbsp;Ctrl+C&amp;nbsp;停止）&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;while&amp;nbsp;True:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;time.sleep(1)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;except&amp;nbsp;KeyboardInterrupt:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ess.running&amp;nbsp;=&amp;nbsp;False
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(&amp;quot;🛑&amp;nbsp;演示结束&amp;quot;)&lt;/pre&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;运行效果&lt;/strong&gt;：&lt;/div&gt;&lt;pre class=&quot;ybc-pre-component ybc-pre-component_not-math&quot;&gt;🎬&amp;nbsp;弹性伸缩演示开始...（按&amp;nbsp;Ctrl+C&amp;nbsp;停止）
📊&amp;nbsp;当前状态:&amp;nbsp;实例数=2,&amp;nbsp;平均CPU=25.5%
🟡&amp;nbsp;正在创建新ECS实例...
✅&amp;nbsp;实例&amp;nbsp;i-38274&amp;nbsp;创建成功，当前实例数:&amp;nbsp;3
📊&amp;nbsp;当前状态:&amp;nbsp;实例数=3,&amp;nbsp;平均CPU=78.2%
🚀&amp;nbsp;触发扩容规则
...&lt;/pre&gt;&lt;hr/&gt;&lt;h2&gt;四、 生产级架构的进阶策略&lt;/h2&gt;&lt;h3&gt;1. 混合云弹性（Hybrid Cloud）&lt;/h3&gt;&lt;div class=&quot;ybc-p&quot;&gt;阿里云在双11期间会采用&lt;strong&gt;混合云&lt;/strong&gt;策略。当自有数据中心资源不足时，自动将非核心业务或溢出流量调度到公有云ECS/ECI上。这需要一套复杂的&lt;strong&gt;资源调度器（Resource Orchestrator）&lt;/strong&gt;。&lt;/div&gt;&lt;h3&gt;2. 无损降级与混部&lt;/h3&gt;&lt;ul class=&quot;ybc-ul-component list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;混部技术&lt;/strong&gt;：将离线的计算任务（如大数据分析）与在线的交易服务混合部署在同一台物理机上。当双11流量高峰来临时，&lt;strong&gt;“杀掉”离线任务&lt;/strong&gt;，将资源瞬间释放给在线服务。&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;无损降级&lt;/strong&gt;：在极端压力下，自动关闭非核心功能（如商品评价、推荐列表），保证核心交易链路的通畅。&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;3. 多级缓存与CDN&lt;/h3&gt;&lt;div class=&quot;ybc-p&quot;&gt;除了Redis，阿里还会在&lt;strong&gt;CDN边缘节点&lt;/strong&gt;缓存静态资源（图片、JS、CSS）。双11当天，CDN的带宽消耗是天文数字，这层缓存挡住了绝大部分对源站的请求。&lt;/div&gt;&lt;hr/&gt;&lt;h2&gt;五、 避坑指南与总结&lt;/h2&gt;&lt;h3&gt;⚠️ 三大误区&lt;/h3&gt;&lt;ol class=&quot;ybc-ol-component ybc-ol-component_1 list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;只扩Web层&lt;/strong&gt;：如果数据库连接池没扩，Web层扩再多实例也会因为拿不到数据库连接而挂掉。必须&lt;strong&gt;全链路扩容&lt;/strong&gt;（Web -&amp;gt; 缓存 -&amp;gt; DB）。&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;忽略健康检查&lt;/strong&gt;：扩容出来的实例如果还没完成应用启动（如Spring Boot还在加载Bean），SLB就把流量打过来，会导致请求失败。必须配置&lt;strong&gt;就绪检查（Readiness Probe）&lt;/strong&gt;。&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;缩容太激进&lt;/strong&gt;：缩容时要采用&lt;strong&gt;渐进式策略&lt;/strong&gt;，先停止接收新流量（排水），等待存量请求处理完再销毁实例，否则会打断用户操作。&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;h3&gt;✅ 核心要点&lt;/h3&gt;&lt;div class=&quot;hyc-common-markdown__table-wrapper&quot; data-has-scroll=&quot;false&quot; style=&quot;font-size: 16px; border-collapse: separate; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;div style=&quot;font-size: 16px; border-collapse: separate; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;table&gt;&lt;thead style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;tr style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot; class=&quot;firstRow&quot;&gt;&lt;th style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;技术点&lt;/div&gt;&lt;/th&gt;&lt;th style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;解决的问题&lt;/div&gt;&lt;/th&gt;&lt;th style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;阿里云产品&lt;/div&gt;&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;tr style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;strong style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;神龙架构&lt;/strong&gt;&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;虚拟化性能损耗&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;ECS裸金属实例&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;strong style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;ESS弹性伸缩&lt;/strong&gt;&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;流量潮汐、成本控制&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;弹性伸缩ESS&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;strong style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;混合云&lt;/strong&gt;&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;资源池瓶颈&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;公有云 + 专有云&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;strong style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;分层过滤&lt;/strong&gt;&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;数据库被打爆&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;SLB + Redis + MQ&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;最后提醒&lt;/strong&gt;：本文的Python代码仅用于演示&lt;strong&gt;决策逻辑&lt;/strong&gt;。生产环境的弹性伸缩涉及镜像制作、安全组配置、负载均衡注册等复杂操作，请直接使用阿里云ESS服务，并配合ARMS监控进行调优。&lt;/div&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;</description><pubDate>Fri, 29 May 2026 09:47:03 +0800</pubDate></item><item><title>京东秒杀系统崩溃？三招Redis缓存策略带你扛住百万并发（附python源码）</title><link>https://alexob.com/?id=378</link><description>&lt;div class=&quot;ybc-p&quot;&gt;京东秒杀系统崩溃，本质是&lt;strong&gt;瞬时流量洪峰&lt;/strong&gt;击穿了数据库。要扛住百万并发，核心思路是：&lt;strong&gt;前端限流削峰、Redis内存预扣、后端异步落库&lt;/strong&gt;。下面用三招Redis核心策略 + Python源码，带你彻底解决高并发秒杀难题。&lt;/div&gt;&lt;hr/&gt;&lt;h2&gt;一、 秒杀崩溃的根源与架构总览&lt;/h2&gt;&lt;h3&gt;为什么传统架构会崩？&lt;/h3&gt;&lt;ul class=&quot;ybc-ul-component list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;数据库瓶颈&lt;/strong&gt;：瞬间百万QPS直接打满数据库连接池，导致服务雪崩。&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;超卖现象&lt;/strong&gt;：单纯的 &lt;code class=&quot;hyc-common-markdown__code__inline&quot;&gt;if stock &amp;gt; 0: stock -= 1&lt;/code&gt;在并发下会扣成负数。&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;库存热点&lt;/strong&gt;：单行数据（如 &lt;code class=&quot;hyc-common-markdown__code__inline&quot;&gt;product_id=666&lt;/code&gt;）成为热点，所有请求都在竞争同一把锁。&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;抗崩架构核心：分层过滤&lt;/h3&gt;&lt;div class=&quot;ybc-p&quot;&gt;京东/淘宝的秒杀架构，本质上是一个&lt;strong&gt;漏斗模型&lt;/strong&gt;，90%的无效请求在到达Redis前就被丢弃了。&lt;/div&gt;&lt;pre class=&quot;ybc-pre-component ybc-pre-component_not-math&quot;&gt;graph&amp;nbsp;TD
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;A[100万并发请求]&amp;nbsp;--&amp;gt;&amp;nbsp;B[网关层:&amp;nbsp;限流/风控]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;B&amp;nbsp;--&amp;gt;&amp;nbsp;C[秒杀服务:&amp;nbsp;Redis预扣库存]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;C&amp;nbsp;--&amp;gt;&amp;nbsp;D[消息队列:&amp;nbsp;削峰填谷]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;D&amp;nbsp;--&amp;gt;&amp;nbsp;E[数据库:&amp;nbsp;最终落库]&lt;/pre&gt;&lt;hr/&gt;&lt;h2&gt;二、 扛住百万并发的三招Redis策略&lt;/h2&gt;&lt;h3&gt;第一招：原子防超卖（Lua脚本）&lt;/h3&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;痛点&lt;/strong&gt;：&lt;code class=&quot;hyc-common-markdown__code__inline&quot;&gt;get&lt;/code&gt;和 &lt;code class=&quot;hyc-common-markdown__code__inline&quot;&gt;decr&lt;/code&gt;是两个操作，高并发下会超卖。&lt;/div&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;解法&lt;/strong&gt;：利用Redis单线程特性，将“查库存”和“扣库存”打包成一个&lt;strong&gt;原子操作&lt;/strong&gt;。&lt;/div&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;Python源码：Lua脚本防超卖&lt;/strong&gt;&lt;/div&gt;&lt;pre class=&quot;ybc-pre-component ybc-pre-component_not-math&quot;&gt;import&amp;nbsp;redis

#&amp;nbsp;连接Redis（生产环境用连接池）
redis_client&amp;nbsp;=&amp;nbsp;redis.Redis(host=&amp;#39;localhost&amp;#39;,&amp;nbsp;port=6379,&amp;nbsp;db=0,&amp;nbsp;decode_responses=True)
#&amp;nbsp;封装好API供应商demo&amp;nbsp;url=https://console.open.onebound.cn/console/?i=Lex
#&amp;nbsp;初始化库存（秒杀开始前执行）
redis_client.set(&amp;quot;seckill:stock:1001&amp;quot;,&amp;nbsp;1000)

#&amp;nbsp;定义Lua脚本（核心：判断+扣减在Redis端原子执行）
SECKILL_SCRIPT&amp;nbsp;=&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;
local&amp;nbsp;stock_key&amp;nbsp;=&amp;nbsp;KEYS[1]
local&amp;nbsp;stock&amp;nbsp;=&amp;nbsp;tonumber(redis.call(&amp;#39;GET&amp;#39;,&amp;nbsp;stock_key))
if&amp;nbsp;stock&amp;nbsp;and&amp;nbsp;stock&amp;nbsp;&amp;gt;&amp;nbsp;0&amp;nbsp;then
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;redis.call(&amp;#39;DECR&amp;#39;,&amp;nbsp;stock_key)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;1&amp;nbsp;--&amp;nbsp;成功
else
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;0&amp;nbsp;--&amp;nbsp;失败
end
&amp;quot;&amp;quot;&amp;quot;
seckill_script&amp;nbsp;=&amp;nbsp;redis_client.register_script(SECKILL_SCRIPT)
#&amp;nbsp;封装好API供应商demo&amp;nbsp;url=https://console.open.onebound.cn/console/?i=Lex
def&amp;nbsp;handle_seckill(user_id,&amp;nbsp;product_id):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;处理秒杀请求（核心逻辑）&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;stock_key&amp;nbsp;=&amp;nbsp;f&amp;quot;seckill:stock:{product_id}&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;执行Lua脚本（原子操作）
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;result&amp;nbsp;=&amp;nbsp;seckill_script(keys=[stock_key])
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;result&amp;nbsp;==&amp;nbsp;1:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;秒杀成功，发送消息到MQ，异步创建订单
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;send_to_mq(user_id,&amp;nbsp;product_id)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;{&amp;quot;code&amp;quot;:&amp;nbsp;200,&amp;nbsp;&amp;quot;msg&amp;quot;:&amp;nbsp;&amp;quot;抢购成功&amp;quot;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;{&amp;quot;code&amp;quot;:&amp;nbsp;400,&amp;nbsp;&amp;quot;msg&amp;quot;:&amp;nbsp;&amp;quot;已售罄&amp;quot;}&lt;/pre&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;关键点&lt;/strong&gt;：Lua脚本在Redis服务器端一次性执行，不会被其他请求打断，彻底解决超卖。&lt;/div&gt;&lt;h3&gt;第二招：库存分片（解决热点Key）&lt;/h3&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;痛点&lt;/strong&gt;：所有请求都打向 &lt;code class=&quot;hyc-common-markdown__code__inline&quot;&gt;seckill:stock:1001&lt;/code&gt;这一个Key，单分片CPU扛不住。&lt;/div&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;解法&lt;/strong&gt;：借鉴京东架构，将库存&lt;strong&gt;分片&lt;/strong&gt;到多个Key中，分散压力。&lt;/div&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;Python源码：库存分片路由&lt;/strong&gt;&lt;/div&gt;&lt;pre class=&quot;ybc-pre-component ybc-pre-component_not-math&quot;&gt;def&amp;nbsp;get_shard_key(product_id,&amp;nbsp;user_id,&amp;nbsp;shard_count=10):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;根据用户ID哈希取模，路由到不同的库存分片&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;shard_index&amp;nbsp;=&amp;nbsp;hash(user_id)&amp;nbsp;%&amp;nbsp;shard_count
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;f&amp;quot;seckill:stock:{product_id}:shard_{shard_index}&amp;quot;

def&amp;nbsp;init_shard_stock(product_id,&amp;nbsp;total_stock,&amp;nbsp;shard_count=10):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;初始化分片库存（总库存1000，分10片，每片100）&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;base_stock&amp;nbsp;=&amp;nbsp;total_stock&amp;nbsp;//&amp;nbsp;shard_count
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;i&amp;nbsp;in&amp;nbsp;range(shard_count):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;key&amp;nbsp;=&amp;nbsp;f&amp;quot;seckill:stock:{product_id}:shard_{i}&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;redis_client.set(key,&amp;nbsp;base_stock)

def&amp;nbsp;sharded_seckill(user_id,&amp;nbsp;product_id):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;分片秒杀逻辑&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;shard_key&amp;nbsp;=&amp;nbsp;get_shard_key(product_id,&amp;nbsp;user_id)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;使用同样的Lua脚本，但操作的是分片Key
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;result&amp;nbsp;=&amp;nbsp;seckill_script(keys=[shard_key])
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;result&amp;nbsp;==&amp;nbsp;1:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;{&amp;quot;code&amp;quot;:&amp;nbsp;200,&amp;nbsp;&amp;quot;msg&amp;quot;:&amp;nbsp;&amp;quot;抢购成功&amp;quot;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;该分片没了，可以尝试其他分片或直接返回售罄
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;{&amp;quot;code&amp;quot;:&amp;nbsp;400,&amp;nbsp;&amp;quot;msg&amp;quot;:&amp;nbsp;&amp;quot;已售罄&amp;quot;}&lt;/pre&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;关键点&lt;/strong&gt;：通过 &lt;code class=&quot;hyc-common-markdown__code__inline&quot;&gt;user_id&lt;/code&gt;哈希路由，将100万QPS的流量分散到10个Redis Key上，性能提升10倍。&lt;/div&gt;&lt;h3&gt;第三招：令牌桶限流（保护Redis）&lt;/h3&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;痛点&lt;/strong&gt;：Redis虽然快，但百万并发依然可能打满网络带宽。&lt;/div&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;解法&lt;/strong&gt;：在网关层或应用层使用&lt;strong&gt;令牌桶算法&lt;/strong&gt;，只放行系统能处理的请求量，多余的直接返回“排队中”。&lt;/div&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;Python源码：Redis实现令牌桶限流&lt;/strong&gt;&lt;/div&gt;&lt;pre class=&quot;ybc-pre-component ybc-pre-component_not-math&quot;&gt;import&amp;nbsp;time

def&amp;nbsp;token_bucket_limiter(user_id,&amp;nbsp;max_requests=100,&amp;nbsp;refill_rate=10):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;令牌桶限流（Redis实现）&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;key&amp;nbsp;=&amp;nbsp;f&amp;quot;rate_limit:{user_id}&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;now&amp;nbsp;=&amp;nbsp;time.time()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;使用Pipeline减少网络往返
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pipe&amp;nbsp;=&amp;nbsp;redis_client.pipeline()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pipe.hgetall(key)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pipe.hset(key,&amp;nbsp;&amp;#39;last_time&amp;#39;,&amp;nbsp;now)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pipe.expire(key,&amp;nbsp;60)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;data,&amp;nbsp;_,&amp;nbsp;_&amp;nbsp;=&amp;nbsp;pipe.execute()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;not&amp;nbsp;data:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;第一次请求，初始化
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;tokens&amp;nbsp;=&amp;nbsp;max_requests&amp;nbsp;-&amp;nbsp;1
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;redis_client.hset(key,&amp;nbsp;&amp;#39;tokens&amp;#39;,&amp;nbsp;tokens)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;True
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;last_time&amp;nbsp;=&amp;nbsp;float(data.get(&amp;#39;last_time&amp;#39;,&amp;nbsp;now))
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;tokens&amp;nbsp;=&amp;nbsp;float(data.get(&amp;#39;tokens&amp;#39;,&amp;nbsp;max_requests))
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;计算这段时间应该补充的令牌
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;elapsed&amp;nbsp;=&amp;nbsp;now&amp;nbsp;-&amp;nbsp;last_time
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;tokens&amp;nbsp;=&amp;nbsp;min(max_requests,&amp;nbsp;tokens&amp;nbsp;+&amp;nbsp;elapsed&amp;nbsp;*&amp;nbsp;refill_rate)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;tokens&amp;nbsp;&amp;gt;=&amp;nbsp;1:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;tokens&amp;nbsp;-=&amp;nbsp;1
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;redis_client.hset(key,&amp;nbsp;&amp;#39;tokens&amp;#39;,&amp;nbsp;tokens)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;True&amp;nbsp;&amp;nbsp;#&amp;nbsp;放行
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;False&amp;nbsp;&amp;nbsp;#&amp;nbsp;限流

#&amp;nbsp;在秒杀入口添加限流
def&amp;nbsp;seckill_entry(user_id,&amp;nbsp;product_id):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;not&amp;nbsp;token_bucket_limiter(user_id):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;{&amp;quot;code&amp;quot;:&amp;nbsp;429,&amp;nbsp;&amp;quot;msg&amp;quot;:&amp;nbsp;&amp;quot;手速太快，请稍后再试&amp;quot;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;handle_seckill(user_id,&amp;nbsp;product_id)&lt;/pre&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;关键点&lt;/strong&gt;：在请求到达Lua脚本前，通过令牌桶过滤掉80%的无效请求，保护Redis不被冲垮。&lt;/div&gt;&lt;hr/&gt;&lt;h2&gt;三、 完整秒杀流程与压测建议&lt;/h2&gt;&lt;h3&gt;1. 完整秒杀时序图&lt;/h3&gt;&lt;pre class=&quot;ybc-pre-component ybc-pre-component_not-math&quot;&gt;sequenceDiagram
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;participant&amp;nbsp;U&amp;nbsp;as&amp;nbsp;用户
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;participant&amp;nbsp;G&amp;nbsp;as&amp;nbsp;网关(限流)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;participant&amp;nbsp;A&amp;nbsp;as&amp;nbsp;秒杀服务(Python)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;participant&amp;nbsp;R&amp;nbsp;as&amp;nbsp;Redis(Lua)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;participant&amp;nbsp;M&amp;nbsp;as&amp;nbsp;消息队列
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;participant&amp;nbsp;D&amp;nbsp;as&amp;nbsp;数据库

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;U-&amp;gt;&amp;gt;G:&amp;nbsp;点击秒杀
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;G-&amp;gt;&amp;gt;A:&amp;nbsp;放行(令牌桶)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;A-&amp;gt;&amp;gt;R:&amp;nbsp;执行Lua脚本(原子扣减)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;R-&amp;gt;&amp;gt;A:&amp;nbsp;成功/失败
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;A-&amp;gt;&amp;gt;M:&amp;nbsp;发送成功消息(异步)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;A-&amp;gt;&amp;gt;U:&amp;nbsp;返回“抢购成功”
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;M-&amp;gt;&amp;gt;D:&amp;nbsp;消费消息，创建订单&lt;/pre&gt;&lt;h3&gt;2. 压测与部署建议&lt;/h3&gt;&lt;ul class=&quot;ybc-ul-component list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;压测工具&lt;/strong&gt;：使用 &lt;code class=&quot;hyc-common-markdown__code__inline&quot;&gt;locust&lt;/code&gt;或 &lt;code class=&quot;hyc-common-markdown__code__inline&quot;&gt;wrk&lt;/code&gt;模拟百万并发。&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;Redis配置&lt;/strong&gt;：必须开启&lt;strong&gt;持久化&lt;/strong&gt;（AOF），防止重启丢数据。&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;连接池&lt;/strong&gt;：Python端务必使用 &lt;code class=&quot;hyc-common-markdown__code__inline&quot;&gt;redis.ConnectionPool&lt;/code&gt;，避免频繁创建连接。&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;监控&lt;/strong&gt;：实时监控Redis的 &lt;code class=&quot;hyc-common-markdown__code__inline&quot;&gt;QPS&lt;/code&gt;和 &lt;code class=&quot;hyc-common-markdown__code__inline&quot;&gt;内存&lt;/code&gt;，设置库存告警。&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;hr/&gt;&lt;h2&gt;四、 避坑指南与总结&lt;/h2&gt;&lt;h3&gt;⚠️ 三大坑点&lt;/h3&gt;&lt;ol class=&quot;ybc-ol-component ybc-ol-component_1 list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;不要用事务&lt;/strong&gt;：Redis事务（MULTI）不是原子回滚，高并发下性能差，必须用Lua。&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;不要先查后写&lt;/strong&gt;：任何“先查数据库再更新”的逻辑都会超卖。&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;不要忘记预热&lt;/strong&gt;：秒杀开始前，必须把库存加载到Redis，不能临时查DB。&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;h3&gt;✅ 三招总结&lt;/h3&gt;&lt;div class=&quot;hyc-common-markdown__table-wrapper&quot; data-has-scroll=&quot;false&quot; style=&quot;font-size: 16px; border-collapse: separate; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;div style=&quot;font-size: 16px; border-collapse: separate; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;table&gt;&lt;thead style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;tr style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot; class=&quot;firstRow&quot;&gt;&lt;th style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;策略&lt;/div&gt;&lt;/th&gt;&lt;th style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;解决的问题&lt;/div&gt;&lt;/th&gt;&lt;th style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;核心工具&lt;/div&gt;&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;tr style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;strong style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;Lua原子脚本&lt;/strong&gt;&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;防超卖、数据一致性&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;Redis单线程&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;strong style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;库存分片&lt;/strong&gt;&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;热点Key性能瓶颈&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;哈希路由&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;strong style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;令牌桶限流&lt;/strong&gt;&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;流量洪峰、保护Redis&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;令牌桶算法&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;最后提醒&lt;/strong&gt;：本文代码仅供学习架构思想。生产环境请务必加入&lt;strong&gt;风控防刷&lt;/strong&gt;（如人机验证）、&lt;strong&gt;熔断降级&lt;/strong&gt;等机制，并确保Redis集群高可用。&lt;/div&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;</description><pubDate>Fri, 29 May 2026 09:26:11 +0800</pubDate></item><item><title>《【源码剖析】我是如何“看懂”淘宝反爬机制的（仅限学习交流）》(附python源码）</title><link>https://alexob.com/?id=377</link><description>&lt;div class=&quot;ybc-p&quot;&gt;淘宝的反爬机制本质上是一套&lt;strong&gt;“行为风控系统”&lt;/strong&gt;，它不关心你是不是“人”，只关心你的行为像不像一个“正常用户”。所谓的“看懂”，其实就是通过逆向工程，还原这套风控系统的检测逻辑。&lt;/div&gt;&lt;div class=&quot;ybc-p&quot;&gt;本文将深度剖析淘宝反爬的&lt;strong&gt;六大核心防线&lt;/strong&gt;，并附上 Python 源码，演示如何通过“伪装”来绕过检测。&lt;/div&gt;&lt;hr/&gt;&lt;h2&gt;一、 淘宝反爬机制“六层防线”深度解析&lt;/h2&gt;&lt;div class=&quot;ybc-p&quot;&gt;淘宝的风控不是单一维度的，而是一个立体的防御体系。你遇到的“滑块验证”或“IP封禁”，通常是触发了其中某一层的阈值。&lt;/div&gt;&lt;div class=&quot;hyc-common-markdown__table-wrapper&quot; data-has-scroll=&quot;false&quot; style=&quot;font-size: 16px; border-collapse: separate; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;div style=&quot;font-size: 16px; border-collapse: separate; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;table&gt;&lt;thead style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;tr style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot; class=&quot;firstRow&quot;&gt;&lt;th style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;防线层级&lt;/div&gt;&lt;/th&gt;&lt;th style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;检测维度&lt;/div&gt;&lt;/th&gt;&lt;th style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;触发后果&lt;/div&gt;&lt;/th&gt;&lt;th style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;破解思路&lt;/div&gt;&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;tr style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;strong style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;L1: 请求特征&lt;/strong&gt;&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;UA缺失、无Referer、无Cookie&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;直接 403&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;完整伪造请求头&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;strong style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;L2: 频率控制&lt;/strong&gt;&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;IP/账号 QPS 过高&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;滑块验证、IP限流&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;代理IP池、随机延时&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;strong style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;L3: 环境指纹&lt;/strong&gt;&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;WebDriver特征、Canvas指纹&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;强制滑块/验证码&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;修改CDP协议、无头浏览器伪装&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;strong style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;L4: 行为轨迹&lt;/strong&gt;&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;鼠标轨迹、点击间隔、页面停留&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;账号风控&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;模拟人类随机行为&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;strong style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;L5: 参数加密&lt;/strong&gt;&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;code class=&quot;hyc-common-markdown__code__inline&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 2px 4px;&quot;&gt;_tb_token&lt;/code&gt;、&lt;code class=&quot;hyc-common-markdown__code__inline&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 2px 4px;&quot;&gt;sign&lt;/code&gt;动态参数&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;接口返回空数据&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;JS逆向/执行&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;strong style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;L6: 数据混淆&lt;/strong&gt;&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;字体反爬、JSON乱序&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;数据解析失败&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;字体映射、动态解析&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;/div&gt;&lt;hr/&gt;&lt;h2&gt;二、 核心防线突破实战（附Python源码）&lt;/h2&gt;&lt;h3&gt;防线1：请求特征与频率控制&lt;/h3&gt;&lt;div class=&quot;ybc-p&quot;&gt;淘宝会严格校验请求头的完整性和IP请求频率。直接使用 &lt;code class=&quot;hyc-common-markdown__code__inline&quot;&gt;requests.get()&lt;/code&gt;不带任何头信息，几乎100%被拦截。&lt;/div&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;源码：模拟真实浏览器请求头&lt;/strong&gt;&lt;/div&gt;&lt;pre class=&quot;ybc-pre-component ybc-pre-component_not-math&quot;&gt;import&amp;nbsp;requests
import&amp;nbsp;time
import&amp;nbsp;random

def&amp;nbsp;get_taobao_page(url):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;模拟真实浏览器访问淘宝页面&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;headers&amp;nbsp;=&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;authority&amp;#39;:&amp;nbsp;&amp;#39;www.taobao.com&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;accept&amp;#39;:&amp;nbsp;&amp;#39;text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;accept-language&amp;#39;:&amp;nbsp;&amp;#39;zh-CN,zh;q=0.9,en;q=0.8&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;cache-control&amp;#39;:&amp;nbsp;&amp;#39;no-cache&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;pragma&amp;#39;:&amp;nbsp;&amp;#39;no-cache&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;sec-ch-ua&amp;#39;:&amp;nbsp;&amp;#39;&amp;quot;Not/A)Brand&amp;quot;;v=&amp;quot;99&amp;quot;,&amp;nbsp;&amp;quot;Google&amp;nbsp;Chrome&amp;quot;;v=&amp;quot;115&amp;quot;,&amp;nbsp;&amp;quot;Chromium&amp;quot;;v=&amp;quot;115&amp;quot;&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;sec-ch-ua-mobile&amp;#39;:&amp;nbsp;&amp;#39;?0&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;sec-ch-ua-platform&amp;#39;:&amp;nbsp;&amp;#39;&amp;quot;Windows&amp;quot;&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;sec-fetch-dest&amp;#39;:&amp;nbsp;&amp;#39;document&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;sec-fetch-mode&amp;#39;:&amp;nbsp;&amp;#39;navigate&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;sec-fetch-site&amp;#39;:&amp;nbsp;&amp;#39;none&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;sec-fetch-user&amp;#39;:&amp;nbsp;&amp;#39;?1&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;upgrade-insecure-requests&amp;#39;:&amp;nbsp;&amp;#39;1&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;user-agent&amp;#39;:&amp;nbsp;&amp;#39;Mozilla/5.0&amp;nbsp;(Windows&amp;nbsp;NT&amp;nbsp;10.0;&amp;nbsp;Win64;&amp;nbsp;x64)&amp;nbsp;AppleWebKit/537.36&amp;nbsp;(KHTML,&amp;nbsp;like&amp;nbsp;Gecko)&amp;nbsp;Chrome/115.0.0.0&amp;nbsp;Safari/537.36&amp;#39;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;关键：必须携带Cookie（即使是空的）
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cookies&amp;nbsp;=&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;cookie2&amp;#39;:&amp;nbsp;&amp;#39;your_cookie2_value&amp;#39;,&amp;nbsp;&amp;nbsp;#&amp;nbsp;淘宝关键Cookie
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;_tb_token_&amp;#39;:&amp;nbsp;&amp;#39;your_tb_token&amp;#39;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;随机延时，避免固定频率
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;time.sleep(random.uniform(1,&amp;nbsp;3))
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;封装好API供应商demo&amp;nbsp;url=https://console.open.onebound.cn/console/?i=Lex
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;response&amp;nbsp;=&amp;nbsp;requests.get(url,&amp;nbsp;headers=headers,&amp;nbsp;cookies=cookies,&amp;nbsp;timeout=10)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;&amp;#39;验证码&amp;#39;&amp;nbsp;in&amp;nbsp;response.text&amp;nbsp;or&amp;nbsp;&amp;#39;滑块&amp;#39;&amp;nbsp;in&amp;nbsp;response.text:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(&amp;quot;⚠️&amp;nbsp;触发风控：需要验证码&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;None
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;response.text
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;except&amp;nbsp;Exception&amp;nbsp;as&amp;nbsp;e:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(f&amp;quot;❌&amp;nbsp;请求失败:&amp;nbsp;{e}&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;None

#&amp;nbsp;测试
if&amp;nbsp;__name__&amp;nbsp;==&amp;nbsp;&amp;quot;__main__&amp;quot;:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;url&amp;nbsp;=&amp;nbsp;&amp;quot;https://item.taobao.com/item.htm?id=674904123402&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;html&amp;nbsp;=&amp;nbsp;get_taobao_page(url)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;html:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(&amp;quot;✅&amp;nbsp;页面获取成功&amp;quot;)&lt;/pre&gt;&lt;h3&gt;防线2：环境指纹检测（Selenium/WebDriver）&lt;/h3&gt;&lt;div class=&quot;ybc-p&quot;&gt;淘宝能精准识别 &lt;code class=&quot;hyc-common-markdown__code__inline&quot;&gt;Selenium&lt;/code&gt;驱动的浏览器，核心在于检测 &lt;code class=&quot;hyc-common-markdown__code__inline&quot;&gt;navigator.webdriver&lt;/code&gt;属性。普通浏览器该属性为 &lt;code class=&quot;hyc-common-markdown__code__inline&quot;&gt;undefined&lt;/code&gt;，而 Selenium 驱动下为 &lt;code class=&quot;hyc-common-markdown__code__inline&quot;&gt;true&lt;/code&gt;。&lt;/div&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;源码：绕过 WebDriver 检测&lt;/strong&gt;&lt;/div&gt;&lt;pre class=&quot;ybc-pre-component ybc-pre-component_not-math&quot;&gt;from&amp;nbsp;selenium&amp;nbsp;import&amp;nbsp;webdriver
from&amp;nbsp;selenium.webdriver.chrome.options&amp;nbsp;import&amp;nbsp;Options
from&amp;nbsp;selenium.webdriver.common.by&amp;nbsp;import&amp;nbsp;By
import&amp;nbsp;time
#&amp;nbsp;封装好API供应商demo&amp;nbsp;url=https://console.open.onebound.cn/console/?i=Lex
def&amp;nbsp;create_undetected_driver():
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;创建一个被淘宝识别为‘真实浏览器’的驱动&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;options&amp;nbsp;=&amp;nbsp;Options()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;关键配置：去除自动化特征
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;options.add_argument(&amp;#39;--disable-blink-features=AutomationControlled&amp;#39;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;options.add_experimental_option(&amp;quot;excludeSwitches&amp;quot;,&amp;nbsp;[&amp;quot;enable-automation&amp;quot;])
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;options.add_experimental_option(&amp;#39;useAutomationExtension&amp;#39;,&amp;nbsp;False)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;无头模式可选（但更容易被识别）
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;options.add_argument(&amp;#39;--headless&amp;#39;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;driver&amp;nbsp;=&amp;nbsp;webdriver.Chrome(options=options)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;执行CDP命令，覆盖&amp;nbsp;webdriver&amp;nbsp;属性
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;driver.execute_cdp_cmd(&amp;#39;Page.addScriptToEvaluateOnNewDocument&amp;#39;,&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;source&amp;#39;:&amp;nbsp;&amp;#39;&amp;#39;&amp;#39;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Object.defineProperty(navigator,&amp;nbsp;&amp;#39;webdriver&amp;#39;,&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;get:&amp;nbsp;()&amp;nbsp;=&amp;gt;&amp;nbsp;undefined
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;})
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;&amp;#39;&amp;#39;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;})
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;driver

def&amp;nbsp;taobao_login_with_selenium(username,&amp;nbsp;password):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;模拟登录（仅供学习，实际登录建议扫码）&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;driver&amp;nbsp;=&amp;nbsp;create_undetected_driver()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;driver.get(&amp;quot;https://login.taobao.com&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;输入账号密码（注意：极大概率会触发滑块）
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;driver.find_element(By.ID,&amp;nbsp;&amp;quot;fm-login-id&amp;quot;).send_keys(username)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;driver.find_element(By.ID,&amp;nbsp;&amp;quot;fm-login-password&amp;quot;).send_keys(password)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;这里需要处理滑块验证码（见下文）
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;handle_slider(driver)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;time.sleep(5)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;driver.quit()

#&amp;nbsp;注意：直接账号密码登录极易风控，建议使用手机扫码登录方式&lt;/pre&gt;&lt;h3&gt;防线3：参数加密（Sign &amp;amp; Token）&lt;/h3&gt;&lt;div class=&quot;ybc-p&quot;&gt;淘宝的 Ajax 接口（如搜索、详情）必须携带动态生成的 &lt;code class=&quot;hyc-common-markdown__code__inline&quot;&gt;_tb_token_&lt;/code&gt;和 &lt;code class=&quot;hyc-common-markdown__code__inline&quot;&gt;sign&lt;/code&gt;参数。这些参数通常由前端 JS 根据时间戳、Cookie、页面参数等计算得出。&lt;/div&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;源码：JS逆向执行获取Sign（概念演示）&lt;/strong&gt;&lt;/div&gt;&lt;pre class=&quot;ybc-pre-component ybc-pre-component_not-math&quot;&gt;import&amp;nbsp;execjs
import&amp;nbsp;requests

def&amp;nbsp;get_encrypted_params(keyword):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;通过执行JS代码生成加密参数（简化版）&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;读取本地保存的淘宝加密JS文件（需提前从网页源码中提取）
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;with&amp;nbsp;open(&amp;#39;taobao_sign.js&amp;#39;,&amp;nbsp;&amp;#39;r&amp;#39;,&amp;nbsp;encoding=&amp;#39;utf-8&amp;#39;)&amp;nbsp;as&amp;nbsp;f:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;js_code&amp;nbsp;=&amp;nbsp;f.read()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;创建JS执行环境
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ctx&amp;nbsp;=&amp;nbsp;execjs.compile(js_code)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;调用JS函数生成sign（函数名需根据逆向结果确定）
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sign&amp;nbsp;=&amp;nbsp;ctx.call(&amp;#39;generateSign&amp;#39;,&amp;nbsp;keyword)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;params&amp;nbsp;=&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;q&amp;#39;:&amp;nbsp;keyword,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;s&amp;#39;:&amp;nbsp;&amp;#39;0&amp;#39;,&amp;nbsp;&amp;nbsp;#&amp;nbsp;页码
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;sign&amp;#39;:&amp;nbsp;sign,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;_tb_token_&amp;#39;:&amp;nbsp;&amp;#39;xxxx&amp;#39;&amp;nbsp;&amp;nbsp;#&amp;nbsp;从Cookie中获取
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;params

def&amp;nbsp;search_taobao(keyword):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;搜索商品（需携带加密参数）&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;url&amp;nbsp;=&amp;nbsp;&amp;quot;https://s.taobao.com/search&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;params&amp;nbsp;=&amp;nbsp;get_encrypted_params(keyword)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;response&amp;nbsp;=&amp;nbsp;requests.get(url,&amp;nbsp;params=params,&amp;nbsp;headers=get_headers())
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;response.json()

#&amp;nbsp;难点：taobao_sign.js&amp;nbsp;需要你从淘宝网页源码中逆向提取并简化&lt;/pre&gt;&lt;h3&gt;防线4：行为轨迹模拟&lt;/h3&gt;&lt;div class=&quot;ybc-p&quot;&gt;淘宝会记录你的鼠标移动轨迹和点击行为。直线移动、匀速滑动、瞬间点击等“机器行为”会被识别。&lt;/div&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;源码：模拟人类滑动轨迹（用于通过滑块）&lt;/strong&gt;&lt;/div&gt;&lt;pre class=&quot;ybc-pre-component ybc-pre-component_not-math&quot;&gt;import&amp;nbsp;random
from&amp;nbsp;selenium.webdriver.common.action_chains&amp;nbsp;import&amp;nbsp;ActionChains
#&amp;nbsp;封装好API供应商demo&amp;nbsp;url=https://console.open.onebound.cn/console/?i=Lex
def&amp;nbsp;generate_tracks(distance):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;生成先加速后减速的滑动轨迹&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;tracks&amp;nbsp;=&amp;nbsp;[]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;current&amp;nbsp;=&amp;nbsp;0
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;mid&amp;nbsp;=&amp;nbsp;distance&amp;nbsp;*&amp;nbsp;3&amp;nbsp;/&amp;nbsp;4&amp;nbsp;&amp;nbsp;#&amp;nbsp;加速段占3/4
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;t&amp;nbsp;=&amp;nbsp;0.2
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;v&amp;nbsp;=&amp;nbsp;0
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;while&amp;nbsp;current&amp;nbsp;&amp;lt;&amp;nbsp;distance:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;current&amp;nbsp;&amp;lt;&amp;nbsp;mid:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;a&amp;nbsp;=&amp;nbsp;random.uniform(2,&amp;nbsp;5)&amp;nbsp;&amp;nbsp;#&amp;nbsp;加速
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;a&amp;nbsp;=&amp;nbsp;-random.uniform(1.5,&amp;nbsp;3)&amp;nbsp;&amp;nbsp;#&amp;nbsp;减速
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;v0&amp;nbsp;=&amp;nbsp;v
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;v&amp;nbsp;=&amp;nbsp;v0&amp;nbsp;+&amp;nbsp;a&amp;nbsp;*&amp;nbsp;t
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;move&amp;nbsp;=&amp;nbsp;v0&amp;nbsp;*&amp;nbsp;t&amp;nbsp;+&amp;nbsp;0.5&amp;nbsp;*&amp;nbsp;a&amp;nbsp;*&amp;nbsp;t&amp;nbsp;*&amp;nbsp;t
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;current&amp;nbsp;+=&amp;nbsp;move
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;tracks.append(round(move))
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;最后微调，模拟人手抖动
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;tracks.extend([-1,&amp;nbsp;0,&amp;nbsp;1]&amp;nbsp;*&amp;nbsp;random.randint(2,&amp;nbsp;5))
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;tracks

def&amp;nbsp;drag_slider(driver,&amp;nbsp;slider,&amp;nbsp;distance):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;拖动滑块&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ActionChains(driver).click_and_hold(slider).perform()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;tracks&amp;nbsp;=&amp;nbsp;generate_tracks(distance)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;x&amp;nbsp;in&amp;nbsp;tracks:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ActionChains(driver).move_by_offset(xoffset=x,&amp;nbsp;yoffset=random.randint(-2,&amp;nbsp;2)).perform()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;time.sleep(random.uniform(0.1,&amp;nbsp;0.3))
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ActionChains(driver).release().perform()&lt;/pre&gt;&lt;hr/&gt;&lt;h2&gt;三、 综合实战：构建抗风控爬虫架构&lt;/h2&gt;&lt;div class=&quot;ybc-p&quot;&gt;一个能“看懂”淘宝反爬的爬虫，应该具备以下架构：&lt;/div&gt;&lt;pre class=&quot;ybc-pre-component ybc-pre-component_not-math&quot;&gt;graph&amp;nbsp;TD
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;A[请求入口]&amp;nbsp;--&amp;gt;&amp;nbsp;B{有Cookie?}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;B&amp;nbsp;--&amp;gt;|无|&amp;nbsp;C[使用Playwright获取新Cookie]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;B&amp;nbsp;--&amp;gt;|有|&amp;nbsp;D[携带Cookie请求]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;C&amp;nbsp;--&amp;gt;&amp;nbsp;E[模拟人类浏览行为]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;E&amp;nbsp;--&amp;gt;&amp;nbsp;F[获取有效Cookie]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;F&amp;nbsp;--&amp;gt;&amp;nbsp;D
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;D&amp;nbsp;--&amp;gt;&amp;nbsp;G{返回状态}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;G&amp;nbsp;--&amp;gt;|200|&amp;nbsp;H[解析数据]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;G&amp;nbsp;--&amp;gt;|403/滑块|&amp;nbsp;I[触发降级策略]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;I&amp;nbsp;--&amp;gt;&amp;nbsp;J[更换IP/清Cookie]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;J&amp;nbsp;--&amp;gt;&amp;nbsp;C
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;H&amp;nbsp;--&amp;gt;&amp;nbsp;K[数据入库]&lt;/pre&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;核心代码框架（Manager类）&lt;/strong&gt;&lt;/div&gt;&lt;pre class=&quot;ybc-pre-component ybc-pre-component_not-math&quot;&gt;class&amp;nbsp;TaoBaoSpider:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;__init__(self):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.session&amp;nbsp;=&amp;nbsp;requests.Session()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.proxy_pool&amp;nbsp;=&amp;nbsp;[]&amp;nbsp;&amp;nbsp;#&amp;nbsp;代理IP池
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.cookie_pool&amp;nbsp;=&amp;nbsp;[]&amp;nbsp;#&amp;nbsp;Cookie池
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;get_valid_cookie(self):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;从池中获取一个有效Cookie，若无则生成&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;not&amp;nbsp;self.cookie_pool:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;self.generate_new_cookie()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;random.choice(self.cookie_pool)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;generate_new_cookie(self):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;使用Playwright生成新Cookie（绕过登录）&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;使用无头浏览器模拟扫码登录或滑块
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;返回有效的&amp;nbsp;cookie&amp;nbsp;字典
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pass
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;request_with_retry(self,&amp;nbsp;url,&amp;nbsp;retry=3):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;带重试机制的请求&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;i&amp;nbsp;in&amp;nbsp;range(retry):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cookie&amp;nbsp;=&amp;nbsp;self.get_valid_cookie()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;proxy&amp;nbsp;=&amp;nbsp;self.get_proxy()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;html&amp;nbsp;=&amp;nbsp;self.session.get(url,&amp;nbsp;cookies=cookie,&amp;nbsp;proxies=proxy)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;self.check_anti_spider(html):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(&amp;quot;触发风控，更换环境&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.ban_proxy(proxy)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;continue
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;html
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;except:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.ban_proxy(proxy)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;None&lt;/pre&gt;&lt;hr/&gt;&lt;h2&gt;四、 法律与合规红线&lt;/h2&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;⚠️ 重要声明&lt;/strong&gt;：&lt;/div&gt;&lt;ol class=&quot;ybc-ol-component ybc-ol-component_1 list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;仅供学习&lt;/strong&gt;：本文所有代码仅用于技术交流与学习，严禁用于商业爬取、恶意攻击或数据窃取。&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;合规边界&lt;/strong&gt;：淘宝数据受《反不正当竞争法》和《数据安全法》保护。大规模爬取可能构成违法行为。&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;官方API&lt;/strong&gt;：商业用途请务必使用 &lt;strong&gt;淘宝开放平台（TOP）API&lt;/strong&gt;，这是唯一合法合规的途径。&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;总结&lt;/strong&gt;：“看懂”淘宝反爬的本质，是理解其&lt;strong&gt;风控逻辑&lt;/strong&gt;而非单纯的技术对抗。通过模拟真实用户行为、维护动态Cookie池、合理控制频率，可以在学习研究的范围内稳定获取数据。但请始终牢记：&lt;strong&gt;技术应当用于正途，尊重平台规则，保护数据安全&lt;/strong&gt;。&lt;/div&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;</description><pubDate>Wed, 27 May 2026 15:33:25 +0800</pubDate></item><item><title>淘宝的购物车为什么永不丢失？分布式会话架构深度解析（附python源码）</title><link>https://alexob.com/?id=376</link><description>&lt;div class=&quot;ybc-p&quot;&gt;淘宝购物车之所以能实现“永不丢失”且跨设备同步，核心在于它彻底抛弃了单机内存存储，采用了&lt;strong&gt;无状态服务 + 分布式缓存（Tair/Redis）&lt;/strong&gt;的架构。这种设计让购物车数据不再依赖某台具体的服务器，而是存储在独立的共享集群中。&lt;/div&gt;&lt;div class=&quot;ybc-p&quot;&gt;下面为你深度解析这套架构的核心原理，并附上可落地的 Python 模拟实现。&lt;/div&gt;&lt;hr/&gt;&lt;h2&gt;一、 淘宝购物车架构深度解析&lt;/h2&gt;&lt;h3&gt;1. 为什么单机 Session 会“丢失”？&lt;/h3&gt;&lt;div class=&quot;ybc-p&quot;&gt;传统的购物车数据存在服务器内存（如 Flask/Django 的 &lt;code class=&quot;hyc-common-markdown__code__inline&quot;&gt;session&lt;/code&gt;）中，这会导致两个致命问题：&lt;/div&gt;&lt;ul class=&quot;ybc-ul-component list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;扩容即丢失&lt;/strong&gt;：当服务器重启或扩容新增节点时，内存数据清空，购物车就没了。&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;无法同步&lt;/strong&gt;：手机和电脑访问的是不同的后端服务器，数据无法互通。&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;2. 淘宝的解决方案：分布式会话&lt;/h3&gt;&lt;div class=&quot;ybc-p&quot;&gt;淘宝通过以下三层架构实现数据持久化：&lt;/div&gt;&lt;div class=&quot;hyc-common-markdown__table-wrapper&quot; data-has-scroll=&quot;false&quot; style=&quot;font-size: 16px; border-collapse: separate; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;div style=&quot;font-size: 16px; border-collapse: separate; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;table&gt;&lt;thead style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;tr style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot; class=&quot;firstRow&quot;&gt;&lt;th style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;组件&lt;/div&gt;&lt;/th&gt;&lt;th style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;角色&lt;/div&gt;&lt;/th&gt;&lt;th style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;淘宝实现方案&lt;/div&gt;&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;tr style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;strong style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;接入层&lt;/strong&gt;&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;身份识别&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;通过 Cookie 或 Token 携带唯一标识（如 &lt;code class=&quot;hyc-common-markdown__code__inline&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 2px 4px;&quot;&gt;session_id&lt;/code&gt;或 &lt;code class=&quot;hyc-common-markdown__code__inline&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 2px 4px;&quot;&gt;user_id&lt;/code&gt;）&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;strong style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;逻辑层&lt;/strong&gt;&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;无状态服务&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;购物车服务集群，不存储任何用户状态，只处理逻辑&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;strong style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;存储层&lt;/strong&gt;&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;数据持久化&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;strong style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;Tair/Redis 集群&lt;/strong&gt;（阿里云自研的高性能 KV 存储）&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;核心流程&lt;/strong&gt;：&lt;/div&gt;&lt;ol class=&quot;ybc-ol-component ybc-ol-component_1 list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;用户访问时，携带 &lt;code class=&quot;hyc-common-markdown__code__inline&quot;&gt;token&lt;/code&gt;或 &lt;code class=&quot;hyc-common-markdown__code__inline&quot;&gt;user_id&lt;/code&gt;。&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;负载均衡将请求随机转发给任意一台购物车服务节点。&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;服务节点根据 &lt;code class=&quot;hyc-common-markdown__code__inline&quot;&gt;user_id&lt;/code&gt;去 Redis 集群中读取/写入数据。&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;数据永远在 Redis 里&lt;/strong&gt;，服务器宕机或重启完全不影响数据安全。&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;h3&gt;3. 匿名购物车与登录合并策略&lt;/h3&gt;&lt;div class=&quot;ybc-p&quot;&gt;这也是淘宝体验好的关键细节：&lt;/div&gt;&lt;ul class=&quot;ybc-ul-component list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;匿名状态&lt;/strong&gt;：使用浏览器指纹或临时 ID 作为 Key，存入 Redis（设置较短过期时间）。&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;登录瞬间&lt;/strong&gt;：系统对比“匿名购物车”和“用户购物车”，智能合并冲突商品，然后删除临时数据。&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;hr/&gt;&lt;h2&gt;二、 Python 实现分布式购物车（Flask + Redis）&lt;/h2&gt;&lt;div class=&quot;ybc-p&quot;&gt;以下代码模拟了淘宝购物车的核心架构，你可以直接运行体验。&lt;/div&gt;&lt;h3&gt;1. 环境准备&lt;/h3&gt;&lt;pre class=&quot;ybc-pre-component ybc-pre-component_not-math&quot;&gt;pip&amp;nbsp;install&amp;nbsp;flask&amp;nbsp;redis&lt;/pre&gt;&lt;h3&gt;2. 核心代码实现&lt;/h3&gt;&lt;pre class=&quot;ybc-pre-component ybc-pre-component_not-math&quot;&gt;#&amp;nbsp;app.py
import&amp;nbsp;json
import&amp;nbsp;uuid
from&amp;nbsp;flask&amp;nbsp;import&amp;nbsp;Flask,&amp;nbsp;request,&amp;nbsp;jsonify,&amp;nbsp;make_response
import&amp;nbsp;redis
#&amp;nbsp;封装好API供应商demo&amp;nbsp;url=https://console.open.onebound.cn/console/?i=Lex
app&amp;nbsp;=&amp;nbsp;Flask(__name__)
app.config[&amp;#39;SECRET_KEY&amp;#39;]&amp;nbsp;=&amp;nbsp;&amp;#39;your-secret-key&amp;#39;

#&amp;nbsp;连接Redis集群（这里用单节点模拟）
redis_client&amp;nbsp;=&amp;nbsp;redis.Redis(host=&amp;#39;localhost&amp;#39;,&amp;nbsp;port=6379,&amp;nbsp;db=0,&amp;nbsp;decode_responses=True)

def&amp;nbsp;get_user_cart_key(user_id):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;生成购物车在Redis中的存储Key&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;f&amp;quot;shopping_cart:{user_id}&amp;quot;

def&amp;nbsp;get_or_create_user_id():
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;获取用户ID：优先从Cookie取，没有则生成匿名ID
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;模拟淘宝的匿名-&amp;gt;登录合并机制
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;user_id&amp;nbsp;=&amp;nbsp;request.cookies.get(&amp;#39;user_id&amp;#39;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;not&amp;nbsp;user_id:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;生成匿名用户ID（实际场景会结合浏览器指纹）
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;user_id&amp;nbsp;=&amp;nbsp;f&amp;quot;anonymous_{uuid.uuid4().hex}&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;user_id

@app.route(&amp;#39;/cart/add&amp;#39;,&amp;nbsp;methods=[&amp;#39;POST&amp;#39;])
def&amp;nbsp;add_to_cart():
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;添加商品到购物车（模仿淘宝的增量更新）&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;data&amp;nbsp;=&amp;nbsp;request.json
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;product_id&amp;nbsp;=&amp;nbsp;data.get(&amp;#39;product_id&amp;#39;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;quantity&amp;nbsp;=&amp;nbsp;data.get(&amp;#39;quantity&amp;#39;,&amp;nbsp;1)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;1.&amp;nbsp;获取用户身份
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;user_id&amp;nbsp;=&amp;nbsp;get_or_create_user_id()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cart_key&amp;nbsp;=&amp;nbsp;get_user_cart_key(user_id)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;2.&amp;nbsp;使用Redis&amp;nbsp;Hash存储（Key:&amp;nbsp;cart:123,&amp;nbsp;Field:&amp;nbsp;product_id,&amp;nbsp;Value:&amp;nbsp;quantity）
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;命令：HSET&amp;nbsp;cart:user123&amp;nbsp;6688&amp;nbsp;2
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;redis_client.hset(cart_key,&amp;nbsp;product_id,&amp;nbsp;quantity)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;3.&amp;nbsp;设置过期时间（匿名用户7天，登录用户永久）
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;user_id.startswith(&amp;#39;anonymous&amp;#39;):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;redis_client.expire(cart_key,&amp;nbsp;7&amp;nbsp;*&amp;nbsp;24&amp;nbsp;*&amp;nbsp;60&amp;nbsp;*&amp;nbsp;60)&amp;nbsp;&amp;nbsp;#&amp;nbsp;7天过期
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;resp&amp;nbsp;=&amp;nbsp;make_response(jsonify({&amp;quot;code&amp;quot;:&amp;nbsp;0,&amp;nbsp;&amp;quot;msg&amp;quot;:&amp;nbsp;&amp;quot;添加成功&amp;quot;}))
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;resp.set_cookie(&amp;#39;user_id&amp;#39;,&amp;nbsp;user_id,&amp;nbsp;max_age=365&amp;nbsp;*&amp;nbsp;24&amp;nbsp;*&amp;nbsp;60&amp;nbsp;*&amp;nbsp;60)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;resp

@app.route(&amp;#39;/cart/list&amp;#39;,&amp;nbsp;methods=[&amp;#39;GET&amp;#39;])
def&amp;nbsp;get_cart():
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;获取购物车列表（支持跨设备同步）&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;user_id&amp;nbsp;=&amp;nbsp;get_or_create_user_id()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cart_key&amp;nbsp;=&amp;nbsp;get_user_cart_key(user_id)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;一次性获取该用户购物车所有商品&amp;nbsp;HGETALL&amp;nbsp;cart:user123
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cart_data&amp;nbsp;=&amp;nbsp;redis_client.hgetall(cart_key)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;组装商品详情（实际业务会去商品服务查询价格、库存）
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;items&amp;nbsp;=&amp;nbsp;[]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;pid,&amp;nbsp;qty&amp;nbsp;in&amp;nbsp;cart_data.items():
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;items.append({
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;product_id&amp;quot;:&amp;nbsp;pid,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;quantity&amp;quot;:&amp;nbsp;int(qty),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;title&amp;quot;:&amp;nbsp;f&amp;quot;模拟商品{pid}&amp;quot;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;price&amp;quot;:&amp;nbsp;99.99
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;})
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;jsonify({
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;user_id&amp;quot;:&amp;nbsp;user_id,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;items&amp;quot;:&amp;nbsp;items,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;total&amp;quot;:&amp;nbsp;len(items)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;})

@app.route(&amp;#39;/cart/merge&amp;#39;,&amp;nbsp;methods=[&amp;#39;POST&amp;#39;])
def&amp;nbsp;merge_cart():
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;登录后合并匿名购物车（淘宝核心逻辑）&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;anonymous_id&amp;nbsp;=&amp;nbsp;request.cookies.get(&amp;#39;user_id&amp;#39;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;login_id&amp;nbsp;=&amp;nbsp;request.json.get(&amp;#39;login_id&amp;#39;)&amp;nbsp;&amp;nbsp;#&amp;nbsp;假设登录后传入
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;封装好API供应商demo&amp;nbsp;url=https://console.open.onebound.cn/console/?i=Lex
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;not&amp;nbsp;anonymous_id&amp;nbsp;or&amp;nbsp;not&amp;nbsp;login_id:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;jsonify({&amp;quot;code&amp;quot;:&amp;nbsp;1,&amp;nbsp;&amp;quot;msg&amp;quot;:&amp;nbsp;&amp;quot;参数错误&amp;quot;})
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;anon_key&amp;nbsp;=&amp;nbsp;get_user_cart_key(anonymous_id)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;login_key&amp;nbsp;=&amp;nbsp;get_user_cart_key(login_id)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;1.&amp;nbsp;获取匿名购物车数据
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;anon_items&amp;nbsp;=&amp;nbsp;redis_client.hgetall(anon_key)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;2.&amp;nbsp;合并到登录账户（这里采用“登录账户优先”策略）
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;pid,&amp;nbsp;qty&amp;nbsp;in&amp;nbsp;anon_items.items():
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;如果登录账户没有该商品，则添加
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;not&amp;nbsp;redis_client.hexists(login_key,&amp;nbsp;pid):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;redis_client.hset(login_key,&amp;nbsp;pid,&amp;nbsp;qty)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;3.&amp;nbsp;删除匿名购物车
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;redis_client.delete(anon_key)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;resp&amp;nbsp;=&amp;nbsp;make_response(jsonify({&amp;quot;code&amp;quot;:&amp;nbsp;0,&amp;nbsp;&amp;quot;msg&amp;quot;:&amp;nbsp;&amp;quot;合并成功&amp;quot;}))
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;resp.set_cookie(&amp;#39;user_id&amp;#39;,&amp;nbsp;login_id,&amp;nbsp;max_age=365&amp;nbsp;*&amp;nbsp;24&amp;nbsp;*&amp;nbsp;60&amp;nbsp;*&amp;nbsp;60)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;resp

if&amp;nbsp;__name__&amp;nbsp;==&amp;nbsp;&amp;#39;__main__&amp;#39;:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;app.run(host=&amp;#39;0.0.0.0&amp;#39;,&amp;nbsp;port=5000,&amp;nbsp;debug=True)&lt;/pre&gt;&lt;h3&gt;3. 测试命令&lt;/h3&gt;&lt;div class=&quot;ybc-p&quot;&gt;启动服务后，使用以下命令测试：&lt;/div&gt;&lt;pre class=&quot;ybc-pre-component ybc-pre-component_not-math&quot;&gt;#&amp;nbsp;添加商品
curl&amp;nbsp;-X&amp;nbsp;POST&amp;nbsp;http://127.0.0.1:5000/cart/add&amp;nbsp;\
&amp;nbsp;&amp;nbsp;-H&amp;nbsp;&amp;quot;Content-Type:&amp;nbsp;application/json&amp;quot;&amp;nbsp;\
&amp;nbsp;&amp;nbsp;-d&amp;nbsp;&amp;#39;{&amp;quot;product_id&amp;quot;:&amp;nbsp;&amp;quot;6688&amp;quot;,&amp;nbsp;&amp;quot;quantity&amp;quot;:&amp;nbsp;2}&amp;#39;&amp;nbsp;\
&amp;nbsp;&amp;nbsp;-c&amp;nbsp;cookies.txt

#&amp;nbsp;查看购物车（会自动携带Cookie）
curl&amp;nbsp;http://127.0.0.1:5000/cart/list&amp;nbsp;-b&amp;nbsp;cookies.txt&lt;/pre&gt;&lt;hr/&gt;&lt;h2&gt;三、 生产级架构进阶&lt;/h2&gt;&lt;h3&gt;1. Redis 数据结构优化&lt;/h3&gt;&lt;div class=&quot;ybc-p&quot;&gt;淘宝不会将整个购物车存为一个 JSON 字符串（性能差），而是使用 &lt;strong&gt;Hash&lt;/strong&gt; 结构：&lt;/div&gt;&lt;ul class=&quot;ybc-ul-component list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;Key&lt;/strong&gt;: &lt;code class=&quot;hyc-common-markdown__code__inline&quot;&gt;cart:{user_id}&lt;/code&gt;&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;Field&lt;/strong&gt;: &lt;code class=&quot;hyc-common-markdown__code__inline&quot;&gt;{sku_id}&lt;/code&gt;（商品唯一标识）&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;Value&lt;/strong&gt;: &lt;code class=&quot;hyc-common-markdown__code__inline&quot;&gt;{quantity}&lt;/code&gt;（数量）&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class=&quot;ybc-p&quot;&gt;这样可以对单个商品进行原子操作（&lt;code class=&quot;hyc-common-markdown__code__inline&quot;&gt;HINCRBY&lt;/code&gt;），无需读取整个列表。&lt;/div&gt;&lt;h3&gt;2. 高并发与一致性&lt;/h3&gt;&lt;ul class=&quot;ybc-ul-component list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;写并发&lt;/strong&gt;：使用 &lt;code class=&quot;hyc-common-markdown__code__inline&quot;&gt;HSETNX&lt;/code&gt;或 Lua 脚本保证在并发添加时数据不错乱。&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;读缓存&lt;/strong&gt;：虽然 Redis 很快，但在双11级别流量下，淘宝还会在客户端（App/Web）做一层本地缓存，减少服务端压力。&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;3. 数据分片（Sharding）&lt;/h3&gt;&lt;div class=&quot;ybc-p&quot;&gt;当用户量上亿时，单台 Redis 扛不住。淘宝采用&lt;strong&gt;一致性哈希&lt;/strong&gt;算法，将不同用户的购物车数据分布到不同的 Redis 集群节点上。&lt;/div&gt;&lt;hr/&gt;&lt;h2&gt;四、 总结&lt;/h2&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;淘宝购物车“永不丢失”的秘诀&lt;/strong&gt;：&lt;/div&gt;&lt;ol class=&quot;ybc-ol-component ybc-ol-component_1 list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;无状态化&lt;/strong&gt;：应用服务器不存数据，可以随意重启、扩容。&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;集中存储&lt;/strong&gt;：购物车数据统一存储在 Redis/Tair 集群中。&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;ID 贯通&lt;/strong&gt;：通过 &lt;code class=&quot;hyc-common-markdown__code__inline&quot;&gt;user_id&lt;/code&gt;或 &lt;code class=&quot;hyc-common-markdown__code__inline&quot;&gt;session_id&lt;/code&gt;作为唯一钥匙，打通多端数据。&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;div class=&quot;ybc-p&quot;&gt;通过上面的 Python 代码，你可以看到实现一个基础的分布式购物车并不复杂。关键在于&lt;strong&gt;将状态（数据）从服务中剥离出来&lt;/strong&gt;，这是构建任何高可用分布式系统的核心思想。&lt;/div&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;</description><pubDate>Wed, 27 May 2026 11:18:50 +0800</pubDate></item><item><title>🔥 别再手动比价了！手把手教你用Python爬虫自动监控淘宝/京东价格</title><link>https://alexob.com/?id=375</link><description>&lt;h1&gt;&lt;span style=&quot;font-size: 14px;&quot;&gt;还在每天打开N个浏览器标签页手动比价？价格波动总是错过？今天我就用&lt;/span&gt;&lt;strong style=&quot;font-size: 14px;&quot;&gt;100行代码&lt;/strong&gt;&lt;span style=&quot;font-size: 14px;&quot;&gt;帮你实现自动价格监控，每天节省1小时，还能抓住最佳购买时机！&lt;/span&gt;&lt;br/&gt;&lt;/h1&gt;&lt;hr/&gt;&lt;h2&gt;一、 价格监控爬虫的“四大核心能力”&lt;/h2&gt;&lt;div class=&quot;hyc-common-markdown__table-wrapper&quot; data-has-scroll=&quot;false&quot; style=&quot;font-size: 16px; border-collapse: separate; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;div style=&quot;font-size: 16px; border-collapse: separate; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;table&gt;&lt;thead style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;tr style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot; class=&quot;firstRow&quot;&gt;&lt;th style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;能力&lt;/div&gt;&lt;/th&gt;&lt;th style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;传统方式&lt;/div&gt;&lt;/th&gt;&lt;th style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;智能爬虫&lt;/div&gt;&lt;/th&gt;&lt;th style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;节省时间&lt;/div&gt;&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;tr style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;strong style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;价格采集&lt;/strong&gt;&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;手动查看&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;自动24小时监控&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;每天1小时&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;strong style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;历史追踪&lt;/strong&gt;&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;Excel记录&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;自动记录数据库&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;每周2小时&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;strong style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;降价提醒&lt;/strong&gt;&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;凭记忆&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;自动微信/邮件提醒&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;不错过任何优惠&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;strong style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;比价分析&lt;/strong&gt;&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;大脑计算&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;自动生成报表&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;每月8小时&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;总计&lt;/strong&gt;：每月节省 &lt;strong&gt;40+ 小时&lt;/strong&gt;，相当于多出1个完整工作日！&lt;/div&gt;&lt;hr/&gt;&lt;h2&gt;二、 完整源码：智能价格监控系统&lt;/h2&gt;&lt;h3&gt;1. 核心爬虫类（支持淘宝/京东/拼多多）&lt;/h3&gt;&lt;pre class=&quot;ybc-pre-component ybc-pre-component_not-math&quot;&gt;#&amp;nbsp;price_monitor.py
import&amp;nbsp;requests
import&amp;nbsp;json
import&amp;nbsp;time
import&amp;nbsp;re
from&amp;nbsp;datetime&amp;nbsp;import&amp;nbsp;datetime
from&amp;nbsp;urllib.parse&amp;nbsp;import&amp;nbsp;quote
import&amp;nbsp;sqlite3
from&amp;nbsp;typing&amp;nbsp;import&amp;nbsp;Dict,&amp;nbsp;List,&amp;nbsp;Optional
import&amp;nbsp;logging
import&amp;nbsp;smtplib
from&amp;nbsp;email.mime.text&amp;nbsp;import&amp;nbsp;MIMEText
import&amp;nbsp;pandas&amp;nbsp;as&amp;nbsp;pd
import&amp;nbsp;matplotlib.pyplot&amp;nbsp;as&amp;nbsp;plt
import&amp;nbsp;matplotlib
matplotlib.use(&amp;#39;Agg&amp;#39;)&amp;nbsp;&amp;nbsp;#&amp;nbsp;无GUI模式
#&amp;nbsp;封装好API供应商demo&amp;nbsp;url=https://console.open.onebound.cn/console/?i=Lex
class&amp;nbsp;PriceMonitor:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;智能价格监控器（支持淘宝、京东、拼多多）&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;__init__(self,&amp;nbsp;db_path=&amp;#39;price_data.db&amp;#39;):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;初始化数据库
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.init_database(db_path)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;配置请求头
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.headers&amp;nbsp;=&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;User-Agent&amp;#39;:&amp;nbsp;&amp;#39;Mozilla/5.0&amp;nbsp;(Windows&amp;nbsp;NT&amp;nbsp;10.0;&amp;nbsp;Win64;&amp;nbsp;x64)&amp;nbsp;AppleWebKit/537.36&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;Accept&amp;#39;:&amp;nbsp;&amp;#39;text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;Accept-Language&amp;#39;:&amp;nbsp;&amp;#39;zh-CN,zh;q=0.9,en;q=0.8&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;Accept-Encoding&amp;#39;:&amp;nbsp;&amp;#39;gzip,&amp;nbsp;deflate,&amp;nbsp;br&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;DNT&amp;#39;:&amp;nbsp;&amp;#39;1&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;Connection&amp;#39;:&amp;nbsp;&amp;#39;keep-alive&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;Upgrade-Insecure-Requests&amp;#39;:&amp;nbsp;&amp;#39;1&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;配置日志
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;logging.basicConfig(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;level=logging.INFO,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;format=&amp;#39;%(asctime)s&amp;nbsp;-&amp;nbsp;%(name)s&amp;nbsp;-&amp;nbsp;%(levelname)s&amp;nbsp;-&amp;nbsp;%(message)s&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;handlers=[
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;logging.FileHandler(&amp;#39;price_monitor.log&amp;#39;),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;logging.StreamHandler()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.logger&amp;nbsp;=&amp;nbsp;logging.getLogger(__name__)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;init_database(self,&amp;nbsp;db_path):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;初始化数据库&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.conn&amp;nbsp;=&amp;nbsp;sqlite3.connect(db_path)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.cursor&amp;nbsp;=&amp;nbsp;self.conn.cursor()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;创建商品表
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.cursor.execute(&amp;#39;&amp;#39;&amp;#39;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;CREATE&amp;nbsp;TABLE&amp;nbsp;IF&amp;nbsp;NOT&amp;nbsp;EXISTS&amp;nbsp;products&amp;nbsp;(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;id&amp;nbsp;INTEGER&amp;nbsp;PRIMARY&amp;nbsp;KEY&amp;nbsp;AUTOINCREMENT,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;name&amp;nbsp;TEXT&amp;nbsp;NOT&amp;nbsp;NULL,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;url&amp;nbsp;TEXT&amp;nbsp;NOT&amp;nbsp;NULL&amp;nbsp;UNIQUE,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;platform&amp;nbsp;TEXT,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;current_price&amp;nbsp;REAL,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;lowest_price&amp;nbsp;REAL,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;highest_price&amp;nbsp;REAL,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;created_at&amp;nbsp;TIMESTAMP&amp;nbsp;DEFAULT&amp;nbsp;CURRENT_TIMESTAMP,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;updated_at&amp;nbsp;TIMESTAMP&amp;nbsp;DEFAULT&amp;nbsp;CURRENT_TIMESTAMP
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;&amp;#39;&amp;#39;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;创建价格历史表
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.cursor.execute(&amp;#39;&amp;#39;&amp;#39;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;CREATE&amp;nbsp;TABLE&amp;nbsp;IF&amp;nbsp;NOT&amp;nbsp;EXISTS&amp;nbsp;price_history&amp;nbsp;(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;id&amp;nbsp;INTEGER&amp;nbsp;PRIMARY&amp;nbsp;KEY&amp;nbsp;AUTOINCREMENT,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;product_id&amp;nbsp;INTEGER,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;price&amp;nbsp;REAL,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;timestamp&amp;nbsp;TIMESTAMP&amp;nbsp;DEFAULT&amp;nbsp;CURRENT_TIMESTAMP,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;FOREIGN&amp;nbsp;KEY&amp;nbsp;(product_id)&amp;nbsp;REFERENCES&amp;nbsp;products&amp;nbsp;(id)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;&amp;#39;&amp;#39;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;创建监控规则表
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.cursor.execute(&amp;#39;&amp;#39;&amp;#39;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;CREATE&amp;nbsp;TABLE&amp;nbsp;IF&amp;nbsp;NOT&amp;nbsp;EXISTS&amp;nbsp;alert_rules&amp;nbsp;(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;id&amp;nbsp;INTEGER&amp;nbsp;PRIMARY&amp;nbsp;KEY&amp;nbsp;AUTOINCREMENT,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;product_id&amp;nbsp;INTEGER,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;target_price&amp;nbsp;REAL,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;alert_type&amp;nbsp;TEXT,&amp;nbsp;&amp;nbsp;--&amp;nbsp;&amp;#39;below&amp;#39;/&amp;#39;above&amp;#39;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;enabled&amp;nbsp;INTEGER&amp;nbsp;DEFAULT&amp;nbsp;1,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;FOREIGN&amp;nbsp;KEY&amp;nbsp;(product_id)&amp;nbsp;REFERENCES&amp;nbsp;products&amp;nbsp;(id)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;&amp;#39;&amp;#39;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.conn.commit()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;add_product(self,&amp;nbsp;url:&amp;nbsp;str,&amp;nbsp;name:&amp;nbsp;str&amp;nbsp;=&amp;nbsp;None):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;添加监控商品&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;platform&amp;nbsp;=&amp;nbsp;self.detect_platform(url)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;如果未提供名称，尝试从URL提取
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;not&amp;nbsp;name:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;name&amp;nbsp;=&amp;nbsp;self.extract_name_from_url(url)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;获取当前价格
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;price_info&amp;nbsp;=&amp;nbsp;self.fetch_price(url)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;price_info&amp;nbsp;and&amp;nbsp;price_info.get(&amp;#39;price&amp;#39;):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;current_price&amp;nbsp;=&amp;nbsp;float(price_info[&amp;#39;price&amp;#39;])
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;插入或更新商品
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.cursor.execute(&amp;#39;&amp;#39;&amp;#39;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;INSERT&amp;nbsp;OR&amp;nbsp;REPLACE&amp;nbsp;INTO&amp;nbsp;products&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;(name,&amp;nbsp;url,&amp;nbsp;platform,&amp;nbsp;current_price,&amp;nbsp;lowest_price,&amp;nbsp;highest_price,&amp;nbsp;updated_at)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;VALUES&amp;nbsp;(?,&amp;nbsp;?,&amp;nbsp;?,&amp;nbsp;?,&amp;nbsp;?,&amp;nbsp;?,&amp;nbsp;CURRENT_TIMESTAMP)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;&amp;#39;&amp;#39;,&amp;nbsp;(name,&amp;nbsp;url,&amp;nbsp;platform,&amp;nbsp;current_price,&amp;nbsp;current_price,&amp;nbsp;current_price))
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;product_id&amp;nbsp;=&amp;nbsp;self.cursor.lastrowid
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;记录价格历史
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.cursor.execute(&amp;#39;&amp;#39;&amp;#39;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;INSERT&amp;nbsp;INTO&amp;nbsp;price_history&amp;nbsp;(product_id,&amp;nbsp;price)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;VALUES&amp;nbsp;(?,&amp;nbsp;?)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;&amp;#39;&amp;#39;,&amp;nbsp;(product_id,&amp;nbsp;current_price))
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.conn.commit()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.logger.info(f&amp;quot;✅&amp;nbsp;添加商品:&amp;nbsp;{name},&amp;nbsp;价格:&amp;nbsp;¥{current_price}&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;product_id
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.logger.error(f&amp;quot;❌&amp;nbsp;无法获取商品价格:&amp;nbsp;{url}&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;None
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;except&amp;nbsp;Exception&amp;nbsp;as&amp;nbsp;e:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.logger.error(f&amp;quot;添加商品失败:&amp;nbsp;{e}&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;None
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;detect_platform(self,&amp;nbsp;url:&amp;nbsp;str)&amp;nbsp;-&amp;gt;&amp;nbsp;str:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;检测电商平台&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;&amp;#39;taobao.com&amp;#39;&amp;nbsp;in&amp;nbsp;url&amp;nbsp;or&amp;nbsp;&amp;#39;tmall.com&amp;#39;&amp;nbsp;in&amp;nbsp;url:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;&amp;#39;taobao&amp;#39;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;elif&amp;nbsp;&amp;#39;jd.com&amp;#39;&amp;nbsp;in&amp;nbsp;url:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;&amp;#39;jd&amp;#39;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;elif&amp;nbsp;&amp;#39;pinduoduo.com&amp;#39;&amp;nbsp;in&amp;nbsp;url&amp;nbsp;or&amp;nbsp;&amp;#39;yangkeduo.com&amp;#39;&amp;nbsp;in&amp;nbsp;url:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;&amp;#39;pdd&amp;#39;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;elif&amp;nbsp;&amp;#39;sunings.com&amp;#39;&amp;nbsp;in&amp;nbsp;url:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;&amp;#39;suning&amp;#39;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;&amp;#39;unknown&amp;#39;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;extract_name_from_url(self,&amp;nbsp;url:&amp;nbsp;str)&amp;nbsp;-&amp;gt;&amp;nbsp;str:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;从URL提取商品名称&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;尝试从URL参数提取
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;&amp;#39;id=&amp;#39;&amp;nbsp;in&amp;nbsp;url:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;product_id&amp;nbsp;=&amp;nbsp;url.split(&amp;#39;id=&amp;#39;)[1].split(&amp;#39;&amp;amp;&amp;#39;)[0]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;f&amp;quot;商品_{product_id}&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;elif&amp;nbsp;&amp;#39;/item/&amp;#39;&amp;nbsp;in&amp;nbsp;url:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;parts&amp;nbsp;=&amp;nbsp;url.split(&amp;#39;/item/&amp;#39;)[1].split(&amp;#39;.&amp;#39;)[0]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;parts
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;url.split(&amp;#39;/&amp;#39;)[-1].split(&amp;#39;.&amp;#39;)[0]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;except:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;&amp;quot;未知商品&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;fetch_price(self,&amp;nbsp;url:&amp;nbsp;str)&amp;nbsp;-&amp;gt;&amp;nbsp;Optional[Dict]:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;获取商品价格（支持多个平台）&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;platform&amp;nbsp;=&amp;nbsp;self.detect_platform(url)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;platform&amp;nbsp;==&amp;nbsp;&amp;#39;taobao&amp;#39;:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;self._fetch_taobao_price(url)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;elif&amp;nbsp;platform&amp;nbsp;==&amp;nbsp;&amp;#39;jd&amp;#39;:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;self._fetch_jd_price(url)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;elif&amp;nbsp;platform&amp;nbsp;==&amp;nbsp;&amp;#39;pdd&amp;#39;:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;self._fetch_pdd_price(url)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;self._fetch_generic_price(url)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;except&amp;nbsp;Exception&amp;nbsp;as&amp;nbsp;e:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.logger.error(f&amp;quot;获取价格失败&amp;nbsp;[{platform}]:&amp;nbsp;{e}&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;None
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;_fetch_taobao_price(self,&amp;nbsp;url:&amp;nbsp;str)&amp;nbsp;-&amp;gt;&amp;nbsp;Dict:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;获取淘宝/天猫价格&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;方法1:&amp;nbsp;尝试从HTML页面提取
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;response&amp;nbsp;=&amp;nbsp;requests.get(url,&amp;nbsp;headers=self.headers,&amp;nbsp;timeout=10)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;封装好API供应商demo&amp;nbsp;url=https://console.open.onebound.cn/console/?i=Lex
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;response.status_code&amp;nbsp;!=&amp;nbsp;200:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;raise&amp;nbsp;Exception(f&amp;quot;HTTP&amp;nbsp;{response.status_code}&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;html&amp;nbsp;=&amp;nbsp;response.text
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;查找价格信息
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;price_patterns&amp;nbsp;=&amp;nbsp;[
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;r&amp;#39;&amp;quot;price&amp;quot;\s*:\s*&amp;quot;([\d.]+)&amp;quot;&amp;#39;,&amp;nbsp;&amp;nbsp;#&amp;nbsp;JSON格式
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;r&amp;#39;&amp;quot;reservePrice&amp;quot;\s*:\s*&amp;quot;([\d.]+)&amp;quot;&amp;#39;,&amp;nbsp;&amp;nbsp;#&amp;nbsp;原价
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;r&amp;#39;&amp;quot;auctionPrice&amp;quot;\s*:\s*&amp;quot;([\d.]+)&amp;quot;&amp;#39;,&amp;nbsp;&amp;nbsp;#&amp;nbsp;拍卖价
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;r&amp;#39;&amp;lt;em&amp;nbsp;class=&amp;quot;tb-rmb-num&amp;quot;&amp;gt;([\d.]+)&amp;lt;/em&amp;gt;&amp;#39;,&amp;nbsp;&amp;nbsp;#&amp;nbsp;价格标签
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;r&amp;#39;&amp;quot;viewPrice&amp;quot;\s*:\s*&amp;quot;([\d.]+)&amp;quot;&amp;#39;,&amp;nbsp;&amp;nbsp;#&amp;nbsp;视图价格
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;price&amp;nbsp;=&amp;nbsp;None
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;pattern&amp;nbsp;in&amp;nbsp;price_patterns:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;match&amp;nbsp;=&amp;nbsp;re.search(pattern,&amp;nbsp;html)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;match:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;price&amp;nbsp;=&amp;nbsp;float(match.group(1))
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;break
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;查找商品名称
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;name_patterns&amp;nbsp;=&amp;nbsp;[
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;r&amp;#39;&amp;quot;title&amp;quot;\s*:\s*&amp;quot;([^&amp;quot;]+)&amp;quot;&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;r&amp;#39;&amp;lt;title&amp;gt;([^&amp;lt;]+)&amp;lt;/title&amp;gt;&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;r&amp;#39;&amp;quot;itemTitle&amp;quot;\s*:\s*&amp;quot;([^&amp;quot;]+)&amp;quot;&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;name&amp;nbsp;=&amp;nbsp;None
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;pattern&amp;nbsp;in&amp;nbsp;name_patterns:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;match&amp;nbsp;=&amp;nbsp;re.search(pattern,&amp;nbsp;html)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;match:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;name&amp;nbsp;=&amp;nbsp;match.group(1).strip()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;len(name)&amp;nbsp;&amp;gt;&amp;nbsp;100:&amp;nbsp;&amp;nbsp;#&amp;nbsp;标题可能太长
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;name&amp;nbsp;=&amp;nbsp;name[:100]&amp;nbsp;+&amp;nbsp;&amp;#39;...&amp;#39;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;break
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;not&amp;nbsp;price:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;尝试查找促销价
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;promo_pattern&amp;nbsp;=&amp;nbsp;r&amp;#39;&amp;quot;promotionPrice&amp;quot;\s*:\s*&amp;quot;([\d.]+)&amp;quot;&amp;#39;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;match&amp;nbsp;=&amp;nbsp;re.search(promo_pattern,&amp;nbsp;html)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;match:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;price&amp;nbsp;=&amp;nbsp;float(match.group(1))
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;{&amp;#39;price&amp;#39;:&amp;nbsp;price,&amp;nbsp;&amp;#39;name&amp;#39;:&amp;nbsp;name,&amp;nbsp;&amp;#39;url&amp;#39;:&amp;nbsp;url}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;_fetch_jd_price(self,&amp;nbsp;url:&amp;nbsp;str)&amp;nbsp;-&amp;gt;&amp;nbsp;Dict:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;获取京东价格&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;response&amp;nbsp;=&amp;nbsp;requests.get(url,&amp;nbsp;headers=self.headers,&amp;nbsp;timeout=10)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;response.status_code&amp;nbsp;!=&amp;nbsp;200:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;raise&amp;nbsp;Exception(f&amp;quot;HTTP&amp;nbsp;{response.status_code}&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;html&amp;nbsp;=&amp;nbsp;response.text
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;京东价格通常在JavaScript中
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;price_patterns&amp;nbsp;=&amp;nbsp;[
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;r&amp;#39;&amp;quot;p&amp;quot;:&amp;quot;([\d.]+)&amp;quot;&amp;#39;,&amp;nbsp;&amp;nbsp;#&amp;nbsp;价格
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;r&amp;#39;jd\.price\s*=\s*([\d.]+)&amp;#39;,&amp;nbsp;&amp;nbsp;#&amp;nbsp;价格变量
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;r&amp;#39;&amp;quot;salePrice&amp;quot;:\s*([\d.]+)&amp;#39;,&amp;nbsp;&amp;nbsp;#&amp;nbsp;销售价
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;r&amp;#39;&amp;lt;em&amp;nbsp;class=&amp;quot;price&amp;nbsp;J-p-[\d]+&amp;quot;&amp;gt;([\d.]+)&amp;lt;/em&amp;gt;&amp;#39;,&amp;nbsp;&amp;nbsp;#&amp;nbsp;价格标签
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;price&amp;nbsp;=&amp;nbsp;None
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;pattern&amp;nbsp;in&amp;nbsp;price_patterns:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;match&amp;nbsp;=&amp;nbsp;re.search(pattern,&amp;nbsp;html)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;match:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;price&amp;nbsp;=&amp;nbsp;float(match.group(1))
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;break
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;except:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;continue
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;查找商品名称
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;name&amp;nbsp;=&amp;nbsp;None
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;name_match&amp;nbsp;=&amp;nbsp;re.search(r&amp;#39;&amp;lt;title&amp;gt;([^&amp;lt;]+)&amp;lt;/title&amp;gt;&amp;#39;,&amp;nbsp;html)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;name_match:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;name&amp;nbsp;=&amp;nbsp;name_match.group(1).split(&amp;#39;【&amp;#39;)[0].split(&amp;#39;（&amp;#39;)[0].strip()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;{&amp;#39;price&amp;#39;:&amp;nbsp;price,&amp;nbsp;&amp;#39;name&amp;#39;:&amp;nbsp;name,&amp;nbsp;&amp;#39;url&amp;#39;:&amp;nbsp;url}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;_fetch_pdd_price(self,&amp;nbsp;url:&amp;nbsp;str)&amp;nbsp;-&amp;gt;&amp;nbsp;Dict:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;获取拼多多价格&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;拼多多有较强的反爬，需要简化处理
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;response&amp;nbsp;=&amp;nbsp;requests.get(url,&amp;nbsp;headers=self.headers,&amp;nbsp;timeout=10)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;response.status_code&amp;nbsp;!=&amp;nbsp;200:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;raise&amp;nbsp;Exception(f&amp;quot;HTTP&amp;nbsp;{response.status_code}&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;html&amp;nbsp;=&amp;nbsp;response.text
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;尝试多种模式
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;price_patterns&amp;nbsp;=&amp;nbsp;[
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;r&amp;#39;&amp;quot;marketPrice&amp;quot;\s*:\s*(\d+)&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;r&amp;#39;&amp;quot;goodsPrice&amp;quot;:\s*&amp;quot;([\d.]+)&amp;quot;&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;r&amp;#39;&amp;quot;price&amp;quot;:\s*&amp;quot;([\d.]+)&amp;quot;&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;price&amp;nbsp;=&amp;nbsp;None
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;pattern&amp;nbsp;in&amp;nbsp;price_patterns:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;match&amp;nbsp;=&amp;nbsp;re.search(pattern,&amp;nbsp;html)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;match:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;price&amp;nbsp;=&amp;nbsp;float(match.group(1))
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;break
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;except:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;continue
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;查找商品名称
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;name&amp;nbsp;=&amp;nbsp;None
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;name_match&amp;nbsp;=&amp;nbsp;re.search(r&amp;#39;&amp;lt;title&amp;gt;([^&amp;lt;]+)&amp;lt;/title&amp;gt;&amp;#39;,&amp;nbsp;html)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;name_match:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;name&amp;nbsp;=&amp;nbsp;name_match.group(1).split(&amp;#39;-&amp;#39;)[0].strip()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;{&amp;#39;price&amp;#39;:&amp;nbsp;price,&amp;nbsp;&amp;#39;name&amp;#39;:&amp;nbsp;name,&amp;nbsp;&amp;#39;url&amp;#39;:&amp;nbsp;url}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;_fetch_generic_price(self,&amp;nbsp;url:&amp;nbsp;str)&amp;nbsp;-&amp;gt;&amp;nbsp;Dict:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;通用价格获取方法&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;response&amp;nbsp;=&amp;nbsp;requests.get(url,&amp;nbsp;headers=self.headers,&amp;nbsp;timeout=10)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;response.status_code&amp;nbsp;!=&amp;nbsp;200:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;raise&amp;nbsp;Exception(f&amp;quot;HTTP&amp;nbsp;{response.status_code}&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;html&amp;nbsp;=&amp;nbsp;response.text
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;尝试查找各种价格格式
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;price_patterns&amp;nbsp;=&amp;nbsp;[
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;r&amp;#39;¥\s*([\d,.]+)&amp;#39;,&amp;nbsp;&amp;nbsp;#&amp;nbsp;¥&amp;nbsp;符号
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;r&amp;#39;￥\s*([\d,.]+)&amp;#39;,&amp;nbsp;&amp;nbsp;#&amp;nbsp;￥&amp;nbsp;符号
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;r&amp;#39;价格\s*[:：]\s*([\d,.]+)&amp;#39;,&amp;nbsp;&amp;nbsp;#&amp;nbsp;价格标签
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;r&amp;#39;price[&amp;quot;\&amp;#39;]?\s*[:=]\s*[&amp;quot;\&amp;#39;]?([\d,.]+)&amp;#39;,&amp;nbsp;&amp;nbsp;#&amp;nbsp;price属性
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;price&amp;nbsp;=&amp;nbsp;None
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;pattern&amp;nbsp;in&amp;nbsp;price_patterns:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;matches&amp;nbsp;=&amp;nbsp;re.findall(pattern,&amp;nbsp;html,&amp;nbsp;re.IGNORECASE)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;matches:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;取第一个匹配的价格
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;price_str&amp;nbsp;=&amp;nbsp;matches[0].replace(&amp;#39;,&amp;#39;,&amp;nbsp;&amp;#39;&amp;#39;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;price&amp;nbsp;=&amp;nbsp;float(price_str)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;break
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;except:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;continue
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;查找商品名称
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;name&amp;nbsp;=&amp;nbsp;None
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;name_match&amp;nbsp;=&amp;nbsp;re.search(r&amp;#39;&amp;lt;title&amp;gt;([^&amp;lt;]+)&amp;lt;/title&amp;gt;&amp;#39;,&amp;nbsp;html)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;name_match:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;name&amp;nbsp;=&amp;nbsp;name_match.group(1).strip()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;{&amp;#39;price&amp;#39;:&amp;nbsp;price,&amp;nbsp;&amp;#39;name&amp;#39;:&amp;nbsp;name,&amp;nbsp;&amp;#39;url&amp;#39;:&amp;nbsp;url}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;update_all_prices(self):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;更新所有商品价格&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.logger.info(&amp;quot;开始更新所有商品价格...&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;获取所有商品
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.cursor.execute(&amp;#39;SELECT&amp;nbsp;id,&amp;nbsp;url,&amp;nbsp;name&amp;nbsp;FROM&amp;nbsp;products&amp;#39;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;products&amp;nbsp;=&amp;nbsp;self.cursor.fetchall()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;updated_count&amp;nbsp;=&amp;nbsp;0
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;product_id,&amp;nbsp;url,&amp;nbsp;name&amp;nbsp;in&amp;nbsp;products:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;获取最新价格
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;price_info&amp;nbsp;=&amp;nbsp;self.fetch_price(url)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;price_info&amp;nbsp;and&amp;nbsp;price_info.get(&amp;#39;price&amp;#39;):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;current_price&amp;nbsp;=&amp;nbsp;float(price_info[&amp;#39;price&amp;#39;])
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;获取历史最低/最高价
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.cursor.execute(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;SELECT&amp;nbsp;MIN(price),&amp;nbsp;MAX(price)&amp;nbsp;FROM&amp;nbsp;price_history&amp;nbsp;WHERE&amp;nbsp;product_id&amp;nbsp;=&amp;nbsp;?&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;(product_id,)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;min_price,&amp;nbsp;max_price&amp;nbsp;=&amp;nbsp;self.cursor.fetchone()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;更新商品信息
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;new_min&amp;nbsp;=&amp;nbsp;min(min_price&amp;nbsp;or&amp;nbsp;current_price,&amp;nbsp;current_price)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;new_max&amp;nbsp;=&amp;nbsp;max(max_price&amp;nbsp;or&amp;nbsp;current_price,&amp;nbsp;current_price)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.cursor.execute(&amp;#39;&amp;#39;&amp;#39;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;UPDATE&amp;nbsp;products&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SET&amp;nbsp;current_price&amp;nbsp;=&amp;nbsp;?,&amp;nbsp;lowest_price&amp;nbsp;=&amp;nbsp;?,&amp;nbsp;highest_price&amp;nbsp;=&amp;nbsp;?,&amp;nbsp;updated_at&amp;nbsp;=&amp;nbsp;CURRENT_TIMESTAMP
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;WHERE&amp;nbsp;id&amp;nbsp;=&amp;nbsp;?
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;&amp;#39;&amp;#39;,&amp;nbsp;(current_price,&amp;nbsp;new_min,&amp;nbsp;new_max,&amp;nbsp;product_id))
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;记录价格历史
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.cursor.execute(&amp;#39;&amp;#39;&amp;#39;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;INSERT&amp;nbsp;INTO&amp;nbsp;price_history&amp;nbsp;(product_id,&amp;nbsp;price)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;VALUES&amp;nbsp;(?,&amp;nbsp;?)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;&amp;#39;&amp;#39;,&amp;nbsp;(product_id,&amp;nbsp;current_price))
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;updated_count&amp;nbsp;+=&amp;nbsp;1
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;检查价格提醒
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.check_price_alerts(product_id,&amp;nbsp;current_price,&amp;nbsp;name)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.logger.info(f&amp;quot;✅&amp;nbsp;更新:&amp;nbsp;{name}&amp;nbsp;-&amp;gt;&amp;nbsp;¥{current_price}&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.logger.warning(f&amp;quot;⚠️&amp;nbsp;无法获取价格:&amp;nbsp;{name}&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;避免请求过快
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;time.sleep(1)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;except&amp;nbsp;Exception&amp;nbsp;as&amp;nbsp;e:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.logger.error(f&amp;quot;更新失败&amp;nbsp;{name}:&amp;nbsp;{e}&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;continue
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.conn.commit()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.logger.info(f&amp;quot;价格更新完成:&amp;nbsp;{updated_count}/{len(products)}&amp;nbsp;个商品&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;updated_count
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;add_alert_rule(self,&amp;nbsp;product_id:&amp;nbsp;int,&amp;nbsp;target_price:&amp;nbsp;float,&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;alert_type:&amp;nbsp;str&amp;nbsp;=&amp;nbsp;&amp;#39;below&amp;#39;):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;添加价格提醒规则&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.cursor.execute(&amp;#39;&amp;#39;&amp;#39;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;INSERT&amp;nbsp;OR&amp;nbsp;REPLACE&amp;nbsp;INTO&amp;nbsp;alert_rules&amp;nbsp;(product_id,&amp;nbsp;target_price,&amp;nbsp;alert_type)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;VALUES&amp;nbsp;(?,&amp;nbsp;?,&amp;nbsp;?)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;&amp;#39;&amp;#39;,&amp;nbsp;(product_id,&amp;nbsp;target_price,&amp;nbsp;alert_type))
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.conn.commit()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.logger.info(f&amp;quot;✅&amp;nbsp;添加提醒规则:&amp;nbsp;商品{product_id},&amp;nbsp;目标价¥{target_price}&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;True
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;except&amp;nbsp;Exception&amp;nbsp;as&amp;nbsp;e:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.logger.error(f&amp;quot;添加提醒失败:&amp;nbsp;{e}&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;False
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;check_price_alerts(self,&amp;nbsp;product_id:&amp;nbsp;int,&amp;nbsp;current_price:&amp;nbsp;float,&amp;nbsp;product_name:&amp;nbsp;str):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;检查价格提醒&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.cursor.execute(&amp;#39;&amp;#39;&amp;#39;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SELECT&amp;nbsp;target_price,&amp;nbsp;alert_type&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;FROM&amp;nbsp;alert_rules&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;WHERE&amp;nbsp;product_id&amp;nbsp;=&amp;nbsp;?&amp;nbsp;AND&amp;nbsp;enabled&amp;nbsp;=&amp;nbsp;1
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;&amp;#39;&amp;#39;,&amp;nbsp;(product_id,))
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;rules&amp;nbsp;=&amp;nbsp;self.cursor.fetchall()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;target_price,&amp;nbsp;alert_type&amp;nbsp;in&amp;nbsp;rules:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;should_alert&amp;nbsp;=&amp;nbsp;False
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;message&amp;nbsp;=&amp;nbsp;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;alert_type&amp;nbsp;==&amp;nbsp;&amp;#39;below&amp;#39;&amp;nbsp;and&amp;nbsp;current_price&amp;nbsp;&amp;lt;=&amp;nbsp;target_price:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;should_alert&amp;nbsp;=&amp;nbsp;True
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;message&amp;nbsp;=&amp;nbsp;f&amp;quot;🎉&amp;nbsp;降价啦！{product_name}&amp;nbsp;当前价:&amp;nbsp;¥{current_price}&amp;nbsp;≤&amp;nbsp;目标价:&amp;nbsp;¥{target_price}&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;elif&amp;nbsp;alert_type&amp;nbsp;==&amp;nbsp;&amp;#39;above&amp;#39;&amp;nbsp;and&amp;nbsp;current_price&amp;nbsp;&amp;gt;=&amp;nbsp;target_price:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;should_alert&amp;nbsp;=&amp;nbsp;True
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;message&amp;nbsp;=&amp;nbsp;f&amp;quot;📈&amp;nbsp;涨价提醒！{product_name}&amp;nbsp;当前价:&amp;nbsp;¥{current_price}&amp;nbsp;≥&amp;nbsp;目标价:&amp;nbsp;¥{target_price}&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;should_alert:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.send_alert(product_id,&amp;nbsp;message)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;send_alert(self,&amp;nbsp;product_id:&amp;nbsp;int,&amp;nbsp;message:&amp;nbsp;str):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;发送提醒&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;这里可以实现多种通知方式
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(f&amp;quot;🔔&amp;nbsp;价格提醒:&amp;nbsp;{message}&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;1.&amp;nbsp;控制台打印
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.logger.info(message)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;2.&amp;nbsp;可以扩展为邮件提醒
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;self.send_email_alert(message)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;3.&amp;nbsp;可以扩展为微信提醒
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;self.send_wechat_alert(message)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;禁用已触发的提醒
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.cursor.execute(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;UPDATE&amp;nbsp;alert_rules&amp;nbsp;SET&amp;nbsp;enabled&amp;nbsp;=&amp;nbsp;0&amp;nbsp;WHERE&amp;nbsp;product_id&amp;nbsp;=&amp;nbsp;?&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;(product_id,)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.conn.commit()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;send_email_alert(self,&amp;nbsp;message:&amp;nbsp;str,&amp;nbsp;to_email:&amp;nbsp;str&amp;nbsp;=&amp;nbsp;None):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;发送邮件提醒（需要配置SMTP）&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;not&amp;nbsp;to_email:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;邮件配置
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;smtp_server&amp;nbsp;=&amp;nbsp;&amp;quot;smtp.163.com&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;smtp_port&amp;nbsp;=&amp;nbsp;465
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sender&amp;nbsp;=&amp;nbsp;&amp;quot;your_email@163.com&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;password&amp;nbsp;=&amp;nbsp;&amp;quot;your_password&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;msg&amp;nbsp;=&amp;nbsp;MIMEText(message,&amp;nbsp;&amp;#39;plain&amp;#39;,&amp;nbsp;&amp;#39;utf-8&amp;#39;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;msg[&amp;#39;Subject&amp;#39;]&amp;nbsp;=&amp;nbsp;&amp;#39;🔔&amp;nbsp;价格监控提醒&amp;#39;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;msg[&amp;#39;From&amp;#39;]&amp;nbsp;=&amp;nbsp;sender
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;msg[&amp;#39;To&amp;#39;]&amp;nbsp;=&amp;nbsp;to_email
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;with&amp;nbsp;smtplib.SMTP_SSL(smtp_server,&amp;nbsp;smtp_port)&amp;nbsp;as&amp;nbsp;server:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;server.login(sender,&amp;nbsp;password)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;server.send_message(msg)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.logger.info(f&amp;quot;📧&amp;nbsp;邮件提醒已发送:&amp;nbsp;{to_email}&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;except&amp;nbsp;Exception&amp;nbsp;as&amp;nbsp;e:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.logger.error(f&amp;quot;发送邮件失败:&amp;nbsp;{e}&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;generate_report(self,&amp;nbsp;days:&amp;nbsp;int&amp;nbsp;=&amp;nbsp;30)&amp;nbsp;-&amp;gt;&amp;nbsp;Dict:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;生成价格监控报告&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;获取时间范围
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cutoff_date&amp;nbsp;=&amp;nbsp;datetime.now().strftime(&amp;#39;%Y-%m-%d&amp;nbsp;%H:%M:%S&amp;#39;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;封装好API供应商demo&amp;nbsp;url=https://console.open.onebound.cn/console/?i=Lex
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;商品统计
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.cursor.execute(&amp;#39;&amp;#39;&amp;#39;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SELECT&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;COUNT(*)&amp;nbsp;as&amp;nbsp;total_products,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;COUNT(DISTINCT&amp;nbsp;platform)&amp;nbsp;as&amp;nbsp;platforms,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;AVG(current_price)&amp;nbsp;as&amp;nbsp;avg_price,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;MIN(lowest_price)&amp;nbsp;as&amp;nbsp;global_min,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;MAX(highest_price)&amp;nbsp;as&amp;nbsp;global_max
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;FROM&amp;nbsp;products
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;&amp;#39;&amp;#39;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;stats&amp;nbsp;=&amp;nbsp;self.cursor.fetchone()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;价格变化统计
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.cursor.execute(&amp;#39;&amp;#39;&amp;#39;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SELECT&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;p.name,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;p.platform,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;p.current_price,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;p.lowest_price,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;p.highest_price,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;(p.current_price&amp;nbsp;-&amp;nbsp;p.lowest_price)&amp;nbsp;as&amp;nbsp;diff_from_low,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ROUND((p.current_price&amp;nbsp;-&amp;nbsp;p.lowest_price)&amp;nbsp;/&amp;nbsp;p.lowest_price&amp;nbsp;*&amp;nbsp;100,&amp;nbsp;2)&amp;nbsp;as&amp;nbsp;discount_pct
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;FROM&amp;nbsp;products&amp;nbsp;p
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ORDER&amp;nbsp;BY&amp;nbsp;discount_pct&amp;nbsp;DESC
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;&amp;#39;&amp;#39;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;products&amp;nbsp;=&amp;nbsp;self.cursor.fetchall()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;转换为DataFrame便于分析
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;columns&amp;nbsp;=&amp;nbsp;[&amp;#39;name&amp;#39;,&amp;nbsp;&amp;#39;platform&amp;#39;,&amp;nbsp;&amp;#39;current&amp;#39;,&amp;nbsp;&amp;#39;lowest&amp;#39;,&amp;nbsp;&amp;#39;highest&amp;#39;,&amp;nbsp;&amp;#39;diff&amp;#39;,&amp;nbsp;&amp;#39;discount_pct&amp;#39;]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;df&amp;nbsp;=&amp;nbsp;pd.DataFrame(products,&amp;nbsp;columns=columns)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;report&amp;nbsp;=&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;generated_at&amp;#39;:&amp;nbsp;datetime.now().strftime(&amp;#39;%Y-%m-%d&amp;nbsp;%H:%M:%S&amp;#39;),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;stats&amp;#39;:&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;total_products&amp;#39;:&amp;nbsp;stats[0],
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;platforms&amp;#39;:&amp;nbsp;stats[1],
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;avg_price&amp;#39;:&amp;nbsp;round(stats[2],&amp;nbsp;2)&amp;nbsp;if&amp;nbsp;stats[2]&amp;nbsp;else&amp;nbsp;0,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;global_min_price&amp;#39;:&amp;nbsp;stats[3],
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;global_max_price&amp;#39;:&amp;nbsp;stats[4]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;},
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;best_deals&amp;#39;:&amp;nbsp;df.nsmallest(5,&amp;nbsp;&amp;#39;current&amp;#39;).to_dict(&amp;#39;records&amp;#39;),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;price_changes&amp;#39;:&amp;nbsp;self.get_price_changes(days)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;report
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;get_price_changes(self,&amp;nbsp;days:&amp;nbsp;int&amp;nbsp;=&amp;nbsp;7)&amp;nbsp;-&amp;gt;&amp;nbsp;List[Dict]:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;获取价格变化趋势&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.cursor.execute(&amp;#39;&amp;#39;&amp;#39;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SELECT&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;p.name,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ph.price,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ph.timestamp
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;FROM&amp;nbsp;price_history&amp;nbsp;ph
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;JOIN&amp;nbsp;products&amp;nbsp;p&amp;nbsp;ON&amp;nbsp;p.id&amp;nbsp;=&amp;nbsp;ph.product_id
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;WHERE&amp;nbsp;ph.timestamp&amp;nbsp;&amp;gt;=&amp;nbsp;datetime(&amp;#39;now&amp;#39;,&amp;nbsp;?)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ORDER&amp;nbsp;BY&amp;nbsp;ph.timestamp&amp;nbsp;DESC
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;&amp;#39;&amp;#39;,&amp;nbsp;(f&amp;#39;-{days}&amp;nbsp;days&amp;#39;,))
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;self.cursor.fetchall()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;plot_price_history(self,&amp;nbsp;product_id:&amp;nbsp;int,&amp;nbsp;save_path:&amp;nbsp;str&amp;nbsp;=&amp;nbsp;None):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;绘制价格历史图表&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.cursor.execute(&amp;#39;&amp;#39;&amp;#39;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SELECT&amp;nbsp;price,&amp;nbsp;timestamp&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;FROM&amp;nbsp;price_history&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;WHERE&amp;nbsp;product_id&amp;nbsp;=&amp;nbsp;?&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ORDER&amp;nbsp;BY&amp;nbsp;timestamp
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;&amp;#39;&amp;#39;,&amp;nbsp;(product_id,))
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;data&amp;nbsp;=&amp;nbsp;self.cursor.fetchall()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;not&amp;nbsp;data:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.logger.warning(f&amp;quot;无价格数据:&amp;nbsp;商品{product_id}&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;获取商品信息
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.cursor.execute(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;SELECT&amp;nbsp;name,&amp;nbsp;current_price&amp;nbsp;FROM&amp;nbsp;products&amp;nbsp;WHERE&amp;nbsp;id&amp;nbsp;=&amp;nbsp;?&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;(product_id,)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;name,&amp;nbsp;current_price&amp;nbsp;=&amp;nbsp;self.cursor.fetchone()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;准备数据
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;prices&amp;nbsp;=&amp;nbsp;[row[0]&amp;nbsp;for&amp;nbsp;row&amp;nbsp;in&amp;nbsp;data]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;timestamps&amp;nbsp;=&amp;nbsp;[row[1]&amp;nbsp;for&amp;nbsp;row&amp;nbsp;in&amp;nbsp;data]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;转换为datetime
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;dates&amp;nbsp;=&amp;nbsp;[datetime.strptime(ts[:19],&amp;nbsp;&amp;#39;%Y-%m-%d&amp;nbsp;%H:%M:%S&amp;#39;)&amp;nbsp;for&amp;nbsp;ts&amp;nbsp;in&amp;nbsp;timestamps]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;创建图表
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;plt.figure(figsize=(12,&amp;nbsp;6))
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;plt.plot(dates,&amp;nbsp;prices,&amp;nbsp;&amp;#39;b-&amp;#39;,&amp;nbsp;linewidth=2,&amp;nbsp;marker=&amp;#39;o&amp;#39;,&amp;nbsp;markersize=4)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;标记当前价格
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;plt.axhline(y=current_price,&amp;nbsp;color=&amp;#39;r&amp;#39;,&amp;nbsp;linestyle=&amp;#39;--&amp;#39;,&amp;nbsp;alpha=0.5,&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;label=f&amp;#39;当前:&amp;nbsp;¥{current_price}&amp;#39;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;标记最低价
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;min_price&amp;nbsp;=&amp;nbsp;min(prices)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;min_date&amp;nbsp;=&amp;nbsp;dates[prices.index(min_price)]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;plt.scatter([min_date],&amp;nbsp;[min_price],&amp;nbsp;color=&amp;#39;g&amp;#39;,&amp;nbsp;s=100,&amp;nbsp;zorder=5)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;plt.annotate(f&amp;#39;最低:&amp;nbsp;¥{min_price}&amp;#39;,&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;xy=(min_date,&amp;nbsp;min_price),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;xytext=(10,&amp;nbsp;10),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;textcoords=&amp;#39;offset&amp;nbsp;points&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;bbox=dict(boxstyle=&amp;#39;round,pad=0.5&amp;#39;,&amp;nbsp;fc=&amp;#39;green&amp;#39;,&amp;nbsp;alpha=0.3))
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;图表美化
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;plt.title(f&amp;#39;{name}&amp;nbsp;价格走势图&amp;#39;,&amp;nbsp;fontsize=16,&amp;nbsp;fontweight=&amp;#39;bold&amp;#39;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;plt.xlabel(&amp;#39;日期&amp;#39;,&amp;nbsp;fontsize=12)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;plt.ylabel(&amp;#39;价格&amp;nbsp;(¥)&amp;#39;,&amp;nbsp;fontsize=12)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;plt.grid(True,&amp;nbsp;alpha=0.3)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;plt.legend()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;plt.xticks(rotation=45)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;plt.tight_layout()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;保存或显示
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;save_path:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;plt.savefig(save_path,&amp;nbsp;dpi=300,&amp;nbsp;bbox_inches=&amp;#39;tight&amp;#39;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.logger.info(f&amp;quot;📈&amp;nbsp;图表已保存:&amp;nbsp;{save_path}&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;plt.show()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;plt.close()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;close(self):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;关闭连接&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;hasattr(self,&amp;nbsp;&amp;#39;conn&amp;#39;):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.conn.close()

#&amp;nbsp;使用示例
if&amp;nbsp;__name__&amp;nbsp;==&amp;nbsp;&amp;quot;__main__&amp;quot;:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(&amp;quot;🛒&amp;nbsp;智能价格监控系统启动！&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(&amp;quot;=&amp;quot;&amp;nbsp;*&amp;nbsp;50)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;创建监控器
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;monitor&amp;nbsp;=&amp;nbsp;PriceMonitor()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;示例商品（替换为你想监控的商品）
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sample_products&amp;nbsp;=&amp;nbsp;[
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;格式:&amp;nbsp;[商品URL,&amp;nbsp;商品名称(可选)]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;[&amp;quot;https://item.taobao.com/item.htm?id=674904123402&amp;quot;,&amp;nbsp;&amp;quot;智能手表&amp;quot;],
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;[&amp;quot;https://item.jd.com/100008348542.html&amp;quot;,&amp;nbsp;&amp;quot;无线耳机&amp;quot;],
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;添加更多商品...
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;1.&amp;nbsp;添加监控商品
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(&amp;quot;\n1.&amp;nbsp;添加监控商品...&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;url,&amp;nbsp;name&amp;nbsp;in&amp;nbsp;sample_products:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;product_id&amp;nbsp;=&amp;nbsp;monitor.add_product(url,&amp;nbsp;name)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;product_id:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(f&amp;quot;&amp;nbsp;&amp;nbsp;&amp;nbsp;✅&amp;nbsp;已添加:&amp;nbsp;{name}&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(f&amp;quot;&amp;nbsp;&amp;nbsp;&amp;nbsp;❌&amp;nbsp;添加失败:&amp;nbsp;{name}&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;time.sleep(2)&amp;nbsp;&amp;nbsp;#&amp;nbsp;避免请求过快
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;2.&amp;nbsp;设置价格提醒
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(&amp;quot;\n2.&amp;nbsp;设置价格提醒...&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;假设第一个商品ID是1，设置当价格低于500时提醒
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;monitor.add_alert_rule(1,&amp;nbsp;500.0,&amp;nbsp;&amp;#39;below&amp;#39;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(&amp;quot;&amp;nbsp;&amp;nbsp;&amp;nbsp;✅&amp;nbsp;已设置:&amp;nbsp;智能手表&amp;nbsp;&amp;lt;&amp;nbsp;¥500&amp;nbsp;时提醒&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;3.&amp;nbsp;更新所有价格
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(&amp;quot;\n3.&amp;nbsp;开始更新价格...&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;updated&amp;nbsp;=&amp;nbsp;monitor.update_all_prices()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(f&amp;quot;&amp;nbsp;&amp;nbsp;&amp;nbsp;更新完成:&amp;nbsp;{updated}&amp;nbsp;个商品&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;4.&amp;nbsp;生成报告
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(&amp;quot;\n4.&amp;nbsp;生成监控报告...&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;report&amp;nbsp;=&amp;nbsp;monitor.generate_report(7)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(f&amp;quot;&amp;nbsp;&amp;nbsp;&amp;nbsp;监控商品总数:&amp;nbsp;{report[&amp;#39;stats&amp;#39;][&amp;#39;total_products&amp;#39;]}&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(f&amp;quot;&amp;nbsp;&amp;nbsp;&amp;nbsp;平台数量:&amp;nbsp;{report[&amp;#39;stats&amp;#39;][&amp;#39;platforms&amp;#39;]}&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(f&amp;quot;&amp;nbsp;&amp;nbsp;&amp;nbsp;平均价格:&amp;nbsp;¥{report[&amp;#39;stats&amp;#39;][&amp;#39;avg_price&amp;#39;]}&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;5.&amp;nbsp;绘制价格图表
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(&amp;quot;\n5.&amp;nbsp;生成价格走势图...&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;monitor.plot_price_history(1,&amp;nbsp;&amp;#39;price_chart.png&amp;#39;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(&amp;quot;&amp;nbsp;&amp;nbsp;&amp;nbsp;📈&amp;nbsp;图表已生成:&amp;nbsp;price_chart.png&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;6.&amp;nbsp;关闭连接
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;monitor.close()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(&amp;quot;\n&amp;quot;&amp;nbsp;+&amp;nbsp;&amp;quot;=&amp;quot;&amp;nbsp;*&amp;nbsp;50)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(&amp;quot;🎯&amp;nbsp;监控系统已就绪！&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(&amp;quot;定时任务可以添加到cron或Windows任务计划&amp;quot;)&lt;/pre&gt;&lt;h3&gt;2. 自动化调度脚本&lt;/h3&gt;&lt;pre class=&quot;ybc-pre-component ybc-pre-component_not-math&quot;&gt;#&amp;nbsp;scheduler.py
import&amp;nbsp;schedule
import&amp;nbsp;time
from&amp;nbsp;datetime&amp;nbsp;import&amp;nbsp;datetime
from&amp;nbsp;price_monitor&amp;nbsp;import&amp;nbsp;PriceMonitor
import&amp;nbsp;logging
#&amp;nbsp;封装好API供应商demo&amp;nbsp;url=https://console.open.onebound.cn/console/?i=Lex
def&amp;nbsp;job():
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;定时执行的价格更新任务&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(f&amp;quot;\n{&amp;#39;=&amp;#39;*50}&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(f&amp;quot;🕐&amp;nbsp;开始执行定时任务:&amp;nbsp;{datetime.now().strftime(&amp;#39;%Y-%m-%d&amp;nbsp;%H:%M:%S&amp;#39;)}&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;monitor&amp;nbsp;=&amp;nbsp;PriceMonitor()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;更新所有价格
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;updated&amp;nbsp;=&amp;nbsp;monitor.update_all_prices()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;生成报告
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;report&amp;nbsp;=&amp;nbsp;monitor.generate_report(1)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(f&amp;quot;✅&amp;nbsp;任务完成:&amp;nbsp;更新&amp;nbsp;{updated}&amp;nbsp;个商品&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(f&amp;quot;&amp;nbsp;&amp;nbsp;&amp;nbsp;今日最佳优惠:&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;deal&amp;nbsp;in&amp;nbsp;report.get(&amp;#39;best_deals&amp;#39;,&amp;nbsp;[])[:3]:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(f&amp;quot;&amp;nbsp;&amp;nbsp;&amp;nbsp;-&amp;nbsp;{deal[&amp;#39;name&amp;#39;]}:&amp;nbsp;¥{deal[&amp;#39;current&amp;#39;]}&amp;nbsp;(最低¥{deal[&amp;#39;lowest&amp;#39;]})&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;except&amp;nbsp;Exception&amp;nbsp;as&amp;nbsp;e:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(f&amp;quot;❌&amp;nbsp;任务失败:&amp;nbsp;{e}&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;finally:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;monitor.close()

if&amp;nbsp;__name__&amp;nbsp;==&amp;nbsp;&amp;quot;__main__&amp;quot;:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(&amp;quot;⏰&amp;nbsp;价格监控定时任务启动&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(&amp;quot;每天&amp;nbsp;9:00,&amp;nbsp;12:00,&amp;nbsp;15:00,&amp;nbsp;18:00,&amp;nbsp;21:00&amp;nbsp;自动检查价格&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;设置定时任务
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;schedule.every().day.at(&amp;quot;09:00&amp;quot;).do(job)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;schedule.every().day.at(&amp;quot;12:00&amp;quot;).do(job)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;schedule.every().day.at(&amp;quot;15:00&amp;quot;).do(job)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;schedule.every().day.at(&amp;quot;18:00&amp;quot;).do(job)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;schedule.every().day.at(&amp;quot;21:00&amp;quot;).do(job)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;立即执行一次
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;job()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;保持运行
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;while&amp;nbsp;True:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;schedule.run_pending()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;time.sleep(60)&amp;nbsp;&amp;nbsp;#&amp;nbsp;每分钟检查一次&lt;/pre&gt;&lt;h3&gt;3. 网页可视化界面（可选）&lt;/h3&gt;&lt;pre class=&quot;ybc-pre-component ybc-pre-component_not-math&quot;&gt;#&amp;nbsp;web_dashboard.py
from&amp;nbsp;flask&amp;nbsp;import&amp;nbsp;Flask,&amp;nbsp;render_template,&amp;nbsp;jsonify,&amp;nbsp;request
import&amp;nbsp;json
from&amp;nbsp;price_monitor&amp;nbsp;import&amp;nbsp;PriceMonitor
import&amp;nbsp;plotly.graph_objects&amp;nbsp;as&amp;nbsp;go
import&amp;nbsp;plotly.utils
import&amp;nbsp;pandas&amp;nbsp;as&amp;nbsp;pd

app&amp;nbsp;=&amp;nbsp;Flask(__name__)
monitor&amp;nbsp;=&amp;nbsp;PriceMonitor()

@app.route(&amp;#39;/&amp;#39;)
def&amp;nbsp;index():
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;首页&amp;nbsp;-&amp;nbsp;显示监控看板&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;render_template(&amp;#39;dashboard.html&amp;#39;)

@app.route(&amp;#39;/api/products&amp;#39;)
def&amp;nbsp;get_products():
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;获取所有监控商品&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;monitor.cursor.execute(&amp;#39;&amp;#39;&amp;#39;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SELECT&amp;nbsp;id,&amp;nbsp;name,&amp;nbsp;url,&amp;nbsp;platform,&amp;nbsp;current_price,&amp;nbsp;lowest_price,&amp;nbsp;highest_price,&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;updated_at,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ROUND((current_price&amp;nbsp;-&amp;nbsp;lowest_price)&amp;nbsp;/&amp;nbsp;lowest_price&amp;nbsp;*&amp;nbsp;100,&amp;nbsp;1)&amp;nbsp;as&amp;nbsp;discount_pct
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;FROM&amp;nbsp;products
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ORDER&amp;nbsp;BY&amp;nbsp;updated_at&amp;nbsp;DESC
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;&amp;#39;&amp;#39;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;products&amp;nbsp;=&amp;nbsp;[]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;row&amp;nbsp;in&amp;nbsp;monitor.cursor.fetchall():
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;products.append({
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;id&amp;#39;:&amp;nbsp;row[0],
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;name&amp;#39;:&amp;nbsp;row[1],
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;url&amp;#39;:&amp;nbsp;row[2],
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;platform&amp;#39;:&amp;nbsp;row[3],
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;current_price&amp;#39;:&amp;nbsp;row[4],
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;lowest_price&amp;#39;:&amp;nbsp;row[5],
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;highest_price&amp;#39;:&amp;nbsp;row[6],
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;updated_at&amp;#39;:&amp;nbsp;row[7],
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;discount_pct&amp;#39;:&amp;nbsp;row[8],
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;is_best_price&amp;#39;:&amp;nbsp;row[4]&amp;nbsp;&amp;lt;=&amp;nbsp;row[5]&amp;nbsp;*&amp;nbsp;1.05&amp;nbsp;&amp;nbsp;#&amp;nbsp;接近最低价5%以内
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;})
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;jsonify(products)

@app.route(&amp;#39;/api/price_history/&amp;lt;int:product_id&amp;gt;&amp;#39;)
def&amp;nbsp;get_price_history(product_id):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;获取价格历史&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;monitor.cursor.execute(&amp;#39;&amp;#39;&amp;#39;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SELECT&amp;nbsp;price,&amp;nbsp;timestamp&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;FROM&amp;nbsp;price_history&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;WHERE&amp;nbsp;product_id&amp;nbsp;=&amp;nbsp;?
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ORDER&amp;nbsp;BY&amp;nbsp;timestamp
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;&amp;#39;&amp;#39;,&amp;nbsp;(product_id,))
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;data&amp;nbsp;=&amp;nbsp;monitor.cursor.fetchall()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;转换为Plotly图表数据
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;prices&amp;nbsp;=&amp;nbsp;[row[0]&amp;nbsp;for&amp;nbsp;row&amp;nbsp;in&amp;nbsp;data]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;timestamps&amp;nbsp;=&amp;nbsp;[row[1]&amp;nbsp;for&amp;nbsp;row&amp;nbsp;in&amp;nbsp;data]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;fig&amp;nbsp;=&amp;nbsp;go.Figure(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;data=go.Scatter(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;x=timestamps,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;y=prices,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;mode=&amp;#39;lines+markers&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;name=&amp;#39;价格走势&amp;#39;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;fig.update_layout(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;title=&amp;#39;价格历史走势&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;xaxis_title=&amp;#39;时间&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;yaxis_title=&amp;#39;价格&amp;nbsp;(¥)&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;template=&amp;#39;plotly_white&amp;#39;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;json.dumps(fig,&amp;nbsp;cls=plotly.utils.PlotlyJSONEncoder)

@app.route(&amp;#39;/api/add_product&amp;#39;,&amp;nbsp;methods=[&amp;#39;POST&amp;#39;])
def&amp;nbsp;add_product():
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;添加新商品&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;data&amp;nbsp;=&amp;nbsp;request.json
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;url&amp;nbsp;=&amp;nbsp;data.get(&amp;#39;url&amp;#39;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;name&amp;nbsp;=&amp;nbsp;data.get(&amp;#39;name&amp;#39;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;not&amp;nbsp;url:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;jsonify({&amp;#39;error&amp;#39;:&amp;nbsp;&amp;#39;URL不能为空&amp;#39;}),&amp;nbsp;400
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;product_id&amp;nbsp;=&amp;nbsp;monitor.add_product(url,&amp;nbsp;name)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;product_id:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;jsonify({&amp;#39;success&amp;#39;:&amp;nbsp;True,&amp;nbsp;&amp;#39;product_id&amp;#39;:&amp;nbsp;product_id})
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;jsonify({&amp;#39;error&amp;#39;:&amp;nbsp;&amp;#39;添加失败&amp;#39;}),&amp;nbsp;500

@app.route(&amp;#39;/api/update_prices&amp;#39;)
def&amp;nbsp;update_prices():
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;手动更新价格&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;updated&amp;nbsp;=&amp;nbsp;monitor.update_all_prices()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;jsonify({&amp;#39;success&amp;#39;:&amp;nbsp;True,&amp;nbsp;&amp;#39;updated&amp;#39;:&amp;nbsp;updated})

if&amp;nbsp;__name__&amp;nbsp;==&amp;nbsp;&amp;#39;__main__&amp;#39;:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;app.run(debug=True,&amp;nbsp;port=5000)&lt;/pre&gt;&lt;hr/&gt;&lt;h2&gt;三、 部署指南：3分钟快速上手&lt;/h2&gt;&lt;h3&gt;步骤1：安装依赖&lt;/h3&gt;&lt;pre class=&quot;ybc-pre-component ybc-pre-component_not-math&quot;&gt;pip&amp;nbsp;install&amp;nbsp;requests&amp;nbsp;pandas&amp;nbsp;matplotlib&amp;nbsp;flask&amp;nbsp;plotly&amp;nbsp;schedule&lt;/pre&gt;&lt;h3&gt;步骤2：创建配置文件&lt;/h3&gt;&lt;pre class=&quot;ybc-pre-component ybc-pre-component_not-math&quot;&gt;#&amp;nbsp;config.py
#&amp;nbsp;邮件提醒配置（可选）
EMAIL_CONFIG&amp;nbsp;=&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;smtp_server&amp;#39;:&amp;nbsp;&amp;#39;smtp.163.com&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;smtp_port&amp;#39;:&amp;nbsp;465,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;sender&amp;#39;:&amp;nbsp;&amp;#39;your_email@163.com&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;password&amp;#39;:&amp;nbsp;&amp;#39;your_password&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;receivers&amp;#39;:&amp;nbsp;[&amp;#39;your_email@163.com&amp;#39;]
}

#&amp;nbsp;监控频率
CHECK_INTERVALS&amp;nbsp;=&amp;nbsp;[&amp;#39;09:00&amp;#39;,&amp;nbsp;&amp;#39;12:00&amp;#39;,&amp;nbsp;&amp;#39;15:00&amp;#39;,&amp;nbsp;&amp;#39;18:00&amp;#39;,&amp;nbsp;&amp;#39;21:00&amp;#39;]&lt;/pre&gt;&lt;h3&gt;步骤3：添加你的商品&lt;/h3&gt;&lt;pre class=&quot;ybc-pre-component ybc-pre-component_not-math&quot;&gt;#&amp;nbsp;my_products.py
MY_PRODUCTS&amp;nbsp;=&amp;nbsp;[
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;淘宝/天猫
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;https://item.taobao.com/item.htm?id=674904123402&amp;quot;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;京东
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;https://item.jd.com/100008348542.html&amp;quot;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;拼多多
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;https://mobile.yangkeduo.com/goods.html?goods_id=123456789&amp;quot;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;添加更多...
]&lt;/pre&gt;&lt;h3&gt;步骤4：运行监控&lt;/h3&gt;&lt;pre class=&quot;ybc-pre-component ybc-pre-component_not-math&quot;&gt;#&amp;nbsp;一次性运行
python&amp;nbsp;price_monitor.py

#&amp;nbsp;定时运行（后台）
nohup&amp;nbsp;python&amp;nbsp;scheduler.py&amp;nbsp;&amp;gt;&amp;nbsp;monitor.log&amp;nbsp;2&amp;gt;&amp;amp;1&amp;nbsp;&amp;amp;

#&amp;nbsp;网页看板
python&amp;nbsp;web_dashboard.py&lt;/pre&gt;&lt;hr/&gt;&lt;h2&gt;四、 高级功能扩展&lt;/h2&gt;&lt;h3&gt;1. 微信/钉钉机器人提醒&lt;/h3&gt;&lt;pre class=&quot;ybc-pre-component ybc-pre-component_not-math&quot;&gt;def&amp;nbsp;send_wechat_alert(message:&amp;nbsp;str):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;发送微信机器人提醒&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;webhook_url&amp;nbsp;=&amp;nbsp;&amp;quot;https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=YOUR_KEY&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;data&amp;nbsp;=&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;msgtype&amp;quot;:&amp;nbsp;&amp;quot;text&amp;quot;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;text&amp;quot;:&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;content&amp;quot;:&amp;nbsp;f&amp;quot;🔔&amp;nbsp;价格提醒\n{message}\n{datetime.now().strftime(&amp;#39;%H:%M&amp;#39;)}&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;requests.post(webhook_url,&amp;nbsp;json=data)

def&amp;nbsp;send_dingtalk_alert(message:&amp;nbsp;str):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;发送钉钉机器人提醒&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;webhook_url&amp;nbsp;=&amp;nbsp;&amp;quot;https://oapi.dingtalk.com/robot/send?access_token=YOUR_TOKEN&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;data&amp;nbsp;=&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;msgtype&amp;quot;:&amp;nbsp;&amp;quot;text&amp;quot;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;text&amp;quot;:&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;content&amp;quot;:&amp;nbsp;f&amp;quot;价格提醒:&amp;nbsp;{message}&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;},
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;at&amp;quot;:&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;atMobiles&amp;quot;:&amp;nbsp;[&amp;quot;13800138000&amp;quot;],&amp;nbsp;&amp;nbsp;#&amp;nbsp;@某人
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;isAtAll&amp;quot;:&amp;nbsp;False
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;requests.post(webhook_url,&amp;nbsp;json=data)&lt;/pre&gt;&lt;h3&gt;2. 智能比价推荐&lt;/h3&gt;&lt;pre class=&quot;ybc-pre-component ybc-pre-component_not-math&quot;&gt;def&amp;nbsp;find_best_deal(product_name:&amp;nbsp;str,&amp;nbsp;platform:&amp;nbsp;str&amp;nbsp;=&amp;nbsp;None)&amp;nbsp;-&amp;gt;&amp;nbsp;Dict:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;智能比价推荐&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;1.&amp;nbsp;搜索同款商品
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;search_urls&amp;nbsp;=&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;taobao&amp;#39;:&amp;nbsp;f&amp;#39;https://s.taobao.com/search?q={quote(product_name)}&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;jd&amp;#39;:&amp;nbsp;f&amp;#39;https://search.jd.com/Search?keyword={quote(product_name)}&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;best_deal&amp;nbsp;=&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;platform&amp;#39;:&amp;nbsp;&amp;#39;&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;price&amp;#39;:&amp;nbsp;float(&amp;#39;inf&amp;#39;),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;url&amp;#39;:&amp;nbsp;&amp;#39;&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;title&amp;#39;:&amp;nbsp;&amp;#39;&amp;#39;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;platform,&amp;nbsp;url&amp;nbsp;in&amp;nbsp;search_urls.items():
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;获取搜索结果页面
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;解析多个商品价格
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;找到最低价
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;price&amp;nbsp;&amp;lt;&amp;nbsp;best_deal[&amp;#39;price&amp;#39;]:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;best_deal.update({
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;platform&amp;#39;:&amp;nbsp;platform,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;price&amp;#39;:&amp;nbsp;price,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;url&amp;#39;:&amp;nbsp;item_url,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;title&amp;#39;:&amp;nbsp;title
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;})
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;best_deal&lt;/pre&gt;&lt;h3&gt;3. 反爬虫策略增强&lt;/h3&gt;&lt;pre class=&quot;ybc-pre-component ybc-pre-component_not-math&quot;&gt;def&amp;nbsp;rotate_proxies():
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;轮换代理IP&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;proxies&amp;nbsp;=&amp;nbsp;[
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;http://proxy1.com:8080&amp;quot;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;http://proxy2.com:8080&amp;quot;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;更多代理...
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;random.choice(proxies)

def&amp;nbsp;use_selenium_for_js():
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;使用Selenium处理JavaScript渲染&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;from&amp;nbsp;selenium&amp;nbsp;import&amp;nbsp;webdriver
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;from&amp;nbsp;selenium.webdriver.chrome.options&amp;nbsp;import&amp;nbsp;Options
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;options&amp;nbsp;=&amp;nbsp;Options()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;options.add_argument(&amp;#39;--headless&amp;#39;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;options.add_argument(&amp;#39;--disable-blink-features=AutomationControlled&amp;#39;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;driver&amp;nbsp;=&amp;nbsp;webdriver.Chrome(options=options)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;driver.get(url)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;等待页面加载
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;time.sleep(2)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;获取完整页面
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;html&amp;nbsp;=&amp;nbsp;driver.page_source
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;driver.quit()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;html&lt;/pre&gt;&lt;hr/&gt;&lt;h2&gt;五、 注意事项与法律合规&lt;/h2&gt;&lt;h3&gt;✅ 允许的行为：&lt;/h3&gt;&lt;ol class=&quot;ybc-ol-component ybc-ol-component_1 list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;监控&lt;strong&gt;自己购买意愿&lt;/strong&gt;的商品&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;合理频率（每天几次）&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;用于&lt;strong&gt;个人决策参考&lt;/strong&gt;&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;h3&gt;⚠️ 禁止的行为：&lt;/h3&gt;&lt;ol class=&quot;ybc-ol-component ybc-ol-component_1 list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;大规模采集（可能违反网站Robots协议）&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;用于商业竞争&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;影响网站正常运营&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;绕过付费API&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;h3&gt;📊 建议策略：&lt;/h3&gt;&lt;ol class=&quot;ybc-ol-component ybc-ol-component_1 list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;设置合理的延迟（&lt;code class=&quot;hyc-common-markdown__code__inline&quot;&gt;time.sleep(1-3)&lt;/code&gt;秒）&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;使用随机User-Agent&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;遵守robots.txt&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;考虑使用官方API（如有）&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;hr/&gt;&lt;h2&gt;💡 最后建议&lt;/h2&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;立即行动清单&lt;/strong&gt;：&lt;/div&gt;&lt;ol class=&quot;ybc-ol-component ybc-ol-component_1 list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;[ ] 安装Python和依赖库&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;[ ] 复制上面的核心代码&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;[ ] 添加3个你最想监控的商品&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;[ ] 运行一次，看看效果&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;[ ] 设置定时任务，忘记比价烦恼&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;记住&lt;/strong&gt;：这个工具的价值不在于技术多复杂，而在于帮你&lt;strong&gt;节省的时间和抓住的机会&lt;/strong&gt;。一次大促省下的钱，可能就值回你学习Python的投入了。&lt;/div&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;互动话题&lt;/strong&gt;：你最想监控什么商品的价格？是电子产品、化妆品还是母婴用品？评论区聊聊，我可以给你针对性的采集建议！&lt;/div&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;</description><pubDate>Mon, 25 May 2026 16:27:13 +0800</pubDate></item><item><title>🔥 从1688接口设计，学习高可用API的最佳实践（附Python源码）</title><link>https://alexob.com/?id=374</link><description>&lt;h1&gt;&lt;span style=&quot;font-size: 14px;&quot;&gt;1688作为阿里巴巴B2B核心平台，日均处理数十亿API请求，其接口设计堪称&lt;/span&gt;&lt;strong style=&quot;font-size: 14px;&quot;&gt;工业级高可用API的教科书&lt;/strong&gt;&lt;span style=&quot;font-size: 14px;&quot;&gt;。本文将深入剖析1688接口设计精髓，并提供可直接用于生产环境的Python高可用API实现。&lt;/span&gt;&lt;br/&gt;&lt;/h1&gt;&lt;hr/&gt;&lt;h2&gt;一、 1688 API 高可用设计的四大支柱&lt;/h2&gt;&lt;pre class=&quot;ybc-pre-component ybc-pre-component_not-math&quot;&gt;graph&amp;nbsp;TD
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;A[高可用API]&amp;nbsp;--&amp;gt;&amp;nbsp;B[容错设计]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;A&amp;nbsp;--&amp;gt;&amp;nbsp;C[性能优化]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;A&amp;nbsp;--&amp;gt;&amp;nbsp;D[安全保障]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;A&amp;nbsp;--&amp;gt;&amp;nbsp;E[运维监控]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;B&amp;nbsp;--&amp;gt;&amp;nbsp;B1[熔断降级]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;B&amp;nbsp;--&amp;gt;&amp;nbsp;B2[重试策略]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;B&amp;nbsp;--&amp;gt;&amp;nbsp;B3[超时控制]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;C&amp;nbsp;--&amp;gt;&amp;nbsp;C1[缓存策略]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;C&amp;nbsp;--&amp;gt;&amp;nbsp;C2[连接池]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;C&amp;nbsp;--&amp;gt;&amp;nbsp;C3[异步处理]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;D&amp;nbsp;--&amp;gt;&amp;nbsp;D1[签名验证]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;D&amp;nbsp;--&amp;gt;&amp;nbsp;D2[限流防护]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;D&amp;nbsp;--&amp;gt;&amp;nbsp;D3[权限控制]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;E&amp;nbsp;--&amp;gt;&amp;nbsp;E1[监控告警]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;E&amp;nbsp;--&amp;gt;&amp;nbsp;E2[日志追踪]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;E&amp;nbsp;--&amp;gt;&amp;nbsp;E3[动态配置]&lt;/pre&gt;&lt;hr/&gt;&lt;h2&gt;二、 核心设计模式源码实现&lt;/h2&gt;&lt;h3&gt;模式1：智能重试与熔断器&lt;/h3&gt;&lt;div class=&quot;ybc-p&quot;&gt;1688接口在调用失败时不会立即返回错误，而是通过&lt;strong&gt;指数退避重试&lt;/strong&gt;和&lt;strong&gt;熔断机制&lt;/strong&gt;保证服务韧性。&lt;/div&gt;&lt;pre class=&quot;ybc-pre-component ybc-pre-component_not-math&quot;&gt;#&amp;nbsp;circuit_breaker.py
import&amp;nbsp;time
import&amp;nbsp;random
from&amp;nbsp;datetime&amp;nbsp;import&amp;nbsp;datetime,&amp;nbsp;timedelta
from&amp;nbsp;typing&amp;nbsp;import&amp;nbsp;Callable,&amp;nbsp;Any,&amp;nbsp;Optional
from&amp;nbsp;enum&amp;nbsp;import&amp;nbsp;Enum
import&amp;nbsp;logging
from&amp;nbsp;dataclasses&amp;nbsp;import&amp;nbsp;dataclass
import&amp;nbsp;functools
#&amp;nbsp;封装好API供应商demo&amp;nbsp;url=https://console.open.onebound.cn/console/?i=Lex
class&amp;nbsp;CircuitState(Enum):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;CLOSED&amp;nbsp;=&amp;nbsp;&amp;quot;closed&amp;quot;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;正常状态
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;OPEN&amp;nbsp;=&amp;nbsp;&amp;quot;open&amp;quot;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;熔断状态
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;HALF_OPEN&amp;nbsp;=&amp;nbsp;&amp;quot;half_open&amp;quot;&amp;nbsp;#&amp;nbsp;半开状态

@dataclass
class&amp;nbsp;CircuitBreakerConfig:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;熔断器配置&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;failure_threshold:&amp;nbsp;int&amp;nbsp;=&amp;nbsp;5&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;失败阈值
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;reset_timeout:&amp;nbsp;int&amp;nbsp;=&amp;nbsp;60&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;熔断恢复时间(秒)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;half_open_max_calls:&amp;nbsp;int&amp;nbsp;=&amp;nbsp;3&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;半开状态最大尝试次数
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;failure_window:&amp;nbsp;int&amp;nbsp;=&amp;nbsp;10&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;统计窗口(秒)

class&amp;nbsp;CircuitBreaker:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;智能熔断器（模仿1688接口容错）&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;__init__(self,&amp;nbsp;name:&amp;nbsp;str,&amp;nbsp;config:&amp;nbsp;CircuitBreakerConfig&amp;nbsp;=&amp;nbsp;None):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.name&amp;nbsp;=&amp;nbsp;name
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.config&amp;nbsp;=&amp;nbsp;config&amp;nbsp;or&amp;nbsp;CircuitBreakerConfig()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.state&amp;nbsp;=&amp;nbsp;CircuitState.CLOSED
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.failure_count&amp;nbsp;=&amp;nbsp;0
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.last_failure_time:&amp;nbsp;Optional[datetime]&amp;nbsp;=&amp;nbsp;None
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.success_count&amp;nbsp;=&amp;nbsp;0
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.last_state_change&amp;nbsp;=&amp;nbsp;datetime.now()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;失败时间窗口
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.failure_timestamps&amp;nbsp;=&amp;nbsp;[]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.logger&amp;nbsp;=&amp;nbsp;logging.getLogger(f&amp;quot;CircuitBreaker.{name}&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;call(self,&amp;nbsp;func:&amp;nbsp;Callable,&amp;nbsp;*args,&amp;nbsp;**kwargs)&amp;nbsp;-&amp;gt;&amp;nbsp;Any:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;执行受保护的方法&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;检查是否应该熔断
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;self.state&amp;nbsp;==&amp;nbsp;CircuitState.OPEN:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;self._should_try_reset():
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.state&amp;nbsp;=&amp;nbsp;CircuitState.HALF_OPEN
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.logger.info(f&amp;quot;🟡&amp;nbsp;熔断器&amp;nbsp;{self.name}&amp;nbsp;进入半开状态&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;raise&amp;nbsp;CircuitBreakerError(f&amp;quot;Circuit&amp;nbsp;breaker&amp;nbsp;&amp;#39;{self.name}&amp;#39;&amp;nbsp;is&amp;nbsp;OPEN&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;执行原函数
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;result&amp;nbsp;=&amp;nbsp;func(*args,&amp;nbsp;**kwargs)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;成功调用
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self._on_success()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;result
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;except&amp;nbsp;Exception&amp;nbsp;as&amp;nbsp;e:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;调用失败
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self._on_failure()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;特殊异常不触发熔断
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;isinstance(e,&amp;nbsp;(BusinessError,&amp;nbsp;ValidationError)):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;raise
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;判断是否应该熔断
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;self.state&amp;nbsp;==&amp;nbsp;CircuitState.HALF_OPEN&amp;nbsp;or&amp;nbsp;self._should_open():
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.state&amp;nbsp;=&amp;nbsp;CircuitState.OPEN
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.last_state_change&amp;nbsp;=&amp;nbsp;datetime.now()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.logger.error(f&amp;quot;🔴&amp;nbsp;熔断器&amp;nbsp;{self.name}&amp;nbsp;触发熔断&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;raise
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;_on_success(self):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;调用成功处理&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;self.state&amp;nbsp;==&amp;nbsp;CircuitState.HALF_OPEN:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.success_count&amp;nbsp;+=&amp;nbsp;1
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;self.success_count&amp;nbsp;&amp;gt;=&amp;nbsp;self.config.half_open_max_calls:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self._reset()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;清空失败计数
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.failure_count&amp;nbsp;=&amp;nbsp;0
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.failure_timestamps.clear()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;_on_failure(self):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;调用失败处理&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;now&amp;nbsp;=&amp;nbsp;datetime.now()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;记录失败时间
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.failure_timestamps.append(now)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;清理过期的失败记录
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cutoff&amp;nbsp;=&amp;nbsp;now&amp;nbsp;-&amp;nbsp;timedelta(seconds=self.config.failure_window)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.failure_timestamps&amp;nbsp;=&amp;nbsp;[
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ts&amp;nbsp;for&amp;nbsp;ts&amp;nbsp;in&amp;nbsp;self.failure_timestamps&amp;nbsp;if&amp;nbsp;ts&amp;nbsp;&amp;gt;&amp;nbsp;cutoff
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;更新失败计数
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.failure_count&amp;nbsp;=&amp;nbsp;len(self.failure_timestamps)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.last_failure_time&amp;nbsp;=&amp;nbsp;now
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;_should_open(self)&amp;nbsp;-&amp;gt;&amp;nbsp;bool:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;判断是否应该熔断&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;基于时间窗口的失败率
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;len(self.failure_timestamps)&amp;nbsp;&amp;gt;=&amp;nbsp;self.config.failure_threshold:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;True
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;检查失败阈值
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;self.failure_count&amp;nbsp;&amp;gt;=&amp;nbsp;self.config.failure_threshold:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;True
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;False
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;_should_try_reset(self)&amp;nbsp;-&amp;gt;&amp;nbsp;bool:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;判断是否应该尝试恢复&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;self.state&amp;nbsp;!=&amp;nbsp;CircuitState.OPEN:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;False
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;time_since_open&amp;nbsp;=&amp;nbsp;(datetime.now()&amp;nbsp;-&amp;nbsp;self.last_state_change).total_seconds()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;time_since_open&amp;nbsp;&amp;gt;=&amp;nbsp;self.config.reset_timeout
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;_reset(self):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;重置熔断器&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.state&amp;nbsp;=&amp;nbsp;CircuitState.CLOSED
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.failure_count&amp;nbsp;=&amp;nbsp;0
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.success_count&amp;nbsp;=&amp;nbsp;0
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.failure_timestamps.clear()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.last_state_change&amp;nbsp;=&amp;nbsp;datetime.now()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.logger.info(f&amp;quot;🟢&amp;nbsp;熔断器&amp;nbsp;{self.name}&amp;nbsp;重置关闭&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;get_status(self)&amp;nbsp;-&amp;gt;&amp;nbsp;dict:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;获取熔断器状态&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;name&amp;quot;:&amp;nbsp;self.name,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;state&amp;quot;:&amp;nbsp;self.state.value,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;failure_count&amp;quot;:&amp;nbsp;self.failure_count,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;success_count&amp;quot;:&amp;nbsp;self.success_count,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;last_failure&amp;quot;:&amp;nbsp;self.last_failure_time.isoformat()&amp;nbsp;if&amp;nbsp;self.last_failure_time&amp;nbsp;else&amp;nbsp;None,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;open_since&amp;quot;:&amp;nbsp;self.last_state_change.isoformat()&amp;nbsp;if&amp;nbsp;self.state&amp;nbsp;==&amp;nbsp;CircuitState.OPEN&amp;nbsp;else&amp;nbsp;None
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

class&amp;nbsp;SmartRetry:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;智能重试策略（带指数退避和抖动）&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;__init__(self,&amp;nbsp;max_retries=3,&amp;nbsp;base_delay=1.0,&amp;nbsp;max_delay=10.0):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.max_retries&amp;nbsp;=&amp;nbsp;max_retries
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.base_delay&amp;nbsp;=&amp;nbsp;base_delay
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.max_delay&amp;nbsp;=&amp;nbsp;max_delay
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;封装好API供应商demo&amp;nbsp;url=https://console.open.onebound.cn/console/?i=Lex
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;__call__(self,&amp;nbsp;func:&amp;nbsp;Callable)&amp;nbsp;-&amp;gt;&amp;nbsp;Callable:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@functools.wraps(func)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;wrapper(*args,&amp;nbsp;**kwargs):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;last_exception&amp;nbsp;=&amp;nbsp;None
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;attempt&amp;nbsp;in&amp;nbsp;range(self.max_retries&amp;nbsp;+&amp;nbsp;1):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;func(*args,&amp;nbsp;**kwargs)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;except&amp;nbsp;(RetryableError,&amp;nbsp;TimeoutError,&amp;nbsp;ConnectionError)&amp;nbsp;as&amp;nbsp;e:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;last_exception&amp;nbsp;=&amp;nbsp;e
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;最后一次重试，直接抛出异常
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;attempt&amp;nbsp;==&amp;nbsp;self.max_retries:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;break
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;计算退避时间（指数退避&amp;nbsp;+&amp;nbsp;随机抖动）
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;delay&amp;nbsp;=&amp;nbsp;self._calculate_delay(attempt)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;记录重试日志
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;logging.warning(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;f&amp;quot;🔄&amp;nbsp;重试&amp;nbsp;{func.__name__},&amp;nbsp;尝试&amp;nbsp;{attempt&amp;nbsp;+&amp;nbsp;1}/{self.max_retries},&amp;nbsp;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;f&amp;quot;延迟&amp;nbsp;{delay:.2f}s,&amp;nbsp;错误:&amp;nbsp;{e}&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;time.sleep(delay)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;except&amp;nbsp;Exception&amp;nbsp;as&amp;nbsp;e:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;非重试异常直接抛出
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;raise
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;所有重试都失败
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;raise&amp;nbsp;MaxRetriesExceeded(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;f&amp;quot;函数&amp;nbsp;{func.__name__}&amp;nbsp;在&amp;nbsp;{self.max_retries}&amp;nbsp;次重试后失败&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)&amp;nbsp;from&amp;nbsp;last_exception
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;wrapper
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;_calculate_delay(self,&amp;nbsp;attempt:&amp;nbsp;int)&amp;nbsp;-&amp;gt;&amp;nbsp;float:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;计算重试延迟&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;指数退避:&amp;nbsp;base&amp;nbsp;*&amp;nbsp;2^attempt
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;exponential_delay&amp;nbsp;=&amp;nbsp;self.base_delay&amp;nbsp;*&amp;nbsp;(2&amp;nbsp;**&amp;nbsp;attempt)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;随机抖动:&amp;nbsp;±20%
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;jitter&amp;nbsp;=&amp;nbsp;random.uniform(0.8,&amp;nbsp;1.2)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;限制最大延迟
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;delay&amp;nbsp;=&amp;nbsp;min(exponential_delay&amp;nbsp;*&amp;nbsp;jitter,&amp;nbsp;self.max_delay)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;delay

#&amp;nbsp;使用示例
if&amp;nbsp;__name__&amp;nbsp;==&amp;nbsp;&amp;quot;__main__&amp;quot;:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;配置日志
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;logging.basicConfig(level=logging.INFO)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;1.&amp;nbsp;创建熔断器
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cb_config&amp;nbsp;=&amp;nbsp;CircuitBreakerConfig(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;failure_threshold=3,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;reset_timeout=30,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;half_open_max_calls=2
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;circuit_breaker&amp;nbsp;=&amp;nbsp;CircuitBreaker(&amp;quot;ProductAPI&amp;quot;,&amp;nbsp;cb_config)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;2.&amp;nbsp;创建重试装饰器
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;retry&amp;nbsp;=&amp;nbsp;SmartRetry(max_retries=3,&amp;nbsp;base_delay=1.0)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;3.&amp;nbsp;模拟API调用函数
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@retry
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;call_external_api(should_fail:&amp;nbsp;bool&amp;nbsp;=&amp;nbsp;False):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;模拟调用外部API&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;should_fail:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;raise&amp;nbsp;ConnectionError(&amp;quot;API连接失败&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;{&amp;quot;status&amp;quot;:&amp;nbsp;&amp;quot;success&amp;quot;,&amp;nbsp;&amp;quot;data&amp;quot;:&amp;nbsp;&amp;quot;sample&amp;quot;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;4.&amp;nbsp;受保护的API调用
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;protected_api_call(should_fail:&amp;nbsp;bool&amp;nbsp;=&amp;nbsp;False):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;result&amp;nbsp;=&amp;nbsp;circuit_breaker.call(call_external_api,&amp;nbsp;should_fail)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(f&amp;quot;✅&amp;nbsp;API调用成功:&amp;nbsp;{result}&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;result
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;except&amp;nbsp;Exception&amp;nbsp;as&amp;nbsp;e:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(f&amp;quot;❌&amp;nbsp;API调用失败:&amp;nbsp;{e}&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;None
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;测试正常调用
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(&amp;quot;1.&amp;nbsp;测试正常调用:&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;protected_api_call(should_fail=False)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;测试连续失败触发熔断
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(&amp;quot;\n2.&amp;nbsp;测试熔断触发:&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;i&amp;nbsp;in&amp;nbsp;range(5):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(f&amp;quot;&amp;nbsp;&amp;nbsp;尝试&amp;nbsp;{i+1}:&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;protected_api_call(should_fail=True)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(f&amp;quot;&amp;nbsp;&amp;nbsp;熔断器状态:&amp;nbsp;{circuit_breaker.get_status()}&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;time.sleep(0.5)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;等待熔断恢复
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(&amp;quot;\n3.&amp;nbsp;等待熔断恢复...&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;time.sleep(35)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;测试熔断恢复后的调用
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(&amp;quot;\n4.&amp;nbsp;测试恢复后调用:&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;protected_api_call(should_fail=False)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(f&amp;quot;&amp;nbsp;&amp;nbsp;最终状态:&amp;nbsp;{circuit_breaker.get_status()}&amp;quot;)&lt;/pre&gt;&lt;h3&gt;模式2：分层缓存策略&lt;/h3&gt;&lt;div class=&quot;ybc-p&quot;&gt;1688对商品、价格等高频访问数据采用&lt;strong&gt;多级缓存策略&lt;/strong&gt;，大幅降低数据库压力。&lt;/div&gt;&lt;pre class=&quot;ybc-pre-component ybc-pre-component_not-math&quot;&gt;#&amp;nbsp;layered_cache.py
import&amp;nbsp;time
import&amp;nbsp;hashlib
import&amp;nbsp;pickle
from&amp;nbsp;typing&amp;nbsp;import&amp;nbsp;Any,&amp;nbsp;Optional,&amp;nbsp;Callable
from&amp;nbsp;functools&amp;nbsp;import&amp;nbsp;wraps
from&amp;nbsp;dataclasses&amp;nbsp;import&amp;nbsp;dataclass
from&amp;nbsp;datetime&amp;nbsp;import&amp;nbsp;datetime,&amp;nbsp;timedelta
import&amp;nbsp;redis
import&amp;nbsp;threading
import&amp;nbsp;json
#&amp;nbsp;封装好API供应商demo&amp;nbsp;url=https://console.open.onebound.cn/console/?i=Lex
@dataclass
class&amp;nbsp;CacheConfig:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;缓存配置&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ttl:&amp;nbsp;int&amp;nbsp;=&amp;nbsp;300&amp;nbsp;&amp;nbsp;#&amp;nbsp;默认5分钟
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;max_size:&amp;nbsp;int&amp;nbsp;=&amp;nbsp;1000
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;enable_local:&amp;nbsp;bool&amp;nbsp;=&amp;nbsp;True
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;enable_redis:&amp;nbsp;bool&amp;nbsp;=&amp;nbsp;True
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;redis_ttl:&amp;nbsp;int&amp;nbsp;=&amp;nbsp;3600&amp;nbsp;&amp;nbsp;#&amp;nbsp;Redis缓存1小时

class&amp;nbsp;LayeredCache:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;分层缓存管理器（本地内存&amp;nbsp;+&amp;nbsp;Redis&amp;nbsp;+&amp;nbsp;数据库）&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;__init__(self,&amp;nbsp;redis_client=None,&amp;nbsp;namespace=&amp;quot;cache&amp;quot;):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;本地内存缓存
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.local_cache&amp;nbsp;=&amp;nbsp;{}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.local_lock&amp;nbsp;=&amp;nbsp;threading.RLock()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;Redis缓存
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.redis&amp;nbsp;=&amp;nbsp;redis_client
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.namespace&amp;nbsp;=&amp;nbsp;namespace
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;缓存统计
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.stats&amp;nbsp;=&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;local_hits&amp;quot;:&amp;nbsp;0,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;redis_hits&amp;quot;:&amp;nbsp;0,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;db_hits&amp;quot;:&amp;nbsp;0,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;total_requests&amp;quot;:&amp;nbsp;0
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;清理线程
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self._cleanup_thread&amp;nbsp;=&amp;nbsp;None
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self._running&amp;nbsp;=&amp;nbsp;False
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;get(self,&amp;nbsp;key:&amp;nbsp;str,&amp;nbsp;loader:&amp;nbsp;Callable&amp;nbsp;=&amp;nbsp;None,&amp;nbsp;config:&amp;nbsp;CacheConfig&amp;nbsp;=&amp;nbsp;None)&amp;nbsp;-&amp;gt;&amp;nbsp;Any:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;获取缓存数据&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.stats[&amp;quot;total_requests&amp;quot;]&amp;nbsp;+=&amp;nbsp;1
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;config&amp;nbsp;=&amp;nbsp;config&amp;nbsp;or&amp;nbsp;CacheConfig()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;1.&amp;nbsp;检查本地缓存
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;config.enable_local:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;with&amp;nbsp;self.local_lock:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;key&amp;nbsp;in&amp;nbsp;self.local_cache:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;entry&amp;nbsp;=&amp;nbsp;self.local_cache[key]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;entry[&amp;quot;expire_at&amp;quot;]&amp;nbsp;&amp;gt;&amp;nbsp;time.time():
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.stats[&amp;quot;local_hits&amp;quot;]&amp;nbsp;+=&amp;nbsp;1
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;entry[&amp;quot;value&amp;quot;]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;清理过期缓存
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;del&amp;nbsp;self.local_cache[key]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;2.&amp;nbsp;检查Redis缓存
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;config.enable_redis&amp;nbsp;and&amp;nbsp;self.redis:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;redis_key&amp;nbsp;=&amp;nbsp;f&amp;quot;{self.namespace}:{key}&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cached_data&amp;nbsp;=&amp;nbsp;self.redis.get(redis_key)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;cached_data:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;data&amp;nbsp;=&amp;nbsp;pickle.loads(cached_data)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;回写到本地缓存
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;config.enable_local:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self._set_local(key,&amp;nbsp;data,&amp;nbsp;config.ttl)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.stats[&amp;quot;redis_hits&amp;quot;]&amp;nbsp;+=&amp;nbsp;1
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;data
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;except:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pass
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;3.&amp;nbsp;调用加载器获取数据
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;loader:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;data&amp;nbsp;=&amp;nbsp;loader()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;写入所有缓存层
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;config.enable_local:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self._set_local(key,&amp;nbsp;data,&amp;nbsp;config.ttl)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;config.enable_redis&amp;nbsp;and&amp;nbsp;self.redis:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;redis_key&amp;nbsp;=&amp;nbsp;f&amp;quot;{self.namespace}:{key}&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.redis.setex(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;redis_key,&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;config.redis_ttl,&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pickle.dumps(data,&amp;nbsp;protocol=pickle.HIGHEST_PROTOCOL)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.stats[&amp;quot;db_hits&amp;quot;]&amp;nbsp;+=&amp;nbsp;1
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;data
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;None
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;_set_local(self,&amp;nbsp;key:&amp;nbsp;str,&amp;nbsp;value:&amp;nbsp;Any,&amp;nbsp;ttl:&amp;nbsp;int):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;设置本地缓存&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;with&amp;nbsp;self.local_lock:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;控制缓存大小
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;len(self.local_cache)&amp;nbsp;&amp;gt;=&amp;nbsp;1000:&amp;nbsp;&amp;nbsp;#&amp;nbsp;简单LRU
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;oldest_key&amp;nbsp;=&amp;nbsp;next(iter(self.local_cache))
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;del&amp;nbsp;self.local_cache[oldest_key]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.local_cache[key]&amp;nbsp;=&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;value&amp;quot;:&amp;nbsp;value,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;expire_at&amp;quot;:&amp;nbsp;time.time()&amp;nbsp;+&amp;nbsp;ttl,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;created_at&amp;quot;:&amp;nbsp;time.time()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;invalidate(self,&amp;nbsp;key:&amp;nbsp;str):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;使缓存失效&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;with&amp;nbsp;self.local_lock:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;key&amp;nbsp;in&amp;nbsp;self.local_cache:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;del&amp;nbsp;self.local_cache[key]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;self.redis:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;redis_key&amp;nbsp;=&amp;nbsp;f&amp;quot;{self.namespace}:{key}&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.redis.delete(redis_key)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;invalidate_pattern(self,&amp;nbsp;pattern:&amp;nbsp;str):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;批量使缓存失效&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;with&amp;nbsp;self.local_lock:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;清理本地缓存
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;keys_to_delete&amp;nbsp;=&amp;nbsp;[
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;k&amp;nbsp;for&amp;nbsp;k&amp;nbsp;in&amp;nbsp;self.local_cache.keys()&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;pattern&amp;nbsp;in&amp;nbsp;k
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;key&amp;nbsp;in&amp;nbsp;keys_to_delete:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;del&amp;nbsp;self.local_cache[key]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;清理Redis缓存
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;self.redis:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;redis_pattern&amp;nbsp;=&amp;nbsp;f&amp;quot;{self.namespace}:{pattern}*&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;keys&amp;nbsp;=&amp;nbsp;self.redis.keys(redis_pattern)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;keys:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.redis.delete(*keys)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;get_stats(self)&amp;nbsp;-&amp;gt;&amp;nbsp;dict:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;获取缓存统计&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;total&amp;nbsp;=&amp;nbsp;self.stats[&amp;quot;total_requests&amp;quot;]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;total&amp;nbsp;==&amp;nbsp;0:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;hit_rate&amp;nbsp;=&amp;nbsp;0
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;hit_rate&amp;nbsp;=&amp;nbsp;(self.stats[&amp;quot;local_hits&amp;quot;]&amp;nbsp;+&amp;nbsp;self.stats[&amp;quot;redis_hits&amp;quot;])&amp;nbsp;/&amp;nbsp;total
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;**self.stats,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;hit_rate&amp;quot;:&amp;nbsp;f&amp;quot;{hit_rate:.1%}&amp;quot;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;local_size&amp;quot;:&amp;nbsp;len(self.local_cache)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;start_cleanup(self,&amp;nbsp;interval=60):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;启动缓存清理线程&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self._running&amp;nbsp;=&amp;nbsp;True
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self._cleanup_thread&amp;nbsp;=&amp;nbsp;threading.Thread(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;target=self._cleanup_loop,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;args=(interval,),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;daemon=True
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self._cleanup_thread.start()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;stop_cleanup(self):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;停止清理线程&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self._running&amp;nbsp;=&amp;nbsp;False
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;self._cleanup_thread:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self._cleanup_thread.join(timeout=5)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;_cleanup_loop(self,&amp;nbsp;interval):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;清理过期缓存的循环&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;while&amp;nbsp;self._running:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;time.sleep(interval)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self._cleanup_expired()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;_cleanup_expired(self):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;清理过期缓存&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;now&amp;nbsp;=&amp;nbsp;time.time()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;with&amp;nbsp;self.local_lock:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;expired_keys&amp;nbsp;=&amp;nbsp;[
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;k&amp;nbsp;for&amp;nbsp;k,&amp;nbsp;v&amp;nbsp;in&amp;nbsp;self.local_cache.items()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;v[&amp;quot;expire_at&amp;quot;]&amp;nbsp;&amp;lt;=&amp;nbsp;now
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;key&amp;nbsp;in&amp;nbsp;expired_keys:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;del&amp;nbsp;self.local_cache[key]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;expired_keys:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(f&amp;quot;🧹&amp;nbsp;清理了&amp;nbsp;{len(expired_keys)}&amp;nbsp;个过期缓存&amp;quot;)

def&amp;nbsp;cache_decorator(ttl=300,&amp;nbsp;key_prefix=&amp;quot;&amp;quot;,&amp;nbsp;use_redis=True):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;缓存装饰器（模仿1688接口缓存）&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;decorator(func):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@wraps(func)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;wrapper(*args,&amp;nbsp;**kwargs):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;生成缓存键
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cache_key&amp;nbsp;=&amp;nbsp;_generate_cache_key(func,&amp;nbsp;args,&amp;nbsp;kwargs,&amp;nbsp;key_prefix)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;获取缓存管理器（单例）
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cache_manager&amp;nbsp;=&amp;nbsp;_get_cache_manager()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;配置
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;config&amp;nbsp;=&amp;nbsp;CacheConfig(ttl=ttl,&amp;nbsp;enable_redis=use_redis)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;定义数据加载器
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;loader():
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;func(*args,&amp;nbsp;**kwargs)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;从缓存获取或加载
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;cache_manager.get(cache_key,&amp;nbsp;loader,&amp;nbsp;config)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;wrapper
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;decorator

def&amp;nbsp;_generate_cache_key(func,&amp;nbsp;args,&amp;nbsp;kwargs,&amp;nbsp;prefix):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;生成缓存键&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;序列化参数
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;key_parts&amp;nbsp;=&amp;nbsp;[
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;prefix&amp;nbsp;or&amp;nbsp;func.__module__&amp;nbsp;+&amp;nbsp;&amp;quot;.&amp;quot;&amp;nbsp;+&amp;nbsp;func.__name__,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;str(args),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;str(sorted(kwargs.items()))
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;key_string&amp;nbsp;=&amp;nbsp;&amp;quot;:&amp;quot;.join(key_parts)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;使用MD5缩短键长度
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;hashlib.md5(key_string.encode()).hexdigest()

#&amp;nbsp;全局缓存管理器
_CACHE_MANAGER&amp;nbsp;=&amp;nbsp;None

def&amp;nbsp;_get_cache_manager():
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;获取缓存管理器单例&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;global&amp;nbsp;_CACHE_MANAGER
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;_CACHE_MANAGER&amp;nbsp;is&amp;nbsp;None:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;初始化Redis连接
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;redis_client&amp;nbsp;=&amp;nbsp;redis.Redis(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;host=&amp;#39;localhost&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;port=6379,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;db=0,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;decode_responses=False
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;测试连接
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;redis_client.ping()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;except:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;redis_client&amp;nbsp;=&amp;nbsp;None
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;_CACHE_MANAGER&amp;nbsp;=&amp;nbsp;LayeredCache(redis_client,&amp;nbsp;&amp;quot;api_cache&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;_CACHE_MANAGER.start_cleanup()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;_CACHE_MANAGER

#&amp;nbsp;使用示例
if&amp;nbsp;__name__&amp;nbsp;==&amp;nbsp;&amp;quot;__main__&amp;quot;:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;import&amp;nbsp;random
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;模拟数据库查询
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;class&amp;nbsp;ProductDB:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;__init__(self):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.query_count&amp;nbsp;=&amp;nbsp;0
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@cache_decorator(ttl=10,&amp;nbsp;key_prefix=&amp;quot;product&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;get_product(self,&amp;nbsp;product_id:&amp;nbsp;int):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;获取产品信息（模拟数据库查询）&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.query_count&amp;nbsp;+=&amp;nbsp;1
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(f&amp;quot;📊&amp;nbsp;查询数据库获取产品&amp;nbsp;{product_id}&amp;nbsp;(第{self.query_count}次)&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;模拟数据库查询延迟
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;time.sleep(0.1)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;id&amp;quot;:&amp;nbsp;product_id,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;name&amp;quot;:&amp;nbsp;f&amp;quot;产品{product_id}&amp;quot;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;price&amp;quot;:&amp;nbsp;random.uniform(10,&amp;nbsp;1000),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;stock&amp;quot;:&amp;nbsp;random.randint(0,&amp;nbsp;1000),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;updated_at&amp;quot;:&amp;nbsp;datetime.now().isoformat()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@cache_decorator(ttl=30,&amp;nbsp;key_prefix=&amp;quot;product_list&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;get_products(self,&amp;nbsp;category:&amp;nbsp;str,&amp;nbsp;page:&amp;nbsp;int&amp;nbsp;=&amp;nbsp;1):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;获取产品列表&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.query_count&amp;nbsp;+=&amp;nbsp;1
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(f&amp;quot;📊&amp;nbsp;查询数据库获取分类&amp;nbsp;{category}&amp;nbsp;第{page}页&amp;nbsp;(第{self.query_count}次)&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;time.sleep(0.2)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;[
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;id&amp;quot;:&amp;nbsp;i&amp;nbsp;+&amp;nbsp;(page-1)*10,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;name&amp;quot;:&amp;nbsp;f&amp;quot;{category}_产品{i}&amp;quot;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;price&amp;quot;:&amp;nbsp;random.uniform(10,&amp;nbsp;100)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;i&amp;nbsp;in&amp;nbsp;range(1,&amp;nbsp;11)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;测试
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;db&amp;nbsp;=&amp;nbsp;ProductDB()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cache_manager&amp;nbsp;=&amp;nbsp;_get_cache_manager()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(&amp;quot;1.&amp;nbsp;测试缓存命中:&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;_&amp;nbsp;in&amp;nbsp;range(5):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;product&amp;nbsp;=&amp;nbsp;db.get_product(123)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(f&amp;quot;&amp;nbsp;&amp;nbsp;产品:&amp;nbsp;{product[&amp;#39;name&amp;#39;]},&amp;nbsp;价格:&amp;nbsp;{product[&amp;#39;price&amp;#39;]:.2f}&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;time.sleep(1)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(&amp;quot;\n2.&amp;nbsp;测试缓存失效:&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;手动使缓存失效
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cache_manager.invalidate_pattern(&amp;quot;product:123&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;product&amp;nbsp;=&amp;nbsp;db.get_product(123)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(f&amp;quot;&amp;nbsp;&amp;nbsp;重新查询:&amp;nbsp;{product[&amp;#39;name&amp;#39;]}&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(&amp;quot;\n3.&amp;nbsp;测试分类缓存:&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;_&amp;nbsp;in&amp;nbsp;range(3):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;products&amp;nbsp;=&amp;nbsp;db.get_products(&amp;quot;electronics&amp;quot;,&amp;nbsp;page=1)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(f&amp;quot;&amp;nbsp;&amp;nbsp;获取到&amp;nbsp;{len(products)}&amp;nbsp;个电子产品&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;time.sleep(1)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(&amp;quot;\n4.&amp;nbsp;缓存统计:&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;stats&amp;nbsp;=&amp;nbsp;cache_manager.get_stats()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;key,&amp;nbsp;value&amp;nbsp;in&amp;nbsp;stats.items():
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(f&amp;quot;&amp;nbsp;&amp;nbsp;{key}:&amp;nbsp;{value}&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;清理
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cache_manager.stop_cleanup()&lt;/pre&gt;&lt;h3&gt;模式3：智能限流与降级&lt;/h3&gt;&lt;div class=&quot;ybc-p&quot;&gt;1688通过&lt;strong&gt;多层次限流&lt;/strong&gt;和&lt;strong&gt;优雅降级&lt;/strong&gt;保护核心服务。&lt;/div&gt;&lt;pre class=&quot;ybc-pre-component ybc-pre-component_not-math&quot;&gt;#&amp;nbsp;rate_limiter.py
import&amp;nbsp;time
import&amp;nbsp;threading
from&amp;nbsp;typing&amp;nbsp;import&amp;nbsp;Dict,&amp;nbsp;List,&amp;nbsp;Optional
from&amp;nbsp;dataclasses&amp;nbsp;import&amp;nbsp;dataclass
from&amp;nbsp;enum&amp;nbsp;import&amp;nbsp;Enum
import&amp;nbsp;redis
from&amp;nbsp;collections&amp;nbsp;import&amp;nbsp;deque
import&amp;nbsp;hashlib
#&amp;nbsp;封装好API供应商demo&amp;nbsp;url=https://console.open.onebound.cn/console/?i=Lex
class&amp;nbsp;LimitAlgorithm(Enum):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;TOKEN_BUCKET&amp;nbsp;=&amp;nbsp;&amp;quot;token_bucket&amp;quot;&amp;nbsp;&amp;nbsp;#&amp;nbsp;令牌桶
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;LEAKY_BUCKET&amp;nbsp;=&amp;nbsp;&amp;quot;leaky_bucket&amp;quot;&amp;nbsp;&amp;nbsp;#&amp;nbsp;漏桶
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SLIDING_WINDOW&amp;nbsp;=&amp;nbsp;&amp;quot;sliding_window&amp;quot;&amp;nbsp;&amp;nbsp;#&amp;nbsp;滑动窗口

@dataclass
class&amp;nbsp;RateLimitConfig:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;限流配置&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;algorithm:&amp;nbsp;LimitAlgorithm&amp;nbsp;=&amp;nbsp;LimitAlgorithm.SLIDING_WINDOW
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;requests_per_second:&amp;nbsp;int&amp;nbsp;=&amp;nbsp;10
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;burst_capacity:&amp;nbsp;int&amp;nbsp;=&amp;nbsp;20&amp;nbsp;&amp;nbsp;#&amp;nbsp;突发容量
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;window_size:&amp;nbsp;int&amp;nbsp;=&amp;nbsp;60&amp;nbsp;&amp;nbsp;#&amp;nbsp;时间窗口(秒)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;降级配置
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;enable_degradation:&amp;nbsp;bool&amp;nbsp;=&amp;nbsp;True
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;degradation_threshold:&amp;nbsp;float&amp;nbsp;=&amp;nbsp;0.8&amp;nbsp;&amp;nbsp;#&amp;nbsp;负载阈值
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;fallback_strategy:&amp;nbsp;str&amp;nbsp;=&amp;nbsp;&amp;quot;basic&amp;quot;&amp;nbsp;&amp;nbsp;#&amp;nbsp;basic/cached/error

class&amp;nbsp;RateLimiter:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;智能限流器（支持多种算法）&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;__init__(self,&amp;nbsp;config:&amp;nbsp;RateLimitConfig,&amp;nbsp;redis_client=None):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.config&amp;nbsp;=&amp;nbsp;config
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.redis&amp;nbsp;=&amp;nbsp;redis_client
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;基于算法的限流器
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;config.algorithm&amp;nbsp;==&amp;nbsp;LimitAlgorithm.TOKEN_BUCKET:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.limiter&amp;nbsp;=&amp;nbsp;TokenBucketLimiter(config)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;elif&amp;nbsp;config.algorithm&amp;nbsp;==&amp;nbsp;LimitAlgorithm.LEAKY_BUCKET:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.limiter&amp;nbsp;=&amp;nbsp;LeakyBucketLimiter(config)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else:&amp;nbsp;&amp;nbsp;#&amp;nbsp;SLIDING_WINDOW
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.limiter&amp;nbsp;=&amp;nbsp;SlidingWindowLimiter(config,&amp;nbsp;redis_client)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;降级处理器
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.degrader&amp;nbsp;=&amp;nbsp;GracefulDegrader(config)&amp;nbsp;if&amp;nbsp;config.enable_degradation&amp;nbsp;else&amp;nbsp;None
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;统计
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.stats&amp;nbsp;=&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;total_requests&amp;quot;:&amp;nbsp;0,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;allowed_requests&amp;quot;:&amp;nbsp;0,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;limited_requests&amp;quot;:&amp;nbsp;0,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;degraded_requests&amp;quot;:&amp;nbsp;0
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;acquire(self,&amp;nbsp;key:&amp;nbsp;str)&amp;nbsp;-&amp;gt;&amp;nbsp;bool:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;获取访问许可&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.stats[&amp;quot;total_requests&amp;quot;]&amp;nbsp;+=&amp;nbsp;1
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;检查系统负载
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;self.degrader&amp;nbsp;and&amp;nbsp;self.degrader.should_degrade():
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.stats[&amp;quot;degraded_requests&amp;quot;]&amp;nbsp;+=&amp;nbsp;1
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;False
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;检查限流
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;allowed&amp;nbsp;=&amp;nbsp;self.limiter.acquire(key)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;allowed:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.stats[&amp;quot;allowed_requests&amp;quot;]&amp;nbsp;+=&amp;nbsp;1
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.stats[&amp;quot;limited_requests&amp;quot;]&amp;nbsp;+=&amp;nbsp;1
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;allowed
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;get_stats(self)&amp;nbsp;-&amp;gt;&amp;nbsp;Dict:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;获取统计信息&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;**self.stats,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;limit_rate&amp;quot;:&amp;nbsp;f&amp;quot;{self.stats[&amp;#39;limited_requests&amp;#39;]&amp;nbsp;/&amp;nbsp;max(self.stats[&amp;#39;total_requests&amp;#39;],&amp;nbsp;1):.1%}&amp;quot;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;degrade_rate&amp;quot;:&amp;nbsp;f&amp;quot;{self.stats[&amp;#39;degraded_requests&amp;#39;]&amp;nbsp;/&amp;nbsp;max(self.stats[&amp;#39;total_requests&amp;#39;],&amp;nbsp;1):.1%}&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

class&amp;nbsp;TokenBucketLimiter:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;令牌桶限流算法&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;__init__(self,&amp;nbsp;config:&amp;nbsp;RateLimitConfig):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.capacity&amp;nbsp;=&amp;nbsp;config.burst_capacity
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.tokens&amp;nbsp;=&amp;nbsp;config.burst_capacity
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.fill_rate&amp;nbsp;=&amp;nbsp;config.requests_per_second
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.last_fill&amp;nbsp;=&amp;nbsp;time.time()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.lock&amp;nbsp;=&amp;nbsp;threading.Lock()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;acquire(self,&amp;nbsp;key:&amp;nbsp;str)&amp;nbsp;-&amp;gt;&amp;nbsp;bool:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;with&amp;nbsp;self.lock:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;补充令牌
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;now&amp;nbsp;=&amp;nbsp;time.time()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;time_passed&amp;nbsp;=&amp;nbsp;now&amp;nbsp;-&amp;nbsp;self.last_fill
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;tokens_to_add&amp;nbsp;=&amp;nbsp;time_passed&amp;nbsp;*&amp;nbsp;self.fill_rate
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.tokens&amp;nbsp;=&amp;nbsp;min(self.capacity,&amp;nbsp;self.tokens&amp;nbsp;+&amp;nbsp;tokens_to_add)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.last_fill&amp;nbsp;=&amp;nbsp;now
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;检查是否有足够令牌
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;self.tokens&amp;nbsp;&amp;gt;=&amp;nbsp;1:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.tokens&amp;nbsp;-=&amp;nbsp;1
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;True
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;False

class&amp;nbsp;SlidingWindowLimiter:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;滑动窗口限流算法（分布式友好）&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;__init__(self,&amp;nbsp;config:&amp;nbsp;RateLimitConfig,&amp;nbsp;redis_client=None):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.window_size&amp;nbsp;=&amp;nbsp;config.window_size
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.max_requests&amp;nbsp;=&amp;nbsp;config.requests_per_second&amp;nbsp;*&amp;nbsp;self.window_size
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;使用Redis支持分布式限流
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.redis&amp;nbsp;=&amp;nbsp;redis_client
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.use_redis&amp;nbsp;=&amp;nbsp;redis_client&amp;nbsp;is&amp;nbsp;not&amp;nbsp;None
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;not&amp;nbsp;self.use_redis:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;本地内存存储
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.windows:&amp;nbsp;Dict[str,&amp;nbsp;deque]&amp;nbsp;=&amp;nbsp;{}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.locks:&amp;nbsp;Dict[str,&amp;nbsp;threading.Lock]&amp;nbsp;=&amp;nbsp;{}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;acquire(self,&amp;nbsp;key:&amp;nbsp;str)&amp;nbsp;-&amp;gt;&amp;nbsp;bool:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;self.use_redis:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;self._acquire_redis(key)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;self._acquire_local(key)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;_acquire_local(self,&amp;nbsp;key:&amp;nbsp;str)&amp;nbsp;-&amp;gt;&amp;nbsp;bool:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;本地限流&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;key&amp;nbsp;not&amp;nbsp;in&amp;nbsp;self.windows:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.windows[key]&amp;nbsp;=&amp;nbsp;deque()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.locks[key]&amp;nbsp;=&amp;nbsp;threading.Lock()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;with&amp;nbsp;self.locks[key]:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;now&amp;nbsp;=&amp;nbsp;time.time()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;window&amp;nbsp;=&amp;nbsp;self.windows[key]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;清理过期的请求
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cutoff&amp;nbsp;=&amp;nbsp;now&amp;nbsp;-&amp;nbsp;self.window_size
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;while&amp;nbsp;window&amp;nbsp;and&amp;nbsp;window[0]&amp;nbsp;&amp;lt;&amp;nbsp;cutoff:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;window.popleft()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;检查是否超过限制
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;len(window)&amp;nbsp;&amp;gt;=&amp;nbsp;self.max_requests:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;False
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;添加当前请求
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;window.append(now)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;True
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;_acquire_redis(self,&amp;nbsp;key:&amp;nbsp;str)&amp;nbsp;-&amp;gt;&amp;nbsp;bool:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;Redis分布式限流&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;redis_key&amp;nbsp;=&amp;nbsp;f&amp;quot;rate_limit:{key}&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;now&amp;nbsp;=&amp;nbsp;int(time.time()&amp;nbsp;*&amp;nbsp;1000)&amp;nbsp;&amp;nbsp;#&amp;nbsp;毫秒时间戳
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;使用Redis的sorted&amp;nbsp;set实现滑动窗口
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pipeline&amp;nbsp;=&amp;nbsp;self.redis.pipeline()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;1.&amp;nbsp;移除窗口外的记录
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pipeline.zremrangebyscore(redis_key,&amp;nbsp;0,&amp;nbsp;now&amp;nbsp;-&amp;nbsp;self.window_size&amp;nbsp;*&amp;nbsp;1000)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;2.&amp;nbsp;获取当前窗口内的请求数
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pipeline.zcard(redis_key)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;3.&amp;nbsp;如果未超限，添加当前请求
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pipeline.zadd(redis_key,&amp;nbsp;{str(now):&amp;nbsp;now})
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;4.&amp;nbsp;设置过期时间
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pipeline.expire(redis_key,&amp;nbsp;self.window_size&amp;nbsp;+&amp;nbsp;1)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;results&amp;nbsp;=&amp;nbsp;pipeline.execute()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;current_count&amp;nbsp;=&amp;nbsp;results[1]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;current_count&amp;nbsp;&amp;lt;&amp;nbsp;self.max_requests:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;True
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;False

class&amp;nbsp;GracefulDegrader:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;优雅降级处理器&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;__init__(self,&amp;nbsp;config:&amp;nbsp;RateLimitConfig):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.config&amp;nbsp;=&amp;nbsp;config
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.system_load&amp;nbsp;=&amp;nbsp;0.0
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.last_check&amp;nbsp;=&amp;nbsp;time.time()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;负载监控窗口
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.load_window&amp;nbsp;=&amp;nbsp;deque(maxlen=10)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;should_degrade(self)&amp;nbsp;-&amp;gt;&amp;nbsp;bool:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;判断是否需要降级&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;更新系统负载
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self._update_system_load()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;检查负载阈值
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;self.system_load&amp;nbsp;&amp;gt;&amp;nbsp;self.config.degradation_threshold:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;True
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;False
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;_update_system_load(self):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;更新系统负载（简化实现）&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;now&amp;nbsp;=&amp;nbsp;time.time()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;模拟CPU/内存负载
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;import&amp;nbsp;psutil
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cpu_load&amp;nbsp;=&amp;nbsp;psutil.cpu_percent(interval=0.1)&amp;nbsp;/&amp;nbsp;100
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;memory_load&amp;nbsp;=&amp;nbsp;psutil.virtual_memory().percent&amp;nbsp;/&amp;nbsp;100
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;加权平均
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;current_load&amp;nbsp;=&amp;nbsp;cpu_load&amp;nbsp;*&amp;nbsp;0.7&amp;nbsp;+&amp;nbsp;memory_load&amp;nbsp;*&amp;nbsp;0.3
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.load_window.append(current_load)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;计算平均负载
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;self.load_window:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.system_load&amp;nbsp;=&amp;nbsp;sum(self.load_window)&amp;nbsp;/&amp;nbsp;len(self.load_window)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;get_fallback_response(self,&amp;nbsp;original_func,&amp;nbsp;*args,&amp;nbsp;**kwargs):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;获取降级响应&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;strategy&amp;nbsp;=&amp;nbsp;self.config.fallback_strategy
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;strategy&amp;nbsp;==&amp;nbsp;&amp;quot;cached&amp;quot;:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;返回缓存数据
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;self._get_cached_response(original_func.__name__,&amp;nbsp;args,&amp;nbsp;kwargs)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;elif&amp;nbsp;strategy&amp;nbsp;==&amp;nbsp;&amp;quot;basic&amp;quot;:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;返回基础数据
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;self._get_basic_response(original_func.__name__)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else:&amp;nbsp;&amp;nbsp;#&amp;nbsp;&amp;quot;error&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;返回友好错误
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;raise&amp;nbsp;ServiceDegradedError(&amp;quot;服务暂时繁忙，请稍后重试&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;_get_cached_response(self,&amp;nbsp;func_name,&amp;nbsp;args,&amp;nbsp;kwargs):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;获取缓存响应&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;这里可以集成缓存系统
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;status&amp;quot;:&amp;nbsp;&amp;quot;degraded&amp;quot;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;message&amp;quot;:&amp;nbsp;&amp;quot;服务降级，返回缓存数据&amp;quot;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;data&amp;quot;:&amp;nbsp;None,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;timestamp&amp;quot;:&amp;nbsp;time.time()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;_get_basic_response(self,&amp;nbsp;func_name):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;获取基础响应&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;status&amp;quot;:&amp;nbsp;&amp;quot;degraded&amp;quot;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;message&amp;quot;:&amp;nbsp;&amp;quot;服务暂时繁忙&amp;quot;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;data&amp;quot;:&amp;nbsp;{&amp;quot;basic_info&amp;quot;:&amp;nbsp;True},
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;timestamp&amp;quot;:&amp;nbsp;time.time()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

def&amp;nbsp;rate_limit_decorator(requests_per_second=10,&amp;nbsp;algorithm=&amp;quot;sliding_window&amp;quot;):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;限流装饰器&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;decorator(func):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;创建限流器
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;config&amp;nbsp;=&amp;nbsp;RateLimitConfig(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;algorithm=LimitAlgorithm(algorithm),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;requests_per_second=requests_per_second
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;limiter&amp;nbsp;=&amp;nbsp;RateLimiter(config)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@wraps(func)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;wrapper(*args,&amp;nbsp;**kwargs):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;生成限流键
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;key&amp;nbsp;=&amp;nbsp;_generate_rate_limit_key(func,&amp;nbsp;args,&amp;nbsp;kwargs)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;检查限流
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;not&amp;nbsp;limiter.acquire(key):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;raise&amp;nbsp;RateLimitExceeded(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;f&amp;quot;API调用频率超限，请稍后重试。限制:&amp;nbsp;{requests_per_second}/秒&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;func(*args,&amp;nbsp;**kwargs)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;wrapper
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;decorator

def&amp;nbsp;degrade_when_overloaded(fallback_strategy=&amp;quot;basic&amp;quot;):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;过载降级装饰器&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;decorator(func):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;config&amp;nbsp;=&amp;nbsp;RateLimitConfig(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;enable_degradation=True,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;fallback_strategy=fallback_strategy
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;degrader&amp;nbsp;=&amp;nbsp;GracefulDegrader(config)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@wraps(func)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;wrapper(*args,&amp;nbsp;**kwargs):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;degrader.should_degrade():
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;degrader.get_fallback_response(func,&amp;nbsp;*args,&amp;nbsp;**kwargs)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;func(*args,&amp;nbsp;**kwargs)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;wrapper
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;decorator

#&amp;nbsp;使用示例
if&amp;nbsp;__name__&amp;nbsp;==&amp;nbsp;&amp;quot;__main__&amp;quot;:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;import&amp;nbsp;random
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;1.&amp;nbsp;测试限流器
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(&amp;quot;🧪&amp;nbsp;测试限流器:&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;config&amp;nbsp;=&amp;nbsp;RateLimitConfig(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;algorithm=LimitAlgorithm.SLIDING_WINDOW,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;requests_per_second=5,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;window_size=10
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;limiter&amp;nbsp;=&amp;nbsp;RateLimiter(config)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;success_count&amp;nbsp;=&amp;nbsp;0
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;i&amp;nbsp;in&amp;nbsp;range(20):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;allowed&amp;nbsp;=&amp;nbsp;limiter.acquire(&amp;quot;user_123&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;allowed:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;success_count&amp;nbsp;+=&amp;nbsp;1
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(f&amp;quot;&amp;nbsp;&amp;nbsp;✅&amp;nbsp;请求&amp;nbsp;{i+1}:&amp;nbsp;允许&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(f&amp;quot;&amp;nbsp;&amp;nbsp;❌&amp;nbsp;请求&amp;nbsp;{i+1}:&amp;nbsp;限流&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;time.sleep(0.1)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(f&amp;quot;\n允许&amp;nbsp;{success_count}/20&amp;nbsp;个请求&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(f&amp;quot;限流统计:&amp;nbsp;{limiter.get_stats()}&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;2.&amp;nbsp;测试装饰器
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(&amp;quot;\n🧪&amp;nbsp;测试限流装饰器:&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@rate_limit_decorator(requests_per_second=3,&amp;nbsp;algorithm=&amp;quot;token_bucket&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;expensive_api_call(user_id:&amp;nbsp;int):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;模拟耗时API调用&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;time.sleep(0.1)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;{&amp;quot;user_id&amp;quot;:&amp;nbsp;user_id,&amp;nbsp;&amp;quot;data&amp;quot;:&amp;nbsp;&amp;quot;result&amp;quot;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;模拟并发调用
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;import&amp;nbsp;concurrent.futures
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;call_api(user_id):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;result&amp;nbsp;=&amp;nbsp;expensive_api_call(user_id)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;f&amp;quot;用户&amp;nbsp;{user_id}:&amp;nbsp;成功&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;except&amp;nbsp;RateLimitExceeded&amp;nbsp;as&amp;nbsp;e:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;f&amp;quot;用户&amp;nbsp;{user_id}:&amp;nbsp;被限流&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;with&amp;nbsp;concurrent.futures.ThreadPoolExecutor(max_workers=10)&amp;nbsp;as&amp;nbsp;executor:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;futures&amp;nbsp;=&amp;nbsp;[executor.submit(call_api,&amp;nbsp;i)&amp;nbsp;for&amp;nbsp;i&amp;nbsp;in&amp;nbsp;range(10)]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;future&amp;nbsp;in&amp;nbsp;concurrent.futures.as_completed(futures):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(f&amp;quot;&amp;nbsp;&amp;nbsp;{future.result()}&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;3.&amp;nbsp;测试降级
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(&amp;quot;\n🧪&amp;nbsp;测试优雅降级:&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@degrade_when_overloaded(fallback_strategy=&amp;quot;cached&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;get_product_details(product_id:&amp;nbsp;int):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;获取产品详情（可能过载）&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;模拟高负载
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;time.sleep(0.5)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;id&amp;quot;:&amp;nbsp;product_id,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;name&amp;quot;:&amp;nbsp;f&amp;quot;产品{product_id}&amp;quot;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;details&amp;quot;:&amp;nbsp;&amp;quot;完整详情&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;模拟正常情况
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(&amp;quot;正常情况:&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;result&amp;nbsp;=&amp;nbsp;get_product_details(123)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(f&amp;quot;&amp;nbsp;&amp;nbsp;{result}&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;模拟高负载（需要修改代码触发）
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(&amp;quot;\n高负载时降级:&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;这里需要实际触发高负载条件&lt;/pre&gt;&lt;h3&gt;模式4：全链路监控与追踪&lt;/h3&gt;&lt;div class=&quot;ybc-p&quot;&gt;1688通过&lt;strong&gt;分布式追踪&lt;/strong&gt;和&lt;strong&gt;智能告警&lt;/strong&gt;实时监控API健康度。&lt;/div&gt;&lt;pre class=&quot;ybc-pre-component ybc-pre-component_not-math&quot;&gt;#&amp;nbsp;api_monitor.py
import&amp;nbsp;time
import&amp;nbsp;json
import&amp;nbsp;logging
from&amp;nbsp;typing&amp;nbsp;import&amp;nbsp;Dict,&amp;nbsp;List,&amp;nbsp;Optional
from&amp;nbsp;dataclasses&amp;nbsp;import&amp;nbsp;dataclass,&amp;nbsp;asdict
from&amp;nbsp;datetime&amp;nbsp;import&amp;nbsp;datetime,&amp;nbsp;timedelta
from&amp;nbsp;enum&amp;nbsp;import&amp;nbsp;Enum
import&amp;nbsp;threading
from&amp;nbsp;collections&amp;nbsp;import&amp;nbsp;deque
import&amp;nbsp;statsd
import&amp;nbsp;requests
#&amp;nbsp;封装好API供应商demo&amp;nbsp;url=https://console.open.onebound.cn/console/?i=Lex
class&amp;nbsp;AlertLevel(Enum):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;INFO&amp;nbsp;=&amp;nbsp;&amp;quot;info&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;WARNING&amp;nbsp;=&amp;nbsp;&amp;quot;warning&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;CRITICAL&amp;nbsp;=&amp;nbsp;&amp;quot;critical&amp;quot;

@dataclass
class&amp;nbsp;APIMetric:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;API监控指标&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;endpoint:&amp;nbsp;str
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;method:&amp;nbsp;str
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;status_code:&amp;nbsp;int
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;response_time:&amp;nbsp;float
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;timestamp:&amp;nbsp;datetime
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;client_ip:&amp;nbsp;str&amp;nbsp;=&amp;nbsp;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;user_id:&amp;nbsp;str&amp;nbsp;=&amp;nbsp;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;error_message:&amp;nbsp;str&amp;nbsp;=&amp;nbsp;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;to_dict(self):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;asdict(self)

class&amp;nbsp;APIMonitor:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;API监控与告警系统&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;__init__(self,&amp;nbsp;statsd_host=&amp;#39;localhost&amp;#39;,&amp;nbsp;statsd_port=8125):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;指标存储
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.metrics:&amp;nbsp;deque&amp;nbsp;=&amp;nbsp;deque(maxlen=10000)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;统计客户端
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.statsd&amp;nbsp;=&amp;nbsp;statsd.StatsClient(statsd_host,&amp;nbsp;statsd_port)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;告警规则
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.alert_rules&amp;nbsp;=&amp;nbsp;self._load_alert_rules()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;监控线程
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self._monitoring&amp;nbsp;=&amp;nbsp;False
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self._monitor_thread&amp;nbsp;=&amp;nbsp;None
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;设置日志
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.logger&amp;nbsp;=&amp;nbsp;logging.getLogger(&amp;quot;APIMonitor&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;record_request(self,&amp;nbsp;metric:&amp;nbsp;APIMetric):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;记录API请求&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.metrics.append(metric)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;发送到StatsD
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self._send_to_statsd(metric)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;检查告警规则
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self._check_alerts(metric)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;_send_to_statsd(self,&amp;nbsp;metric:&amp;nbsp;APIMetric):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;发送指标到StatsD&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;响应时间
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.statsd.timing(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;f&amp;quot;api.{metric.endpoint}.{metric.method}.response_time&amp;quot;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;metric.response_time
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;状态码
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.statsd.incr(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;f&amp;quot;api.{metric.endpoint}.{metric.method}.status.{metric.status_code}&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;错误率
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;metric.status_code&amp;nbsp;&amp;gt;=&amp;nbsp;400:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.statsd.incr(f&amp;quot;api.{metric.endpoint}.{metric.method}.errors&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;except&amp;nbsp;Exception&amp;nbsp;as&amp;nbsp;e:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.logger.error(f&amp;quot;发送StatsD失败:&amp;nbsp;{e}&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;_check_alerts(self,&amp;nbsp;metric:&amp;nbsp;APIMetric):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;检查告警规则&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;rule&amp;nbsp;in&amp;nbsp;self.alert_rules:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;self._matches_rule(metric,&amp;nbsp;rule):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self._trigger_alert(metric,&amp;nbsp;rule)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;_matches_rule(self,&amp;nbsp;metric:&amp;nbsp;APIMetric,&amp;nbsp;rule:&amp;nbsp;dict)&amp;nbsp;-&amp;gt;&amp;nbsp;bool:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;检查是否匹配告警规则&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;匹配端点
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;rule.get(&amp;#39;endpoint&amp;#39;)&amp;nbsp;and&amp;nbsp;metric.endpoint&amp;nbsp;!=&amp;nbsp;rule[&amp;#39;endpoint&amp;#39;]:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;False
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;匹配状态码
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;rule.get(&amp;#39;status_codes&amp;#39;):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;metric.status_code&amp;nbsp;not&amp;nbsp;in&amp;nbsp;rule[&amp;#39;status_codes&amp;#39;]:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;False
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;响应时间阈值
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;rule.get(&amp;#39;response_time_threshold&amp;#39;):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;metric.response_time&amp;nbsp;&amp;lt;&amp;nbsp;rule[&amp;#39;response_time_threshold&amp;#39;]:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;False
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;True
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;_trigger_alert(self,&amp;nbsp;metric:&amp;nbsp;APIMetric,&amp;nbsp;rule:&amp;nbsp;dict):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;触发告警&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;alert&amp;nbsp;=&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;level&amp;#39;:&amp;nbsp;rule.get(&amp;#39;level&amp;#39;,&amp;nbsp;AlertLevel.WARNING),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;endpoint&amp;#39;:&amp;nbsp;metric.endpoint,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;method&amp;#39;:&amp;nbsp;metric.method,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;status_code&amp;#39;:&amp;nbsp;metric.status_code,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;response_time&amp;#39;:&amp;nbsp;metric.response_time,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;timestamp&amp;#39;:&amp;nbsp;datetime.now().isoformat(),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;rule_name&amp;#39;:&amp;nbsp;rule.get(&amp;#39;name&amp;#39;),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;message&amp;#39;:&amp;nbsp;rule.get(&amp;#39;message&amp;#39;,&amp;nbsp;&amp;#39;API监控告警&amp;#39;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;发送告警
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self._send_alert(alert)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.logger.warning(f&amp;quot;🚨&amp;nbsp;告警触发:&amp;nbsp;{json.dumps(alert,&amp;nbsp;indent=2)}&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;_send_alert(self,&amp;nbsp;alert:&amp;nbsp;dict):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;发送告警（可扩展为邮件、钉钉、Slack等）&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;这里可以实现多种告警方式
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pass
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;_load_alert_rules(self)&amp;nbsp;-&amp;gt;&amp;nbsp;List[Dict]:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;加载告警规则&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;[
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;name&amp;#39;:&amp;nbsp;&amp;#39;slow_response&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;endpoint&amp;#39;:&amp;nbsp;&amp;#39;/api/products&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;response_time_threshold&amp;#39;:&amp;nbsp;1000,&amp;nbsp;&amp;nbsp;#&amp;nbsp;1秒
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;level&amp;#39;:&amp;nbsp;AlertLevel.WARNING,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;message&amp;#39;:&amp;nbsp;&amp;#39;API响应过慢&amp;#39;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;},
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;name&amp;#39;:&amp;nbsp;&amp;#39;server_error&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;status_codes&amp;#39;:&amp;nbsp;[500,&amp;nbsp;502,&amp;nbsp;503,&amp;nbsp;504],
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;level&amp;#39;:&amp;nbsp;AlertLevel.CRITICAL,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;message&amp;#39;:&amp;nbsp;&amp;#39;服务器错误&amp;#39;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;},
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;name&amp;#39;:&amp;nbsp;&amp;#39;high_error_rate&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;level&amp;#39;:&amp;nbsp;AlertLevel.CRITICAL,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;message&amp;#39;:&amp;nbsp;&amp;#39;错误率过高&amp;#39;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;get_recent_metrics(self,&amp;nbsp;minutes:&amp;nbsp;int&amp;nbsp;=&amp;nbsp;5)&amp;nbsp;-&amp;gt;&amp;nbsp;List[APIMetric]:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;获取最近N分钟的指标&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cutoff&amp;nbsp;=&amp;nbsp;datetime.now()&amp;nbsp;-&amp;nbsp;timedelta(minutes=minutes)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;[m&amp;nbsp;for&amp;nbsp;m&amp;nbsp;in&amp;nbsp;self.metrics&amp;nbsp;if&amp;nbsp;m.timestamp&amp;nbsp;&amp;gt;&amp;nbsp;cutoff]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;calculate_stats(self,&amp;nbsp;minutes:&amp;nbsp;int&amp;nbsp;=&amp;nbsp;5)&amp;nbsp;-&amp;gt;&amp;nbsp;Dict:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;计算统计信息&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;recent&amp;nbsp;=&amp;nbsp;self.get_recent_metrics(minutes)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;not&amp;nbsp;recent:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;{}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;响应时间统计
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;response_times&amp;nbsp;=&amp;nbsp;[m.response_time&amp;nbsp;for&amp;nbsp;m&amp;nbsp;in&amp;nbsp;recent]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;状态码分布
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;status_codes&amp;nbsp;=&amp;nbsp;{}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;m&amp;nbsp;in&amp;nbsp;recent:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;code&amp;nbsp;=&amp;nbsp;m.status_code
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;status_codes[code]&amp;nbsp;=&amp;nbsp;status_codes.get(code,&amp;nbsp;0)&amp;nbsp;+&amp;nbsp;1
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;端点统计
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;endpoints&amp;nbsp;=&amp;nbsp;{}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;m&amp;nbsp;in&amp;nbsp;recent:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;key&amp;nbsp;=&amp;nbsp;f&amp;quot;{m.method}&amp;nbsp;{m.endpoint}&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;endpoints[key]&amp;nbsp;=&amp;nbsp;endpoints.get(key,&amp;nbsp;0)&amp;nbsp;+&amp;nbsp;1
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;total_requests&amp;#39;:&amp;nbsp;len(recent),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;avg_response_time&amp;#39;:&amp;nbsp;sum(response_times)&amp;nbsp;/&amp;nbsp;len(response_times),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;p95_response_time&amp;#39;:&amp;nbsp;sorted(response_times)[int(len(response_times)&amp;nbsp;*&amp;nbsp;0.95)],
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;error_rate&amp;#39;:&amp;nbsp;sum(1&amp;nbsp;for&amp;nbsp;m&amp;nbsp;in&amp;nbsp;recent&amp;nbsp;if&amp;nbsp;m.status_code&amp;nbsp;&amp;gt;=&amp;nbsp;400)&amp;nbsp;/&amp;nbsp;len(recent),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;status_codes&amp;#39;:&amp;nbsp;status_codes,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;top_endpoints&amp;#39;:&amp;nbsp;dict(sorted(endpoints.items(),&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;key=lambda&amp;nbsp;x:&amp;nbsp;x[1],&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;reverse=True)[:10])
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;start_monitoring(self,&amp;nbsp;interval=60):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;启动监控线程&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self._monitoring&amp;nbsp;=&amp;nbsp;True
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self._monitor_thread&amp;nbsp;=&amp;nbsp;threading.Thread(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;target=self._monitor_loop,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;args=(interval,),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;daemon=True
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self._monitor_thread.start()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;stop_monitoring(self):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;停止监控线程&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self._monitoring&amp;nbsp;=&amp;nbsp;False
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;self._monitor_thread:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self._monitor_thread.join(timeout=5)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;_monitor_loop(self,&amp;nbsp;interval):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;监控循环&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;while&amp;nbsp;self._monitoring:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;time.sleep(interval)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;计算并报告统计
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;stats&amp;nbsp;=&amp;nbsp;self.calculate_stats(5)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;stats:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.logger.info(f&amp;quot;📊&amp;nbsp;API监控统计:&amp;nbsp;{json.dumps(stats,&amp;nbsp;indent=2)}&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;检查全局告警
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self._check_global_alerts(stats)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;_check_global_alerts(self,&amp;nbsp;stats:&amp;nbsp;Dict):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;检查全局告警&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;错误率告警
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;stats.get(&amp;#39;error_rate&amp;#39;,&amp;nbsp;0)&amp;nbsp;&amp;gt;&amp;nbsp;0.1:&amp;nbsp;&amp;nbsp;#&amp;nbsp;错误率超过10%
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self._trigger_alert(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;APIMetric(&amp;quot;&amp;quot;,&amp;nbsp;&amp;quot;&amp;quot;,&amp;nbsp;0,&amp;nbsp;0,&amp;nbsp;datetime.now()),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;name&amp;#39;:&amp;nbsp;&amp;#39;global_error_rate&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;level&amp;#39;:&amp;nbsp;AlertLevel.CRITICAL,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;message&amp;#39;:&amp;nbsp;f&amp;#39;全局错误率过高:&amp;nbsp;{stats[&amp;quot;error_rate&amp;quot;]:.1%}&amp;#39;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;响应时间告警
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;stats.get(&amp;#39;p95_response_time&amp;#39;,&amp;nbsp;0)&amp;nbsp;&amp;gt;&amp;nbsp;2000:&amp;nbsp;&amp;nbsp;#&amp;nbsp;P95超过2秒
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self._trigger_alert(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;APIMetric(&amp;quot;&amp;quot;,&amp;nbsp;&amp;quot;&amp;quot;,&amp;nbsp;0,&amp;nbsp;0,&amp;nbsp;datetime.now()),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;name&amp;#39;:&amp;nbsp;&amp;#39;global_slow_response&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;level&amp;#39;:&amp;nbsp;AlertLevel.WARNING,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;message&amp;#39;:&amp;nbsp;f&amp;#39;P95响应时间过长:&amp;nbsp;{stats[&amp;quot;p95_response_time&amp;quot;]:.0f}ms&amp;#39;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)

def&amp;nbsp;monitor_decorator():
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;API监控装饰器&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;decorator(func):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@wraps(func)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;wrapper(*args,&amp;nbsp;**kwargs):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;获取监控实例
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;monitor&amp;nbsp;=&amp;nbsp;_get_monitor()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;start_time&amp;nbsp;=&amp;nbsp;time.time()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;执行原函数
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;result&amp;nbsp;=&amp;nbsp;func(*args,&amp;nbsp;**kwargs)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;计算响应时间
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;response_time&amp;nbsp;=&amp;nbsp;(time.time()&amp;nbsp;-&amp;nbsp;start_time)&amp;nbsp;*&amp;nbsp;1000
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;记录成功指标
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;metric&amp;nbsp;=&amp;nbsp;APIMetric(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;endpoint=func.__module__&amp;nbsp;+&amp;nbsp;&amp;quot;.&amp;quot;&amp;nbsp;+&amp;nbsp;func.__name__,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;method=&amp;quot;GET&amp;quot;,&amp;nbsp;&amp;nbsp;#&amp;nbsp;可以从请求中获取
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;status_code=200,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;response_time=response_time,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;timestamp=datetime.now(),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;client_ip=&amp;quot;127.0.0.1&amp;quot;&amp;nbsp;&amp;nbsp;#&amp;nbsp;可以从请求中获取
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;monitor.record_request(metric)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;result
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;except&amp;nbsp;Exception&amp;nbsp;as&amp;nbsp;e:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;计算响应时间
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;response_time&amp;nbsp;=&amp;nbsp;(time.time()&amp;nbsp;-&amp;nbsp;start_time)&amp;nbsp;*&amp;nbsp;1000
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;记录失败指标
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;metric&amp;nbsp;=&amp;nbsp;APIMetric(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;endpoint=func.__module__&amp;nbsp;+&amp;nbsp;&amp;quot;.&amp;quot;&amp;nbsp;+&amp;nbsp;func.__name__,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;method=&amp;quot;GET&amp;quot;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;status_code=500,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;response_time=response_time,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;timestamp=datetime.now(),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;client_ip=&amp;quot;127.0.0.1&amp;quot;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;error_message=str(e)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;monitor.record_request(metric)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;raise
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;wrapper
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;decorator

#&amp;nbsp;全局监控器
_MONITOR&amp;nbsp;=&amp;nbsp;None

def&amp;nbsp;_get_monitor():
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;获取监控器单例&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;global&amp;nbsp;_MONITOR
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;_MONITOR&amp;nbsp;is&amp;nbsp;None:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;_MONITOR&amp;nbsp;=&amp;nbsp;APIMonitor()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;_MONITOR.start_monitoring()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;_MONITOR

#&amp;nbsp;使用示例
if&amp;nbsp;__name__&amp;nbsp;==&amp;nbsp;&amp;quot;__main__&amp;quot;:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;配置日志
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;logging.basicConfig(level=logging.INFO)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;创建监控器
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;monitor&amp;nbsp;=&amp;nbsp;APIMonitor()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;monitor.start_monitoring(interval=10)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;模拟API调用
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(&amp;quot;🧪&amp;nbsp;模拟API调用监控:&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@monitor_decorator()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;get_product_api(product_id:&amp;nbsp;int):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;模拟产品API&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;time.sleep(0.1&amp;nbsp;+&amp;nbsp;random.random()&amp;nbsp;*&amp;nbsp;0.2)&amp;nbsp;&amp;nbsp;#&amp;nbsp;随机延迟
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;模拟错误
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;random.random()&amp;nbsp;&amp;lt;&amp;nbsp;0.1:&amp;nbsp;&amp;nbsp;#&amp;nbsp;10%错误率
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;raise&amp;nbsp;Exception(&amp;quot;数据库连接失败&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;{&amp;quot;id&amp;quot;:&amp;nbsp;product_id,&amp;nbsp;&amp;quot;name&amp;quot;:&amp;nbsp;f&amp;quot;产品{product_id}&amp;quot;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;批量调用
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;i&amp;nbsp;in&amp;nbsp;range(50):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;result&amp;nbsp;=&amp;nbsp;get_product_api(i)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(f&amp;quot;&amp;nbsp;&amp;nbsp;✅&amp;nbsp;调用&amp;nbsp;{i}:&amp;nbsp;成功&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;except&amp;nbsp;Exception&amp;nbsp;as&amp;nbsp;e:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(f&amp;quot;&amp;nbsp;&amp;nbsp;❌&amp;nbsp;调用&amp;nbsp;{i}:&amp;nbsp;失败&amp;nbsp;-&amp;nbsp;{e}&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;time.sleep(0.05)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;等待监控采集
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;time.sleep(2)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;获取统计
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(&amp;quot;\n📊&amp;nbsp;监控统计:&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;stats&amp;nbsp;=&amp;nbsp;monitor.calculate_stats(5)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;key,&amp;nbsp;value&amp;nbsp;in&amp;nbsp;stats.items():
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;isinstance(value,&amp;nbsp;dict):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(f&amp;quot;&amp;nbsp;&amp;nbsp;{key}:&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;k,&amp;nbsp;v&amp;nbsp;in&amp;nbsp;value.items():
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(f&amp;quot;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{k}:&amp;nbsp;{v}&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(f&amp;quot;&amp;nbsp;&amp;nbsp;{key}:&amp;nbsp;{value}&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;清理
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;monitor.stop_monitoring()&lt;/pre&gt;&lt;hr/&gt;&lt;h2&gt;三、 1688 API 设计的最佳实践总结&lt;/h2&gt;&lt;h3&gt;1. &lt;strong&gt;容错设计&lt;/strong&gt;&lt;/h3&gt;&lt;ul class=&quot;ybc-ul-component list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;重试策略&lt;/strong&gt;：指数退避 + 随机抖动&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;熔断机制&lt;/strong&gt;：快速失败，避免雪崩&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;超时控制&lt;/strong&gt;：分层超时（连接/读取/总超时）&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;2. &lt;strong&gt;性能优化&lt;/strong&gt;&lt;/h3&gt;&lt;ul class=&quot;ybc-ul-component list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;多级缓存&lt;/strong&gt;：本地 → Redis → 数据库&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;连接池&lt;/strong&gt;：复用TCP连接&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;异步处理&lt;/strong&gt;：非阻塞IO，并行调用&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;3. &lt;strong&gt;安全防护&lt;/strong&gt;&lt;/h3&gt;&lt;ul class=&quot;ybc-ul-component list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;签名验证&lt;/strong&gt;：防止请求篡改&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;限流策略&lt;/strong&gt;：令牌桶/漏桶/滑动窗口&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;权限控制&lt;/strong&gt;：RBAC + 细粒度权限&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;4. &lt;strong&gt;监控运维&lt;/strong&gt;&lt;/h3&gt;&lt;ul class=&quot;ybc-ul-component list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;分布式追踪&lt;/strong&gt;：全链路监控&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;智能告警&lt;/strong&gt;：基于SLO的告警&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;动态配置&lt;/strong&gt;：热更新配置&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;hr/&gt;&lt;h2&gt;四、 实战：构建高可用API网关&lt;/h2&gt;&lt;pre class=&quot;ybc-pre-component ybc-pre-component_not-math&quot;&gt;#&amp;nbsp;api_gateway.py
from&amp;nbsp;flask&amp;nbsp;import&amp;nbsp;Flask,&amp;nbsp;request,&amp;nbsp;jsonify
import&amp;nbsp;time
from&amp;nbsp;functools&amp;nbsp;import&amp;nbsp;wraps
#&amp;nbsp;封装好API供应商demo&amp;nbsp;url=https://console.open.onebound.cn/console/?i=Lex
app&amp;nbsp;=&amp;nbsp;Flask(__name__)

#&amp;nbsp;初始化组件
circuit_breaker&amp;nbsp;=&amp;nbsp;CircuitBreaker(&amp;quot;ExternalAPI&amp;quot;)
cache_manager&amp;nbsp;=&amp;nbsp;LayeredCache()
rate_limiter&amp;nbsp;=&amp;nbsp;RateLimiter(RateLimitConfig(requests_per_second=100))
monitor&amp;nbsp;=&amp;nbsp;APIMonitor()

def&amp;nbsp;api_protector(func):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;API保护装饰器（集成所有保护机制）&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@wraps(func)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;wrapper(*args,&amp;nbsp;**kwargs):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;1.&amp;nbsp;限流检查
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;client_ip&amp;nbsp;=&amp;nbsp;request.remote_addr
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;not&amp;nbsp;rate_limiter.acquire(client_ip):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;jsonify({&amp;quot;error&amp;quot;:&amp;nbsp;&amp;quot;请求频率超限&amp;quot;}),&amp;nbsp;429
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;2.&amp;nbsp;熔断保护
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;result&amp;nbsp;=&amp;nbsp;circuit_breaker.call(func,&amp;nbsp;*args,&amp;nbsp;**kwargs)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;3.&amp;nbsp;记录监控指标
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;metric&amp;nbsp;=&amp;nbsp;APIMetric(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;endpoint=request.path,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;method=request.method,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;status_code=200,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;response_time=0,&amp;nbsp;&amp;nbsp;#&amp;nbsp;实际计算
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;timestamp=datetime.now(),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;client_ip=client_ip
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;monitor.record_request(metric)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;result
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;except&amp;nbsp;Exception&amp;nbsp;as&amp;nbsp;e:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;jsonify({&amp;quot;error&amp;quot;:&amp;nbsp;str(e)}),&amp;nbsp;500
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;wrapper

@app.route(&amp;#39;/api/products/&amp;lt;product_id&amp;gt;&amp;#39;)
@api_protector
def&amp;nbsp;get_product(product_id):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;获取产品详情&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;1.&amp;nbsp;检查缓存
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cache_key&amp;nbsp;=&amp;nbsp;f&amp;quot;product:{product_id}&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;product&amp;nbsp;=&amp;nbsp;cache_manager.get(cache_key)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;product:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;jsonify(product)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;2.&amp;nbsp;调用外部API（受保护）
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;product&amp;nbsp;=&amp;nbsp;fetch_from_external_api(product_id)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;3.&amp;nbsp;写入缓存
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cache_manager.set(cache_key,&amp;nbsp;product,&amp;nbsp;ttl=300)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;jsonify(product)

if&amp;nbsp;__name__&amp;nbsp;==&amp;nbsp;&amp;quot;__main__&amp;quot;:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;app.run(host=&amp;#39;0.0.0.0&amp;#39;,&amp;nbsp;port=8000,&amp;nbsp;debug=False)&lt;/pre&gt;&lt;hr/&gt;&lt;h2&gt;五、 实施建议&lt;/h2&gt;&lt;ol class=&quot;ybc-ol-component ybc-ol-component_1 list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;从小处开始&lt;/strong&gt;：先在一个核心接口上实现熔断和重试&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;渐进式改进&lt;/strong&gt;：逐步添加缓存、限流、监控&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;监控先行&lt;/strong&gt;：先建立监控，再优化性能&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;测试驱动&lt;/strong&gt;：编写故障注入测试，验证容错能力&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;记住&lt;/strong&gt;：高可用不是一蹴而就的，而是通过持续改进和从故障中学习实现的。1688的API设计经过十余年锤炼，你可以借鉴其思路，但需要根据自身业务特点进行调整。&lt;/div&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;互动话题&lt;/strong&gt;：你的API遇到过哪些可用性问题？是性能瓶颈、容错不足还是监控缺失？评论区聊聊，我可以给你针对性的改进建议！&lt;/div&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;</description><pubDate>Mon, 25 May 2026 14:59:55 +0800</pubDate></item><item><title>🔥 人工抓取数据革命：从“人肉爬虫”到“智能数据工厂”全面转型指南</title><link>https://alexob.com/?id=373</link><description>&lt;h1&gt;🔥 人工抓取数据革命：从“人肉爬虫”到“智能数据工厂”全面转型指南&lt;/h1&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;“人肉爬虫”时代即将终结&lt;/strong&gt;。当企业还在用人工复制粘贴、Excel导出、微信群发索取数据时，竞争对手已经用智能数据工厂实现了分钟级数据洞察。这不是危言耸听——&lt;strong&gt;2024年，数据采集效率差距将决定企业生死&lt;/strong&gt;。&lt;/div&gt;&lt;div class=&quot;ybc-p&quot;&gt;本文将为你提供从“人肉爬虫”到“智能数据工厂”的完整转型路线图，包含可直接部署的Python源码。&lt;/div&gt;&lt;hr/&gt;&lt;h2&gt;一、 现状诊断：你的企业处于哪个阶段？&lt;/h2&gt;&lt;pre class=&quot;ybc-pre-component ybc-pre-component_not-math&quot;&gt;#&amp;nbsp;stage_diagnosis.py
class&amp;nbsp;DataAcquisitionStage:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;数据采集成熟度诊断&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;STAGES&amp;nbsp;=&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;0:&amp;nbsp;&amp;quot;🔴&amp;nbsp;石器时代&amp;nbsp;-&amp;nbsp;全人工&amp;quot;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;1:&amp;nbsp;&amp;quot;🟡&amp;nbsp;铁器时代&amp;nbsp;-&amp;nbsp;半自动脚本&amp;quot;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;2:&amp;nbsp;&amp;quot;🟢&amp;nbsp;工业时代&amp;nbsp;-&amp;nbsp;自动化工具&amp;quot;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;3:&amp;nbsp;&amp;quot;🔵&amp;nbsp;信息时代&amp;nbsp;-&amp;nbsp;智能系统&amp;quot;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;4:&amp;nbsp;&amp;quot;🟣&amp;nbsp;智能时代&amp;nbsp;-&amp;nbsp;数据工厂&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@staticmethod
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;diagnose(your_situation:&amp;nbsp;dict)&amp;nbsp;-&amp;gt;&amp;nbsp;int:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;诊断企业数据采集成熟度&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;score&amp;nbsp;=&amp;nbsp;0
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;1.&amp;nbsp;数据来源多样性
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;your_situation.get(&amp;#39;sources&amp;#39;,&amp;nbsp;0)&amp;nbsp;&amp;gt;&amp;nbsp;20:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;score&amp;nbsp;+=&amp;nbsp;1
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;your_situation.get(&amp;#39;has_api&amp;#39;,&amp;nbsp;False):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;score&amp;nbsp;+=&amp;nbsp;1
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;2.&amp;nbsp;自动化程度
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;your_situation.get(&amp;#39;automation_rate&amp;#39;,&amp;nbsp;0)&amp;nbsp;&amp;gt;&amp;nbsp;0.8:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;score&amp;nbsp;+=&amp;nbsp;1
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;your_situation.get(&amp;#39;has_scheduler&amp;#39;,&amp;nbsp;False):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;score&amp;nbsp;+=&amp;nbsp;1
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;3.&amp;nbsp;智能化程度
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;your_situation.get(&amp;#39;has_ai_parsing&amp;#39;,&amp;nbsp;False):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;score&amp;nbsp;+=&amp;nbsp;1
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;your_situation.get(&amp;#39;has_self_healing&amp;#39;,&amp;nbsp;False):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;score&amp;nbsp;+=&amp;nbsp;1
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;4.&amp;nbsp;数据治理
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;your_situation.get(&amp;#39;has_data_quality&amp;#39;,&amp;nbsp;False):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;score&amp;nbsp;+=&amp;nbsp;1
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;your_situation.get(&amp;#39;has_lineage&amp;#39;,&amp;nbsp;False):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;score&amp;nbsp;+=&amp;nbsp;1
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;min(score,&amp;nbsp;4)

#&amp;nbsp;自我诊断
your_company&amp;nbsp;=&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;sources&amp;#39;:&amp;nbsp;5,&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;数据源数量
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;has_api&amp;#39;:&amp;nbsp;False,&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;是否有API接入
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;automation_rate&amp;#39;:&amp;nbsp;0.3,&amp;nbsp;#&amp;nbsp;自动化比例
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;has_scheduler&amp;#39;:&amp;nbsp;False,&amp;nbsp;#&amp;nbsp;是否有定时任务
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;has_ai_parsing&amp;#39;:&amp;nbsp;False,#&amp;nbsp;是否用AI解析
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;has_self_healing&amp;#39;:&amp;nbsp;False,&amp;nbsp;#&amp;nbsp;是否自愈
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;has_data_quality&amp;#39;:&amp;nbsp;False,&amp;nbsp;#&amp;nbsp;数据质量监控
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;has_lineage&amp;#39;:&amp;nbsp;False&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;数据血缘
}

stage&amp;nbsp;=&amp;nbsp;DataAcquisitionStage.diagnose(your_company)
print(f&amp;quot;📊&amp;nbsp;你的企业处于:&amp;nbsp;{DataAcquisitionStage.STAGES[stage]}&amp;quot;)&lt;/pre&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;大多数企业卡在0-1阶段&lt;/strong&gt;，表现为：&lt;/div&gt;&lt;ul class=&quot;ybc-ul-component list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;👨💻 人工复制粘贴Excel&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;📧 微信群发索取数据&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;🔁 重复性工作占80%时间&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;📈 数据延迟1-3天&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;❌ 错误率5-10%&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;hr/&gt;&lt;h2&gt;二、 转型蓝图：五级火箭模型&lt;/h2&gt;&lt;pre class=&quot;ybc-pre-component ybc-pre-component_not-math&quot;&gt;graph&amp;nbsp;TD
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;A[人肉爬虫&amp;nbsp;Stage&amp;nbsp;0]&amp;nbsp;--&amp;gt;&amp;nbsp;B[脚本辅助&amp;nbsp;Stage&amp;nbsp;1]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;B&amp;nbsp;--&amp;gt;&amp;nbsp;C[自动化工具&amp;nbsp;Stage&amp;nbsp;2]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;C&amp;nbsp;--&amp;gt;&amp;nbsp;D[智能系统&amp;nbsp;Stage&amp;nbsp;3]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;D&amp;nbsp;--&amp;gt;&amp;nbsp;E[数据工厂&amp;nbsp;Stage&amp;nbsp;4]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;E&amp;nbsp;--&amp;gt;&amp;nbsp;E1[数据即服务&amp;nbsp;DaaS]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;E&amp;nbsp;--&amp;gt;&amp;nbsp;E2[实时数据流]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;E&amp;nbsp;--&amp;gt;&amp;nbsp;E3[预测性采集]&lt;/pre&gt;&lt;hr/&gt;&lt;h2&gt;三、 核心组件：智能数据工厂架构&lt;/h2&gt;&lt;h3&gt;组件1：自适应采集引擎&lt;/h3&gt;&lt;div class=&quot;ybc-p&quot;&gt;能自动识别网页结构变化，支持API/WebSocket/文件等多源接入。&lt;/div&gt;&lt;pre class=&quot;ybc-pre-component ybc-pre-component_not-math&quot;&gt;#&amp;nbsp;adaptive_crawler.py
import&amp;nbsp;requests
import&amp;nbsp;json
from&amp;nbsp;bs4&amp;nbsp;import&amp;nbsp;BeautifulSoup
from&amp;nbsp;selenium&amp;nbsp;import&amp;nbsp;webdriver
from&amp;nbsp;selenium.webdriver.common.by&amp;nbsp;import&amp;nbsp;By
from&amp;nbsp;selenium.webdriver.support.ui&amp;nbsp;import&amp;nbsp;WebDriverWait
from&amp;nbsp;selenium.webdriver.support&amp;nbsp;import&amp;nbsp;expected_conditions&amp;nbsp;as&amp;nbsp;EC
import&amp;nbsp;undetected_chromedriver&amp;nbsp;as&amp;nbsp;uc
import&amp;nbsp;pandas&amp;nbsp;as&amp;nbsp;pd
import&amp;nbsp;time
from&amp;nbsp;urllib.parse&amp;nbsp;import&amp;nbsp;urlparse
import&amp;nbsp;re

class&amp;nbsp;AdaptiveCrawler:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;自适应采集引擎&amp;nbsp;-&amp;nbsp;智能识别网站类型并选择最佳采集策略&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;__init__(self,&amp;nbsp;use_selenium=False,&amp;nbsp;headless=True):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.session&amp;nbsp;=&amp;nbsp;requests.Session()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.session.headers.update({
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;User-Agent&amp;#39;:&amp;nbsp;&amp;#39;Mozilla/5.0&amp;nbsp;(Windows&amp;nbsp;NT&amp;nbsp;10.0;&amp;nbsp;Win64;&amp;nbsp;x64)&amp;nbsp;AppleWebKit/537.36&amp;#39;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;})
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.use_selenium&amp;nbsp;=&amp;nbsp;use_selenium
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;use_selenium:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;options&amp;nbsp;=&amp;nbsp;uc.ChromeOptions()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;headless:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;options.add_argument(&amp;#39;--headless&amp;#39;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;options.add_argument(&amp;#39;--disable-blink-features=AutomationControlled&amp;#39;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.driver&amp;nbsp;=&amp;nbsp;uc.Chrome(options=options)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;detect_page_type(self,&amp;nbsp;url:&amp;nbsp;str)&amp;nbsp;-&amp;gt;&amp;nbsp;dict:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;智能检测页面类型&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;response&amp;nbsp;=&amp;nbsp;self.session.get(url,&amp;nbsp;timeout=10)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;content_type&amp;nbsp;=&amp;nbsp;response.headers.get(&amp;#39;content-type&amp;#39;,&amp;nbsp;&amp;#39;&amp;#39;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;detection&amp;nbsp;=&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;type&amp;#39;:&amp;nbsp;&amp;#39;unknown&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;features&amp;#39;:&amp;nbsp;[],
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;suggested_method&amp;#39;:&amp;nbsp;&amp;#39;requests&amp;#39;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;检测JSON&amp;nbsp;API
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;&amp;#39;application/json&amp;#39;&amp;nbsp;in&amp;nbsp;content_type:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;detection[&amp;#39;type&amp;#39;]&amp;nbsp;=&amp;nbsp;&amp;#39;json_api&amp;#39;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;detection[&amp;#39;suggested_method&amp;#39;]&amp;nbsp;=&amp;nbsp;&amp;#39;requests&amp;#39;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;detection[&amp;#39;features&amp;#39;].append(&amp;#39;has_json&amp;#39;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;检测HTML页面
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;elif&amp;nbsp;&amp;#39;text/html&amp;#39;&amp;nbsp;in&amp;nbsp;content_type:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;detection[&amp;#39;type&amp;#39;]&amp;nbsp;=&amp;nbsp;&amp;#39;html_page&amp;#39;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;soup&amp;nbsp;=&amp;nbsp;BeautifulSoup(response.text,&amp;nbsp;&amp;#39;html.parser&amp;#39;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;检查是否是SPA
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;script_tags&amp;nbsp;=&amp;nbsp;soup.find_all(&amp;#39;script&amp;#39;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;spa_indicators&amp;nbsp;=&amp;nbsp;[&amp;#39;react&amp;#39;,&amp;nbsp;&amp;#39;vue&amp;#39;,&amp;nbsp;&amp;#39;angular&amp;#39;,&amp;nbsp;&amp;#39;webpack&amp;#39;]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;is_spa&amp;nbsp;=&amp;nbsp;any(indicator&amp;nbsp;in&amp;nbsp;str(script_tags).lower()&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;indicator&amp;nbsp;in&amp;nbsp;spa_indicators)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;is_spa&amp;nbsp;or&amp;nbsp;len(soup.find_all())&amp;nbsp;&amp;lt;&amp;nbsp;50:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;detection[&amp;#39;suggested_method&amp;#39;]&amp;nbsp;=&amp;nbsp;&amp;#39;selenium&amp;#39;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;detection[&amp;#39;features&amp;#39;].append(&amp;#39;is_spa&amp;#39;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;detection[&amp;#39;suggested_method&amp;#39;]&amp;nbsp;=&amp;nbsp;&amp;#39;requests&amp;#39;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;检查是否有表格数据
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;tables&amp;nbsp;=&amp;nbsp;soup.find_all(&amp;#39;table&amp;#39;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;tables:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;detection[&amp;#39;features&amp;#39;].append(&amp;#39;has_tables&amp;#39;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;检查是否有分页
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pagination&amp;nbsp;=&amp;nbsp;soup.find_all([&amp;#39;a&amp;#39;,&amp;nbsp;&amp;#39;div&amp;#39;],&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;string=re.compile(r&amp;#39;下一页|next|more&amp;#39;,&amp;nbsp;re.I))
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;pagination:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;detection[&amp;#39;features&amp;#39;].append(&amp;#39;has_pagination&amp;#39;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;detection
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;except&amp;nbsp;Exception&amp;nbsp;as&amp;nbsp;e:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(f&amp;quot;检测失败:&amp;nbsp;{e}&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;{&amp;#39;type&amp;#39;:&amp;nbsp;&amp;#39;error&amp;#39;,&amp;nbsp;&amp;#39;suggested_method&amp;#39;:&amp;nbsp;&amp;#39;requests&amp;#39;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;extract_with_best_method(self,&amp;nbsp;url:&amp;nbsp;str,&amp;nbsp;config:&amp;nbsp;dict&amp;nbsp;=&amp;nbsp;None)&amp;nbsp;-&amp;gt;&amp;nbsp;pd.DataFrame:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;使用最佳方法提取数据&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;detection&amp;nbsp;=&amp;nbsp;self.detect_page_type(url)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;method&amp;nbsp;=&amp;nbsp;detection[&amp;#39;suggested_method&amp;#39;]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(f&amp;quot;🔍&amp;nbsp;检测到页面类型:&amp;nbsp;{detection[&amp;#39;type&amp;#39;]}&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(f&amp;quot;🎯&amp;nbsp;使用采集方法:&amp;nbsp;{method}&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;method&amp;nbsp;==&amp;nbsp;&amp;#39;selenium&amp;#39;&amp;nbsp;and&amp;nbsp;self.use_selenium:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;self.extract_with_selenium(url,&amp;nbsp;config)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;self.extract_with_requests(url,&amp;nbsp;config)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;extract_with_requests(self,&amp;nbsp;url:&amp;nbsp;str,&amp;nbsp;config:&amp;nbsp;dict&amp;nbsp;=&amp;nbsp;None)&amp;nbsp;-&amp;gt;&amp;nbsp;pd.DataFrame:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;使用Requests提取&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;response&amp;nbsp;=&amp;nbsp;self.session.get(url,&amp;nbsp;timeout=30)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;response.raise_for_status()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;自动识别内容类型
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;content_type&amp;nbsp;=&amp;nbsp;response.headers.get(&amp;#39;content-type&amp;#39;,&amp;nbsp;&amp;#39;&amp;#39;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;&amp;#39;application/json&amp;#39;&amp;nbsp;in&amp;nbsp;content_type:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;data&amp;nbsp;=&amp;nbsp;json.loads(response.text)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;尝试自动展平JSON
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;df&amp;nbsp;=&amp;nbsp;self.flatten_json(data)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;HTML解析
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;df&amp;nbsp;=&amp;nbsp;self.parse_html_table(response.text)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;df
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;except&amp;nbsp;Exception&amp;nbsp;as&amp;nbsp;e:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(f&amp;quot;Requests提取失败:&amp;nbsp;{e}&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;pd.DataFrame()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;extract_with_selenium(self,&amp;nbsp;url:&amp;nbsp;str,&amp;nbsp;config:&amp;nbsp;dict&amp;nbsp;=&amp;nbsp;None)&amp;nbsp;-&amp;gt;&amp;nbsp;pd.DataFrame:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;使用Selenium处理动态页面&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;not&amp;nbsp;hasattr(self,&amp;nbsp;&amp;#39;driver&amp;#39;):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(&amp;quot;❌&amp;nbsp;Selenium未初始化&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;pd.DataFrame()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.driver.get(url)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;time.sleep(2)&amp;nbsp;&amp;nbsp;#&amp;nbsp;等待加载
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;智能等待元素出现
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;wait&amp;nbsp;=&amp;nbsp;WebDriverWait(self.driver,&amp;nbsp;10)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;尝试多种数据提取方式
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;data&amp;nbsp;=&amp;nbsp;[]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;方式1:&amp;nbsp;提取表格
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;tables&amp;nbsp;=&amp;nbsp;self.driver.find_elements(By.TAG_NAME,&amp;nbsp;&amp;#39;table&amp;#39;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;tables:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;table&amp;nbsp;in&amp;nbsp;tables[:3]:&amp;nbsp;&amp;nbsp;#&amp;nbsp;最多处理3个表格
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;html&amp;nbsp;=&amp;nbsp;table.get_attribute(&amp;#39;outerHTML&amp;#39;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;df&amp;nbsp;=&amp;nbsp;pd.read_html(html)[0]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;data.append(df)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;方式2:&amp;nbsp;提取列表
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;not&amp;nbsp;data&amp;nbsp;and&amp;nbsp;config&amp;nbsp;and&amp;nbsp;config.get(&amp;#39;item_selector&amp;#39;):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;items&amp;nbsp;=&amp;nbsp;self.driver.find_elements(By.CSS_SELECTOR,&amp;nbsp;config[&amp;#39;item_selector&amp;#39;])
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;item&amp;nbsp;in&amp;nbsp;items[:50]:&amp;nbsp;&amp;nbsp;#&amp;nbsp;限制数量
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;item_data&amp;nbsp;=&amp;nbsp;{}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;field,&amp;nbsp;selector&amp;nbsp;in&amp;nbsp;config.get(&amp;#39;field_selectors&amp;#39;,&amp;nbsp;{}).items():
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;element&amp;nbsp;=&amp;nbsp;item.find_element(By.CSS_SELECTOR,&amp;nbsp;selector)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;item_data[field]&amp;nbsp;=&amp;nbsp;element.text
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;except:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;item_data[field]&amp;nbsp;=&amp;nbsp;None
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;item_data:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;data.append(item_data)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;合并所有数据
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;data:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;isinstance(data[0],&amp;nbsp;pd.DataFrame):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;result&amp;nbsp;=&amp;nbsp;pd.concat(data,&amp;nbsp;ignore_index=True)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;result&amp;nbsp;=&amp;nbsp;pd.DataFrame(data)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;result
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;pd.DataFrame()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;except&amp;nbsp;Exception&amp;nbsp;as&amp;nbsp;e:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(f&amp;quot;Selenium提取失败:&amp;nbsp;{e}&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;pd.DataFrame()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;finally:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;不关闭driver以便重用
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pass
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;parse_html_table(self,&amp;nbsp;html:&amp;nbsp;str)&amp;nbsp;-&amp;gt;&amp;nbsp;pd.DataFrame:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;解析HTML表格&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;dfs&amp;nbsp;=&amp;nbsp;pd.read_html(html)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;dfs:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;dfs[0]&amp;nbsp;&amp;nbsp;#&amp;nbsp;返回第一个表格
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;except:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pass
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;尝试用BeautifulSoup解析
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;soup&amp;nbsp;=&amp;nbsp;BeautifulSoup(html,&amp;nbsp;&amp;#39;html.parser&amp;#39;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;tables&amp;nbsp;=&amp;nbsp;soup.find_all(&amp;#39;table&amp;#39;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;tables:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;pd.read_html(str(tables[0]))[0]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;pd.DataFrame()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;flatten_json(self,&amp;nbsp;data:&amp;nbsp;dict,&amp;nbsp;prefix:&amp;nbsp;str&amp;nbsp;=&amp;nbsp;&amp;#39;&amp;#39;)&amp;nbsp;-&amp;gt;&amp;nbsp;pd.DataFrame:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;展平嵌套JSON&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;items&amp;nbsp;=&amp;nbsp;[]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;flatten(x,&amp;nbsp;name=&amp;#39;&amp;#39;):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;isinstance(x,&amp;nbsp;dict):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;a&amp;nbsp;in&amp;nbsp;x:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;flatten(x[a],&amp;nbsp;f&amp;#39;{name}{a}.&amp;#39;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;elif&amp;nbsp;isinstance(x,&amp;nbsp;list):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;i,&amp;nbsp;a&amp;nbsp;in&amp;nbsp;enumerate(x):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;flatten(a,&amp;nbsp;f&amp;#39;{name}{i}.&amp;#39;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;items.append((name[:-1],&amp;nbsp;x))
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;flatten(data)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;df&amp;nbsp;=&amp;nbsp;pd.DataFrame(dict(items),&amp;nbsp;index=[0])
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;df
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;close(self):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;清理资源&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;hasattr(self,&amp;nbsp;&amp;#39;driver&amp;#39;):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.driver.quit()

#&amp;nbsp;使用示例
if&amp;nbsp;__name__&amp;nbsp;==&amp;nbsp;&amp;quot;__main__&amp;quot;:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;crawler&amp;nbsp;=&amp;nbsp;AdaptiveCrawler(use_selenium=True,&amp;nbsp;headless=True)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;测试不同网站
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;test_urls&amp;nbsp;=&amp;nbsp;[
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;https://httpbin.org/json&amp;quot;,&amp;nbsp;&amp;nbsp;#&amp;nbsp;JSON&amp;nbsp;API
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;https://news.ycombinator.com&amp;quot;,&amp;nbsp;&amp;nbsp;#&amp;nbsp;传统HTML
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;https://quotes.toscrape.com/js/&amp;quot;,&amp;nbsp;&amp;nbsp;#&amp;nbsp;JavaScript渲染
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;url&amp;nbsp;in&amp;nbsp;test_urls:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(f&amp;quot;\n{&amp;#39;=&amp;#39;*50}&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(f&amp;quot;测试URL:&amp;nbsp;{url}&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;df&amp;nbsp;=&amp;nbsp;crawler.extract_with_best_method(url)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;not&amp;nbsp;df.empty:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(f&amp;quot;✅&amp;nbsp;成功提取&amp;nbsp;{len(df)}&amp;nbsp;行数据&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(df.head())
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(&amp;quot;❌&amp;nbsp;提取失败&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;crawler.close()&lt;/pre&gt;&lt;h3&gt;组件2：智能解析器&lt;/h3&gt;&lt;div class=&quot;ybc-p&quot;&gt;用AI识别非结构化数据，自动适配网站改版。&lt;/div&gt;&lt;pre class=&quot;ybc-pre-component ybc-pre-component_not-math&quot;&gt;#&amp;nbsp;smart_parser.py
import&amp;nbsp;cv2
import&amp;nbsp;pytesseract
import&amp;nbsp;numpy&amp;nbsp;as&amp;nbsp;np
from&amp;nbsp;PIL&amp;nbsp;import&amp;nbsp;Image
import&amp;nbsp;io
import&amp;nbsp;pandas&amp;nbsp;as&amp;nbsp;pd
from&amp;nbsp;transformers&amp;nbsp;import&amp;nbsp;pipeline
import&amp;nbsp;easyocr
import&amp;nbsp;re

class&amp;nbsp;SmartParser:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;智能解析器&amp;nbsp;-&amp;nbsp;处理图片、PDF、复杂HTML&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;__init__(self):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;初始化OCR
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.reader&amp;nbsp;=&amp;nbsp;easyocr.Reader([&amp;#39;ch_sim&amp;#39;,&amp;nbsp;&amp;#39;en&amp;#39;])
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;初始化NLP模型
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.ner_pipeline&amp;nbsp;=&amp;nbsp;pipeline(&amp;quot;ner&amp;quot;,&amp;nbsp;grouped_entities=True)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;except:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.ner_pipeline&amp;nbsp;=&amp;nbsp;None
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;规则库
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.rules&amp;nbsp;=&amp;nbsp;self.load_parsing_rules()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;parse_with_ai(self,&amp;nbsp;content,&amp;nbsp;content_type=&amp;#39;html&amp;#39;,&amp;nbsp;domain=None):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;智能解析内容&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;content_type&amp;nbsp;==&amp;nbsp;&amp;#39;image&amp;#39;:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;self.parse_image(content)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;elif&amp;nbsp;content_type&amp;nbsp;==&amp;nbsp;&amp;#39;pdf&amp;#39;:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;self.parse_pdf(content)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;elif&amp;nbsp;content_type&amp;nbsp;==&amp;nbsp;&amp;#39;html&amp;#39;:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;self.parse_html(content,&amp;nbsp;domain)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;elif&amp;nbsp;content_type&amp;nbsp;==&amp;nbsp;&amp;#39;text&amp;#39;:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;self.parse_text(content)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;self.parse_unknown(content)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;parse_image(self,&amp;nbsp;image_data):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;解析图片中的文字和表格&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;results&amp;nbsp;=&amp;nbsp;[]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;方法1:&amp;nbsp;EasyOCR
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ocr_result&amp;nbsp;=&amp;nbsp;self.reader.readtext(image_data)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;detection&amp;nbsp;in&amp;nbsp;ocr_result:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;bbox,&amp;nbsp;text,&amp;nbsp;confidence&amp;nbsp;=&amp;nbsp;detection
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;confidence&amp;nbsp;&amp;gt;&amp;nbsp;0.5:&amp;nbsp;&amp;nbsp;#&amp;nbsp;置信度阈值
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;results.append({
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;text&amp;#39;:&amp;nbsp;text,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;confidence&amp;#39;:&amp;nbsp;confidence,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;bbox&amp;#39;:&amp;nbsp;bbox,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;source&amp;#39;:&amp;nbsp;&amp;#39;easyocr&amp;#39;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;})
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;方法2:&amp;nbsp;表格检测
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;img_array&amp;nbsp;=&amp;nbsp;np.array(Image.open(io.BytesIO(image_data)))
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;tables&amp;nbsp;=&amp;nbsp;self.detect_tables(img_array)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;table&amp;nbsp;in&amp;nbsp;tables:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;results.append({
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;type&amp;#39;:&amp;nbsp;&amp;#39;table&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;data&amp;#39;:&amp;nbsp;table,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;source&amp;#39;:&amp;nbsp;&amp;#39;table_detection&amp;#39;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;})
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;results
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;detect_tables(self,&amp;nbsp;image):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;检测图片中的表格&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;使用OpenCV检测直线
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;gray&amp;nbsp;=&amp;nbsp;cv2.cvtColor(image,&amp;nbsp;cv2.COLOR_BGR2GRAY)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;edges&amp;nbsp;=&amp;nbsp;cv2.Canny(gray,&amp;nbsp;50,&amp;nbsp;150,&amp;nbsp;apertureSize=3)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;霍夫直线检测
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;lines&amp;nbsp;=&amp;nbsp;cv2.HoughLinesP(edges,&amp;nbsp;1,&amp;nbsp;np.pi/180,&amp;nbsp;100,&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;minLineLength=100,&amp;nbsp;maxLineGap=10)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;tables&amp;nbsp;=&amp;nbsp;[]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;lines&amp;nbsp;is&amp;nbsp;not&amp;nbsp;None:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;这里简化处理，实际需要更复杂的表格检测逻辑
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;table_data&amp;nbsp;=&amp;nbsp;[[&amp;#39;检测到表格&amp;#39;,&amp;nbsp;&amp;#39;需进一步处理&amp;#39;]]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;tables.append(table_data)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;tables
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;parse_pdf(self,&amp;nbsp;pdf_data):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;解析PDF文档&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;import&amp;nbsp;PyPDF2
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pdf_reader&amp;nbsp;=&amp;nbsp;PyPDF2.PdfReader(io.BytesIO(pdf_data))
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;text&amp;nbsp;=&amp;nbsp;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;page&amp;nbsp;in&amp;nbsp;pdf_reader.pages:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;text&amp;nbsp;+=&amp;nbsp;page.extract_text()&amp;nbsp;+&amp;nbsp;&amp;quot;\n&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;提取结构化信息
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;structured_data&amp;nbsp;=&amp;nbsp;self.extract_structured_info(text)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;raw_text&amp;#39;:&amp;nbsp;text,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;structured&amp;#39;:&amp;nbsp;structured_data,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;page_count&amp;#39;:&amp;nbsp;len(pdf_reader.pages)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;parse_html(self,&amp;nbsp;html,&amp;nbsp;domain=None):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;智能解析HTML&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;from&amp;nbsp;bs4&amp;nbsp;import&amp;nbsp;BeautifulSoup
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;soup&amp;nbsp;=&amp;nbsp;BeautifulSoup(html,&amp;nbsp;&amp;#39;html.parser&amp;#39;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;移除脚本和样式
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;script&amp;nbsp;in&amp;nbsp;soup([&amp;quot;script&amp;quot;,&amp;nbsp;&amp;quot;style&amp;quot;]):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;script.decompose()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;尝试匹配已知网站规则
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;domain&amp;nbsp;and&amp;nbsp;domain&amp;nbsp;in&amp;nbsp;self.rules:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;self.apply_rules(soup,&amp;nbsp;self.rules[domain])
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;自动检测数据模式
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;data&amp;nbsp;=&amp;nbsp;self.auto_detect_data(soup)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;data
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;auto_detect_data(self,&amp;nbsp;soup):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;自动检测HTML中的数据模式&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;data&amp;nbsp;=&amp;nbsp;{}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;检测表格
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;tables&amp;nbsp;=&amp;nbsp;soup.find_all(&amp;#39;table&amp;#39;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;tables:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;data[&amp;#39;tables&amp;#39;]&amp;nbsp;=&amp;nbsp;[]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;table&amp;nbsp;in&amp;nbsp;tables[:3]:&amp;nbsp;&amp;nbsp;#&amp;nbsp;最多处理3个表格
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;df&amp;nbsp;=&amp;nbsp;pd.read_html(str(table))[0]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;data[&amp;#39;tables&amp;#39;].append(df.to_dict(&amp;#39;records&amp;#39;))
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;except:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pass
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;检测列表
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;list_items&amp;nbsp;=&amp;nbsp;soup.find_all([&amp;#39;li&amp;#39;,&amp;nbsp;&amp;#39;div&amp;#39;,&amp;nbsp;&amp;#39;tr&amp;#39;])
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;len(list_items)&amp;nbsp;&amp;gt;&amp;nbsp;3:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;items&amp;nbsp;=&amp;nbsp;[]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;item&amp;nbsp;in&amp;nbsp;list_items[:50]:&amp;nbsp;&amp;nbsp;#&amp;nbsp;限制数量
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;text&amp;nbsp;=&amp;nbsp;item.get_text(strip=True)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;text&amp;nbsp;and&amp;nbsp;len(text)&amp;nbsp;&amp;gt;&amp;nbsp;3:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;items.append(text)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;items:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;data[&amp;#39;list_items&amp;#39;]&amp;nbsp;=&amp;nbsp;items
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;检测键值对
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;key_value_pairs&amp;nbsp;=&amp;nbsp;{}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;dt&amp;nbsp;in&amp;nbsp;soup.find_all([&amp;#39;dt&amp;#39;,&amp;nbsp;&amp;#39;th&amp;#39;,&amp;nbsp;&amp;#39;strong&amp;#39;,&amp;nbsp;&amp;#39;b&amp;#39;]):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;key&amp;nbsp;=&amp;nbsp;dt.get_text(strip=True).rstrip(&amp;#39;:&amp;#39;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;查找相邻的值
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;next_sibling&amp;nbsp;=&amp;nbsp;dt.find_next_sibling([&amp;#39;dd&amp;#39;,&amp;nbsp;&amp;#39;td&amp;#39;,&amp;nbsp;&amp;#39;span&amp;#39;,&amp;nbsp;&amp;#39;div&amp;#39;])
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;next_sibling:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;value&amp;nbsp;=&amp;nbsp;next_sibling.get_text(strip=True)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;key&amp;nbsp;and&amp;nbsp;value:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;key_value_pairs[key]&amp;nbsp;=&amp;nbsp;value
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;key_value_pairs:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;data[&amp;#39;key_value&amp;#39;]&amp;nbsp;=&amp;nbsp;key_value_pairs
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;data
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;parse_text(self,&amp;nbsp;text):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;解析纯文本&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;使用NLP提取实体
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;entities&amp;nbsp;=&amp;nbsp;[]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;self.ner_pipeline:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ner_results&amp;nbsp;=&amp;nbsp;self.ner_pipeline(text[:512])&amp;nbsp;&amp;nbsp;#&amp;nbsp;限制长度
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;entities&amp;nbsp;=&amp;nbsp;[{&amp;quot;entity&amp;quot;:&amp;nbsp;ent[&amp;quot;entity_group&amp;quot;],&amp;nbsp;&amp;quot;word&amp;quot;:&amp;nbsp;ent[&amp;quot;word&amp;quot;]}&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;ent&amp;nbsp;in&amp;nbsp;ner_results]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;提取电话号码、邮箱等
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;patterns&amp;nbsp;=&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;phone&amp;#39;:&amp;nbsp;r&amp;#39;\b\d{3}[-.]?\d{3}[-.]?\d{4}\b&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;email&amp;#39;:&amp;nbsp;r&amp;#39;\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;url&amp;#39;:&amp;nbsp;r&amp;#39;https?://(?:[-\w.]|(?:%[\da-fA-F]{2}))+&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;date&amp;#39;:&amp;nbsp;r&amp;#39;\b\d{4}[-/]\d{1,2}[-/]\d{1,2}\b&amp;#39;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;extracted&amp;nbsp;=&amp;nbsp;{}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;name,&amp;nbsp;pattern&amp;nbsp;in&amp;nbsp;patterns.items():
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;matches&amp;nbsp;=&amp;nbsp;re.findall(pattern,&amp;nbsp;text,&amp;nbsp;re.IGNORECASE)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;matches:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;extracted[name]&amp;nbsp;=&amp;nbsp;matches
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;entities&amp;#39;:&amp;nbsp;entities,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;patterns&amp;#39;:&amp;nbsp;extracted,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;length&amp;#39;:&amp;nbsp;len(text)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;load_parsing_rules(self):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;加载解析规则库&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;github.com&amp;#39;:&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;repositories&amp;#39;:&amp;nbsp;&amp;#39;.repo-list&amp;nbsp;li&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;name&amp;#39;:&amp;nbsp;&amp;#39;h3&amp;nbsp;a&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;description&amp;#39;:&amp;nbsp;&amp;#39;p&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;stars&amp;#39;:&amp;nbsp;&amp;#39;.muted-link&amp;#39;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;},
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;amazon.com&amp;#39;:&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;products&amp;#39;:&amp;nbsp;&amp;#39;[data-component-type=&amp;quot;s-search-result&amp;quot;]&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;title&amp;#39;:&amp;nbsp;&amp;#39;h2&amp;nbsp;a&amp;nbsp;span&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;price&amp;#39;:&amp;nbsp;&amp;#39;.a-price-whole&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;rating&amp;#39;:&amp;nbsp;&amp;#39;.a-icon-alt&amp;#39;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;apply_rules(self,&amp;nbsp;soup,&amp;nbsp;rules):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;应用解析规则&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;data&amp;nbsp;=&amp;nbsp;{}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;container_selector&amp;nbsp;=&amp;nbsp;rules.get(&amp;#39;container&amp;#39;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;container_selector:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;items&amp;nbsp;=&amp;nbsp;soup.select(container_selector)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;records&amp;nbsp;=&amp;nbsp;[]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;item&amp;nbsp;in&amp;nbsp;items[:100]:&amp;nbsp;&amp;nbsp;#&amp;nbsp;限制数量
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;record&amp;nbsp;=&amp;nbsp;{}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;field,&amp;nbsp;selector&amp;nbsp;in&amp;nbsp;rules.items():
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;field&amp;nbsp;!=&amp;nbsp;&amp;#39;container&amp;#39;:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;element&amp;nbsp;=&amp;nbsp;item.select_one(selector)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;element:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;record[field]&amp;nbsp;=&amp;nbsp;element.get_text(strip=True)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;record:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;records.append(record)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;data[&amp;#39;records&amp;#39;]&amp;nbsp;=&amp;nbsp;records
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;data

#&amp;nbsp;使用示例
if&amp;nbsp;__name__&amp;nbsp;==&amp;nbsp;&amp;quot;__main__&amp;quot;:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;parser&amp;nbsp;=&amp;nbsp;SmartParser()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;测试文本解析
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sample_text&amp;nbsp;=&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;联系人:&amp;nbsp;张三
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;电话:&amp;nbsp;138-1234-5678
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;邮箱:&amp;nbsp;zhangsan@example.com
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;地址:&amp;nbsp;北京市海淀区中关村大街1号
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;网址:&amp;nbsp;https://www.example.com
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;日期:&amp;nbsp;2024-05-20
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;result&amp;nbsp;=&amp;nbsp;parser.parse_text(sample_text)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(&amp;quot;📄&amp;nbsp;文本解析结果:&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(f&amp;quot;实体识别:&amp;nbsp;{result.get(&amp;#39;entities&amp;#39;,&amp;nbsp;[])}&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(f&amp;quot;模式匹配:&amp;nbsp;{result.get(&amp;#39;patterns&amp;#39;,&amp;nbsp;{})}&amp;quot;)&lt;/pre&gt;&lt;h3&gt;组件3：自愈式调度器&lt;/h3&gt;&lt;div class=&quot;ybc-p&quot;&gt;自动重试、故障转移、数据质量校验。&lt;/div&gt;&lt;pre class=&quot;ybc-pre-component ybc-pre-component_not-math&quot;&gt;#&amp;nbsp;self_healing_scheduler.py
import&amp;nbsp;schedule
import&amp;nbsp;time
import&amp;nbsp;threading
from&amp;nbsp;datetime&amp;nbsp;import&amp;nbsp;datetime,&amp;nbsp;timedelta
import&amp;nbsp;json
import&amp;nbsp;sqlite3
from&amp;nbsp;typing&amp;nbsp;import&amp;nbsp;Dict,&amp;nbsp;List,&amp;nbsp;Callable
import&amp;nbsp;logging
from&amp;nbsp;dataclasses&amp;nbsp;import&amp;nbsp;dataclass
from&amp;nbsp;enum&amp;nbsp;import&amp;nbsp;Enum
import&amp;nbsp;hashlib
#&amp;nbsp;封装好API供应商demo&amp;nbsp;url=https://console.open.onebound.cn/console/?i=Lex
class&amp;nbsp;TaskStatus(Enum):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;PENDING&amp;nbsp;=&amp;nbsp;&amp;quot;pending&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;RUNNING&amp;nbsp;=&amp;nbsp;&amp;quot;running&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SUCCESS&amp;nbsp;=&amp;nbsp;&amp;quot;success&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;FAILED&amp;nbsp;=&amp;nbsp;&amp;quot;failed&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;RETRYING&amp;nbsp;=&amp;nbsp;&amp;quot;retrying&amp;quot;

@dataclass
class&amp;nbsp;Task:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;采集任务定义&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;id:&amp;nbsp;str
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;name:&amp;nbsp;str
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;url:&amp;nbsp;str
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;schedule:&amp;nbsp;str&amp;nbsp;&amp;nbsp;#&amp;nbsp;cron表达式
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;parser_config:&amp;nbsp;Dict
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;max_retries:&amp;nbsp;int&amp;nbsp;=&amp;nbsp;3
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;timeout:&amp;nbsp;int&amp;nbsp;=&amp;nbsp;300
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;created_at:&amp;nbsp;datetime&amp;nbsp;=&amp;nbsp;None
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;__post_init__(self):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;self.created_at&amp;nbsp;is&amp;nbsp;None:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.created_at&amp;nbsp;=&amp;nbsp;datetime.now()

class&amp;nbsp;SelfHealingScheduler:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;自愈式任务调度器&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;__init__(self,&amp;nbsp;db_path=&amp;#39;tasks.db&amp;#39;):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.db_path&amp;nbsp;=&amp;nbsp;db_path
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.tasks:&amp;nbsp;Dict[str,&amp;nbsp;Task]&amp;nbsp;=&amp;nbsp;{}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.task_handlers:&amp;nbsp;Dict[str,&amp;nbsp;Callable]&amp;nbsp;=&amp;nbsp;{}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.running&amp;nbsp;=&amp;nbsp;False
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.worker_thread&amp;nbsp;=&amp;nbsp;None
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;初始化数据库
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.init_database()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;加载任务
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.load_tasks()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;设置日志
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;logging.basicConfig(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;level=logging.INFO,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;format=&amp;#39;%(asctime)s&amp;nbsp;-&amp;nbsp;%(name)s&amp;nbsp;-&amp;nbsp;%(levelname)s&amp;nbsp;-&amp;nbsp;%(message)s&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;handlers=[
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;logging.FileHandler(&amp;#39;scheduler.log&amp;#39;),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;logging.StreamHandler()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.logger&amp;nbsp;=&amp;nbsp;logging.getLogger(__name__)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;init_database(self):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;初始化任务数据库&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;conn&amp;nbsp;=&amp;nbsp;sqlite3.connect(self.db_path)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cursor&amp;nbsp;=&amp;nbsp;conn.cursor()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;任务表
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cursor.execute(&amp;#39;&amp;#39;&amp;#39;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;CREATE&amp;nbsp;TABLE&amp;nbsp;IF&amp;nbsp;NOT&amp;nbsp;EXISTS&amp;nbsp;tasks&amp;nbsp;(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;id&amp;nbsp;TEXT&amp;nbsp;PRIMARY&amp;nbsp;KEY,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;name&amp;nbsp;TEXT,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;url&amp;nbsp;TEXT,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;schedule&amp;nbsp;TEXT,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;parser_config&amp;nbsp;TEXT,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;max_retries&amp;nbsp;INTEGER,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;timeout&amp;nbsp;INTEGER,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;created_at&amp;nbsp;TIMESTAMP,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;enabled&amp;nbsp;INTEGER&amp;nbsp;DEFAULT&amp;nbsp;1
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;&amp;#39;&amp;#39;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;执行记录表
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cursor.execute(&amp;#39;&amp;#39;&amp;#39;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;CREATE&amp;nbsp;TABLE&amp;nbsp;IF&amp;nbsp;NOT&amp;nbsp;EXISTS&amp;nbsp;executions&amp;nbsp;(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;id&amp;nbsp;TEXT&amp;nbsp;PRIMARY&amp;nbsp;KEY,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;task_id&amp;nbsp;TEXT,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;started_at&amp;nbsp;TIMESTAMP,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;finished_at&amp;nbsp;TIMESTAMP,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;status&amp;nbsp;TEXT,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;error_message&amp;nbsp;TEXT,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;data_count&amp;nbsp;INTEGER,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;execution_time&amp;nbsp;REAL,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;retry_count&amp;nbsp;INTEGER,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;FOREIGN&amp;nbsp;KEY&amp;nbsp;(task_id)&amp;nbsp;REFERENCES&amp;nbsp;tasks&amp;nbsp;(id)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;&amp;#39;&amp;#39;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;数据质量表
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cursor.execute(&amp;#39;&amp;#39;&amp;#39;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;CREATE&amp;nbsp;TABLE&amp;nbsp;IF&amp;nbsp;NOT&amp;nbsp;EXISTS&amp;nbsp;data_quality&amp;nbsp;(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;id&amp;nbsp;INTEGER&amp;nbsp;PRIMARY&amp;nbsp;KEY&amp;nbsp;AUTOINCREMENT,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;task_id&amp;nbsp;TEXT,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;execution_id&amp;nbsp;TEXT,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;check_time&amp;nbsp;TIMESTAMP,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;metric_name&amp;nbsp;TEXT,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;metric_value&amp;nbsp;REAL,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;threshold&amp;nbsp;REAL,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;passed&amp;nbsp;INTEGER,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;FOREIGN&amp;nbsp;KEY&amp;nbsp;(task_id)&amp;nbsp;REFERENCES&amp;nbsp;tasks&amp;nbsp;(id),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;FOREIGN&amp;nbsp;KEY&amp;nbsp;(execution_id)&amp;nbsp;REFERENCES&amp;nbsp;executions&amp;nbsp;(id)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;&amp;#39;&amp;#39;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;conn.commit()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;conn.close()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;add_task(self,&amp;nbsp;task:&amp;nbsp;Task,&amp;nbsp;handler:&amp;nbsp;Callable):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;添加任务&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.tasks[task.id]&amp;nbsp;=&amp;nbsp;task
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.task_handlers[task.id]&amp;nbsp;=&amp;nbsp;handler
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;保存到数据库
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;conn&amp;nbsp;=&amp;nbsp;sqlite3.connect(self.db_path)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cursor&amp;nbsp;=&amp;nbsp;conn.cursor()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cursor.execute(&amp;#39;&amp;#39;&amp;#39;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;INSERT&amp;nbsp;OR&amp;nbsp;REPLACE&amp;nbsp;INTO&amp;nbsp;tasks&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;(id,&amp;nbsp;name,&amp;nbsp;url,&amp;nbsp;schedule,&amp;nbsp;parser_config,&amp;nbsp;max_retries,&amp;nbsp;timeout,&amp;nbsp;created_at)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;VALUES&amp;nbsp;(?,&amp;nbsp;?,&amp;nbsp;?,&amp;nbsp;?,&amp;nbsp;?,&amp;nbsp;?,&amp;nbsp;?,&amp;nbsp;?)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;&amp;#39;&amp;#39;,&amp;nbsp;(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;task.id,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;task.name,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;task.url,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;task.schedule,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;json.dumps(task.parser_config),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;task.max_retries,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;task.timeout,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;task.created_at.isoformat()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;))
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;conn.commit()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;conn.close()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.logger.info(f&amp;quot;✅&amp;nbsp;添加任务:&amp;nbsp;{task.name}&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;remove_task(self,&amp;nbsp;task_id:&amp;nbsp;str):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;移除任务&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;task_id&amp;nbsp;in&amp;nbsp;self.tasks:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;del&amp;nbsp;self.tasks[task_id]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;del&amp;nbsp;self.task_handlers[task_id]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;conn&amp;nbsp;=&amp;nbsp;sqlite3.connect(self.db_path)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cursor&amp;nbsp;=&amp;nbsp;conn.cursor()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cursor.execute(&amp;#39;DELETE&amp;nbsp;FROM&amp;nbsp;tasks&amp;nbsp;WHERE&amp;nbsp;id&amp;nbsp;=&amp;nbsp;?&amp;#39;,&amp;nbsp;(task_id,))
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;conn.commit()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;conn.close()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.logger.info(f&amp;quot;🗑️&amp;nbsp;移除任务:&amp;nbsp;{task_id}&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;load_tasks(self):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;从数据库加载任务&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;conn&amp;nbsp;=&amp;nbsp;sqlite3.connect(self.db_path)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cursor&amp;nbsp;=&amp;nbsp;conn.cursor()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cursor.execute(&amp;#39;SELECT&amp;nbsp;*&amp;nbsp;FROM&amp;nbsp;tasks&amp;nbsp;WHERE&amp;nbsp;enabled&amp;nbsp;=&amp;nbsp;1&amp;#39;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;rows&amp;nbsp;=&amp;nbsp;cursor.fetchall()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;row&amp;nbsp;in&amp;nbsp;rows:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;task&amp;nbsp;=&amp;nbsp;Task(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;id=row[0],
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;name=row[1],
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;url=row[2],
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;schedule=row[3],
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;parser_config=json.loads(row[4]),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;max_retries=row[5],
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;timeout=row[6],
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;created_at=datetime.fromisoformat(row[7])
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.tasks[task.id]&amp;nbsp;=&amp;nbsp;task
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;conn.close()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.logger.info(f&amp;quot;📥&amp;nbsp;加载&amp;nbsp;{len(self.tasks)}&amp;nbsp;个任务&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;schedule_all_tasks(self):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;调度所有任务&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;task_id,&amp;nbsp;task&amp;nbsp;in&amp;nbsp;self.tasks.items():
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;解析cron表达式
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;task.schedule&amp;nbsp;==&amp;nbsp;&amp;#39;hourly&amp;#39;:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;schedule.every().hour.do(self.run_task,&amp;nbsp;task_id)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;elif&amp;nbsp;task.schedule&amp;nbsp;==&amp;nbsp;&amp;#39;daily&amp;#39;:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;schedule.every().day.at(&amp;quot;00:00&amp;quot;).do(self.run_task,&amp;nbsp;task_id)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;elif&amp;nbsp;task.schedule.startswith(&amp;#39;every&amp;#39;):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;解析&amp;nbsp;every.10.minutes
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;parts&amp;nbsp;=&amp;nbsp;task.schedule.split(&amp;#39;.&amp;#39;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;len(parts)&amp;nbsp;==&amp;nbsp;3:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;interval&amp;nbsp;=&amp;nbsp;int(parts[1])
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;unit&amp;nbsp;=&amp;nbsp;parts[2]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;unit&amp;nbsp;==&amp;nbsp;&amp;#39;minutes&amp;#39;:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;schedule.every(interval).minutes.do(self.run_task,&amp;nbsp;task_id)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;elif&amp;nbsp;unit&amp;nbsp;==&amp;nbsp;&amp;#39;hours&amp;#39;:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;schedule.every(interval).hours.do(self.run_task,&amp;nbsp;task_id)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;elif&amp;nbsp;unit&amp;nbsp;==&amp;nbsp;&amp;#39;days&amp;#39;:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;schedule.every(interval).days.do(self.run_task,&amp;nbsp;task_id)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;默认每小时
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;schedule.every().hour.do(self.run_task,&amp;nbsp;task_id)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.logger.info(f&amp;quot;⏰&amp;nbsp;调度任务:&amp;nbsp;{task.name}&amp;nbsp;-&amp;nbsp;{task.schedule}&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;run_task(self,&amp;nbsp;task_id:&amp;nbsp;str,&amp;nbsp;retry_count:&amp;nbsp;int&amp;nbsp;=&amp;nbsp;0):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;执行单个任务&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;task_id&amp;nbsp;not&amp;nbsp;in&amp;nbsp;self.tasks&amp;nbsp;or&amp;nbsp;task_id&amp;nbsp;not&amp;nbsp;in&amp;nbsp;self.task_handlers:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.logger.error(f&amp;quot;任务不存在:&amp;nbsp;{task_id}&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;task&amp;nbsp;=&amp;nbsp;self.tasks[task_id]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;handler&amp;nbsp;=&amp;nbsp;self.task_handlers[task_id]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;execution_id&amp;nbsp;=&amp;nbsp;f&amp;quot;{task_id}_{datetime.now().strftime(&amp;#39;%Y%m%d%H%M%S&amp;#39;)}&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;started_at&amp;nbsp;=&amp;nbsp;datetime.now()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.logger.info(f&amp;quot;🚀&amp;nbsp;开始执行:&amp;nbsp;{task.name}&amp;nbsp;(尝试&amp;nbsp;{retry_count&amp;nbsp;+&amp;nbsp;1})&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;记录执行开始
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.record_execution_start(execution_id,&amp;nbsp;task_id,&amp;nbsp;started_at)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;执行任务
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;result&amp;nbsp;=&amp;nbsp;handler(task.url,&amp;nbsp;task.parser_config)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;finished_at&amp;nbsp;=&amp;nbsp;datetime.now()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;execution_time&amp;nbsp;=&amp;nbsp;(finished_at&amp;nbsp;-&amp;nbsp;started_at).total_seconds()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;数据质量检查
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;quality_passed&amp;nbsp;=&amp;nbsp;self.check_data_quality(task_id,&amp;nbsp;execution_id,&amp;nbsp;result)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;quality_passed:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;status&amp;nbsp;=&amp;nbsp;TaskStatus.SUCCESS
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;error_message&amp;nbsp;=&amp;nbsp;None
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.logger.info(f&amp;quot;✅&amp;nbsp;任务成功:&amp;nbsp;{task.name},&amp;nbsp;耗时:&amp;nbsp;{execution_time:.1f}s&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;status&amp;nbsp;=&amp;nbsp;TaskStatus.FAILED
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;error_message&amp;nbsp;=&amp;nbsp;&amp;quot;数据质量检查失败&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.logger.warning(f&amp;quot;⚠️&amp;nbsp;数据质量检查失败:&amp;nbsp;{task.name}&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;记录执行结果
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.record_execution_finish(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;execution_id,&amp;nbsp;finished_at,&amp;nbsp;status.value,&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;error_message,&amp;nbsp;len(result)&amp;nbsp;if&amp;nbsp;isinstance(result,&amp;nbsp;list)&amp;nbsp;else&amp;nbsp;0,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;execution_time,&amp;nbsp;retry_count
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;result
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;封装好API供应商demo&amp;nbsp;url=https://console.open.onebound.cn/console/?i=Lex
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;except&amp;nbsp;Exception&amp;nbsp;as&amp;nbsp;e:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;finished_at&amp;nbsp;=&amp;nbsp;datetime.now()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;execution_time&amp;nbsp;=&amp;nbsp;(finished_at&amp;nbsp;-&amp;nbsp;started_at).total_seconds()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;error_msg&amp;nbsp;=&amp;nbsp;str(e)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.logger.error(f&amp;quot;❌&amp;nbsp;任务失败:&amp;nbsp;{task.name},&amp;nbsp;错误:&amp;nbsp;{error_msg}&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;记录失败
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.record_execution_finish(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;execution_id,&amp;nbsp;finished_at,&amp;nbsp;TaskStatus.FAILED.value,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;error_msg,&amp;nbsp;0,&amp;nbsp;execution_time,&amp;nbsp;retry_count
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;重试逻辑
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;retry_count&amp;nbsp;&amp;lt;&amp;nbsp;task.max_retries:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;delay&amp;nbsp;=&amp;nbsp;2&amp;nbsp;**&amp;nbsp;retry_count&amp;nbsp;&amp;nbsp;#&amp;nbsp;指数退避
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.logger.info(f&amp;quot;🔄&amp;nbsp;将在&amp;nbsp;{delay}&amp;nbsp;秒后重试...&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;time.sleep(delay)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;self.run_task(task_id,&amp;nbsp;retry_count&amp;nbsp;+&amp;nbsp;1)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.logger.error(f&amp;quot;💥&amp;nbsp;任务重试次数用尽:&amp;nbsp;{task.name}&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;发送告警
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.send_alert(task,&amp;nbsp;error_msg)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;None
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;check_data_quality(self,&amp;nbsp;task_id:&amp;nbsp;str,&amp;nbsp;execution_id:&amp;nbsp;str,&amp;nbsp;data)&amp;nbsp;-&amp;gt;&amp;nbsp;bool:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;检查数据质量&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;not&amp;nbsp;data:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.record_quality_check(task_id,&amp;nbsp;execution_id,&amp;nbsp;&amp;#39;has_data&amp;#39;,&amp;nbsp;0,&amp;nbsp;1,&amp;nbsp;False)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;False
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;checks&amp;nbsp;=&amp;nbsp;[
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;(&amp;#39;data_count&amp;#39;,&amp;nbsp;len(data)&amp;nbsp;if&amp;nbsp;isinstance(data,&amp;nbsp;list)&amp;nbsp;else&amp;nbsp;1,&amp;nbsp;1),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;(&amp;#39;null_ratio&amp;#39;,&amp;nbsp;self.calculate_null_ratio(data),&amp;nbsp;0.3),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;passed_all&amp;nbsp;=&amp;nbsp;True
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;metric_name,&amp;nbsp;metric_value,&amp;nbsp;threshold&amp;nbsp;in&amp;nbsp;checks:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;passed&amp;nbsp;=&amp;nbsp;metric_value&amp;nbsp;&amp;lt;=&amp;nbsp;threshold&amp;nbsp;if&amp;nbsp;metric_name&amp;nbsp;==&amp;nbsp;&amp;#39;null_ratio&amp;#39;&amp;nbsp;else&amp;nbsp;metric_value&amp;nbsp;&amp;gt;=&amp;nbsp;threshold
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.record_quality_check(task_id,&amp;nbsp;execution_id,&amp;nbsp;metric_name,&amp;nbsp;metric_value,&amp;nbsp;threshold,&amp;nbsp;passed)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;not&amp;nbsp;passed:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;passed_all&amp;nbsp;=&amp;nbsp;False
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.logger.warning(f&amp;quot;数据质量检查失败:&amp;nbsp;{metric_name}={metric_value},&amp;nbsp;阈值={threshold}&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;passed_all
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;calculate_null_ratio(self,&amp;nbsp;data):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;计算空值比例&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;not&amp;nbsp;isinstance(data,&amp;nbsp;list)&amp;nbsp;or&amp;nbsp;not&amp;nbsp;data:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;1.0
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;isinstance(data[0],&amp;nbsp;dict):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;total_cells&amp;nbsp;=&amp;nbsp;len(data)&amp;nbsp;*&amp;nbsp;len(data[0])
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;null_cells&amp;nbsp;=&amp;nbsp;sum(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;1&amp;nbsp;for&amp;nbsp;row&amp;nbsp;in&amp;nbsp;data&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;value&amp;nbsp;in&amp;nbsp;row.values()&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;value&amp;nbsp;is&amp;nbsp;None&amp;nbsp;or&amp;nbsp;str(value).strip()&amp;nbsp;==&amp;nbsp;&amp;#39;&amp;#39;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;null_cells&amp;nbsp;/&amp;nbsp;total_cells&amp;nbsp;if&amp;nbsp;total_cells&amp;nbsp;&amp;gt;&amp;nbsp;0&amp;nbsp;else&amp;nbsp;1.0
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;0.0
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;record_execution_start(self,&amp;nbsp;execution_id:&amp;nbsp;str,&amp;nbsp;task_id:&amp;nbsp;str,&amp;nbsp;started_at:&amp;nbsp;datetime):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;记录执行开始&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;conn&amp;nbsp;=&amp;nbsp;sqlite3.connect(self.db_path)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cursor&amp;nbsp;=&amp;nbsp;conn.cursor()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cursor.execute(&amp;#39;&amp;#39;&amp;#39;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;INSERT&amp;nbsp;INTO&amp;nbsp;executions&amp;nbsp;(id,&amp;nbsp;task_id,&amp;nbsp;started_at,&amp;nbsp;status)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;VALUES&amp;nbsp;(?,&amp;nbsp;?,&amp;nbsp;?,&amp;nbsp;?)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;&amp;#39;&amp;#39;,&amp;nbsp;(execution_id,&amp;nbsp;task_id,&amp;nbsp;started_at.isoformat(),&amp;nbsp;TaskStatus.RUNNING.value))
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;conn.commit()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;conn.close()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;record_execution_finish(self,&amp;nbsp;execution_id:&amp;nbsp;str,&amp;nbsp;finished_at:&amp;nbsp;datetime,&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;status:&amp;nbsp;str,&amp;nbsp;error_message:&amp;nbsp;str,&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;data_count:&amp;nbsp;int,&amp;nbsp;execution_time:&amp;nbsp;float,&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;retry_count:&amp;nbsp;int):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;记录执行完成&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;conn&amp;nbsp;=&amp;nbsp;sqlite3.connect(self.db_path)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cursor&amp;nbsp;=&amp;nbsp;conn.cursor()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cursor.execute(&amp;#39;&amp;#39;&amp;#39;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;UPDATE&amp;nbsp;executions&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SET&amp;nbsp;finished_at&amp;nbsp;=&amp;nbsp;?,&amp;nbsp;status&amp;nbsp;=&amp;nbsp;?,&amp;nbsp;error_message&amp;nbsp;=&amp;nbsp;?,&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;data_count&amp;nbsp;=&amp;nbsp;?,&amp;nbsp;execution_time&amp;nbsp;=&amp;nbsp;?,&amp;nbsp;retry_count&amp;nbsp;=&amp;nbsp;?
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;WHERE&amp;nbsp;id&amp;nbsp;=&amp;nbsp;?
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;&amp;#39;&amp;#39;,&amp;nbsp;(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;finished_at.isoformat(),&amp;nbsp;status,&amp;nbsp;error_message,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;data_count,&amp;nbsp;execution_time,&amp;nbsp;retry_count,&amp;nbsp;execution_id
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;))
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;conn.commit()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;conn.close()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;record_quality_check(self,&amp;nbsp;task_id:&amp;nbsp;str,&amp;nbsp;execution_id:&amp;nbsp;str,&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;metric_name:&amp;nbsp;str,&amp;nbsp;metric_value:&amp;nbsp;float,&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;threshold:&amp;nbsp;float,&amp;nbsp;passed:&amp;nbsp;bool):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;记录质量检查结果&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;conn&amp;nbsp;=&amp;nbsp;sqlite3.connect(self.db_path)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cursor&amp;nbsp;=&amp;nbsp;conn.cursor()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cursor.execute(&amp;#39;&amp;#39;&amp;#39;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;INSERT&amp;nbsp;INTO&amp;nbsp;data_quality&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;(task_id,&amp;nbsp;execution_id,&amp;nbsp;check_time,&amp;nbsp;metric_name,&amp;nbsp;metric_value,&amp;nbsp;threshold,&amp;nbsp;passed)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;VALUES&amp;nbsp;(?,&amp;nbsp;?,&amp;nbsp;?,&amp;nbsp;?,&amp;nbsp;?,&amp;nbsp;?,&amp;nbsp;?)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;&amp;#39;&amp;#39;,&amp;nbsp;(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;task_id,&amp;nbsp;execution_id,&amp;nbsp;datetime.now().isoformat(),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;metric_name,&amp;nbsp;metric_value,&amp;nbsp;threshold,&amp;nbsp;1&amp;nbsp;if&amp;nbsp;passed&amp;nbsp;else&amp;nbsp;0
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;))
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;conn.commit()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;conn.close()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;send_alert(self,&amp;nbsp;task:&amp;nbsp;Task,&amp;nbsp;error_message:&amp;nbsp;str):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;发送告警&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;这里可以实现邮件、钉钉、企业微信告警
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;alert_message&amp;nbsp;=&amp;nbsp;f&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;🚨&amp;nbsp;数据采集告警
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;任务:&amp;nbsp;{task.name}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;URL:&amp;nbsp;{task.url}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;时间:&amp;nbsp;{datetime.now().strftime(&amp;#39;%Y-%m-%d&amp;nbsp;%H:%M:%S&amp;#39;)}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;错误:&amp;nbsp;{error_message}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;重试次数:&amp;nbsp;{task.max_retries}&amp;nbsp;次已用尽
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;封装好API供应商demo&amp;nbsp;url=https://console.open.onebound.cn/console/?i=Lex
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.logger.error(alert_message)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;示例:&amp;nbsp;打印到控制台
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(alert_message)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;start(self):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;启动调度器&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.running&amp;nbsp;=&amp;nbsp;True
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.schedule_all_tasks()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.worker_thread&amp;nbsp;=&amp;nbsp;threading.Thread(target=self.run_scheduler,&amp;nbsp;daemon=True)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.worker_thread.start()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.logger.info(&amp;quot;🚀&amp;nbsp;调度器已启动&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;run_scheduler(self):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;调度器主循环&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;while&amp;nbsp;self.running:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;schedule.run_pending()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;time.sleep(1)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;stop(self):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;停止调度器&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.running&amp;nbsp;=&amp;nbsp;False
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;self.worker_thread:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.worker_thread.join(timeout=5)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.logger.info(&amp;quot;🛑&amp;nbsp;调度器已停止&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;get_task_stats(self,&amp;nbsp;days:&amp;nbsp;int&amp;nbsp;=&amp;nbsp;7)&amp;nbsp;-&amp;gt;&amp;nbsp;Dict:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;获取任务统计&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;conn&amp;nbsp;=&amp;nbsp;sqlite3.connect(self.db_path)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cursor&amp;nbsp;=&amp;nbsp;conn.cursor()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cutoff&amp;nbsp;=&amp;nbsp;(datetime.now()&amp;nbsp;-&amp;nbsp;timedelta(days=days)).isoformat()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;成功率
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cursor.execute(&amp;#39;&amp;#39;&amp;#39;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SELECT&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;task_id,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;COUNT(*)&amp;nbsp;as&amp;nbsp;total,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SUM(CASE&amp;nbsp;WHEN&amp;nbsp;status&amp;nbsp;=&amp;nbsp;&amp;#39;success&amp;#39;&amp;nbsp;THEN&amp;nbsp;1&amp;nbsp;ELSE&amp;nbsp;0&amp;nbsp;END)&amp;nbsp;as&amp;nbsp;success
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;FROM&amp;nbsp;executions&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;WHERE&amp;nbsp;started_at&amp;nbsp;&amp;gt;&amp;nbsp;?
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;GROUP&amp;nbsp;BY&amp;nbsp;task_id
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;&amp;#39;&amp;#39;,&amp;nbsp;(cutoff,))
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;stats&amp;nbsp;=&amp;nbsp;{}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;row&amp;nbsp;in&amp;nbsp;cursor.fetchall():
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;task_id,&amp;nbsp;total,&amp;nbsp;success&amp;nbsp;=&amp;nbsp;row
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;total&amp;nbsp;&amp;gt;&amp;nbsp;0:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;stats[task_id]&amp;nbsp;=&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;total&amp;#39;:&amp;nbsp;total,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;success&amp;#39;:&amp;nbsp;success,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;success_rate&amp;#39;:&amp;nbsp;success&amp;nbsp;/&amp;nbsp;total
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;平均执行时间
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cursor.execute(&amp;#39;&amp;#39;&amp;#39;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SELECT&amp;nbsp;task_id,&amp;nbsp;AVG(execution_time)&amp;nbsp;as&amp;nbsp;avg_time
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;FROM&amp;nbsp;executions&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;WHERE&amp;nbsp;started_at&amp;nbsp;&amp;gt;&amp;nbsp;?&amp;nbsp;AND&amp;nbsp;status&amp;nbsp;=&amp;nbsp;&amp;#39;success&amp;#39;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;GROUP&amp;nbsp;BY&amp;nbsp;task_id
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;&amp;#39;&amp;#39;,&amp;nbsp;(cutoff,))
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;row&amp;nbsp;in&amp;nbsp;cursor.fetchall():
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;task_id,&amp;nbsp;avg_time&amp;nbsp;=&amp;nbsp;row
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;task_id&amp;nbsp;in&amp;nbsp;stats:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;stats[task_id][&amp;#39;avg_time&amp;#39;]&amp;nbsp;=&amp;nbsp;avg_time
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;conn.close()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;stats

#&amp;nbsp;使用示例
if&amp;nbsp;__name__&amp;nbsp;==&amp;nbsp;&amp;quot;__main__&amp;quot;:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;创建调度器
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;scheduler&amp;nbsp;=&amp;nbsp;SelfHealingScheduler()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;定义任务处理器
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;sample_handler(url,&amp;nbsp;config):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;示例任务处理器&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;import&amp;nbsp;requests
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;response&amp;nbsp;=&amp;nbsp;requests.get(url,&amp;nbsp;timeout=10)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;response.status_code&amp;nbsp;==&amp;nbsp;200:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;模拟数据处理
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;[{&amp;#39;id&amp;#39;:&amp;nbsp;i,&amp;nbsp;&amp;#39;data&amp;#39;:&amp;nbsp;f&amp;#39;sample_{i}&amp;#39;}&amp;nbsp;for&amp;nbsp;i&amp;nbsp;in&amp;nbsp;range(10)]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;raise&amp;nbsp;Exception(f&amp;quot;HTTP&amp;nbsp;{response.status_code}&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;添加任务
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;task&amp;nbsp;=&amp;nbsp;Task(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;id=&amp;#39;test_task_1&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;name=&amp;#39;示例采集任务&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;url=&amp;#39;https://httpbin.org/json&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;schedule=&amp;#39;every.5.minutes&amp;#39;,&amp;nbsp;&amp;nbsp;#&amp;nbsp;每5分钟
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;parser_config={&amp;#39;type&amp;#39;:&amp;nbsp;&amp;#39;json&amp;#39;},
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;max_retries=2,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;timeout=30
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;scheduler.add_task(task,&amp;nbsp;sample_handler)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;启动调度器
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(&amp;quot;⏰&amp;nbsp;启动调度器，运行5分钟后停止...&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;scheduler.start()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;运行5分钟
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;time.sleep(300)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;获取统计
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;stats&amp;nbsp;=&amp;nbsp;scheduler.get_task_stats(1)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(&amp;quot;\n📊&amp;nbsp;任务统计:&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;task_id,&amp;nbsp;stat&amp;nbsp;in&amp;nbsp;stats.items():
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(f&amp;quot;{task_id}:&amp;nbsp;成功率&amp;nbsp;{stat[&amp;#39;success_rate&amp;#39;]:.1%},&amp;nbsp;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;f&amp;quot;平均耗时&amp;nbsp;{stat.get(&amp;#39;avg_time&amp;#39;,&amp;nbsp;0):.1f}s&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;finally:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;scheduler.stop()&lt;/pre&gt;&lt;hr/&gt;&lt;h2&gt;四、 实施路径：12周转型计划&lt;/h2&gt;&lt;h3&gt;第1-2周：现状评估与试点&lt;/h3&gt;&lt;ol class=&quot;ybc-ol-component ybc-ol-component_1 list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;盘点数据源&lt;/strong&gt;：列出所有人工采集的数据源&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;选择试点&lt;/strong&gt;：选取3-5个高价值、规则明确的数据源&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;建立基线&lt;/strong&gt;：记录当前人工采集的时间、成本、错误率&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;h3&gt;第3-6周：工具开发与部署&lt;/h3&gt;&lt;ol class=&quot;ybc-ol-component ybc-ol-component_1 list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;开发核心引擎&lt;/strong&gt;：使用上述代码构建基础采集系统&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;建立数据管道&lt;/strong&gt;：从采集→清洗→存储的完整流程&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;培训关键用户&lt;/strong&gt;：教会业务人员使用新工具&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;h3&gt;第7-9周：规模化推广&lt;/h3&gt;&lt;ol class=&quot;ybc-ol-component ybc-ol-component_1 list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;迁移更多数据源&lt;/strong&gt;：每周迁移5-10个数据源&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;建立监控体系&lt;/strong&gt;：数据质量、系统健康度监控&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;优化性能&lt;/strong&gt;：处理速度、稳定性优化&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;h3&gt;第10-12周：智能化升级&lt;/h3&gt;&lt;ol class=&quot;ybc-ol-component ybc-ol-component_1 list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;引入AI能力&lt;/strong&gt;：智能解析、异常检测&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;建立告警机制&lt;/strong&gt;：自动发现问题并通知&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;编制操作手册&lt;/strong&gt;：SOP、故障处理指南&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;hr/&gt;&lt;h2&gt;五、 成功案例：转型前后对比&lt;/h2&gt;&lt;div class=&quot;hyc-common-markdown__table-wrapper&quot; data-has-scroll=&quot;false&quot; style=&quot;font-size: 16px; border-collapse: separate; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;div style=&quot;font-size: 16px; border-collapse: separate; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;table&gt;&lt;thead style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;tr style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot; class=&quot;firstRow&quot;&gt;&lt;th style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;指标&lt;/div&gt;&lt;/th&gt;&lt;th style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;转型前（人工）&lt;/div&gt;&lt;/th&gt;&lt;th style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;转型后（智能工厂）&lt;/div&gt;&lt;/th&gt;&lt;th style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;提升&lt;/div&gt;&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;tr style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;strong style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;采集效率&lt;/strong&gt;&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;1人天/数据源&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;5分钟/数据源&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;strong style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;96倍&lt;/strong&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;strong style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;数据延迟&lt;/strong&gt;&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;1-3天&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;分钟级&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;strong style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;99%减少&lt;/strong&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;strong style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;错误率&lt;/strong&gt;&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;5-10%&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&amp;lt;0.1%&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;strong style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;99%降低&lt;/strong&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;strong style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;人力成本&lt;/strong&gt;&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;5人团队&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;1人维护&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;strong style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;80%降低&lt;/strong&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;strong style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;数据价值&lt;/strong&gt;&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;滞后决策&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;实时洞察&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;strong style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;无法量化&lt;/strong&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;/div&gt;&lt;hr/&gt;&lt;h2&gt;💡 最后建议&lt;/h2&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;不要试图一步到位&lt;/strong&gt;。从最有痛点的1-2个场景开始，快速验证价值，然后逐步扩展。记住：&lt;strong&gt;完成比完美更重要&lt;/strong&gt;。&lt;/div&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;立即行动清单&lt;/strong&gt;：&lt;/div&gt;&lt;ol class=&quot;ybc-ol-component ybc-ol-component_1 list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;[ ] 盘点你团队中还在人工采集的数据&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;[ ] 选择一个本周就可以自动化的数据源&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;[ ] 运行上面的示例代码，看看效果&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;[ ] 制定你的12周转型计划&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;数据是新时代的石油，但人工采集就像用勺子挖油井。是时候升级到智能钻井平台了。&lt;/strong&gt;&lt;/div&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;互动话题&lt;/strong&gt;：你的团队还在人工采集哪些数据？最大的痛点是什么？评论区聊聊，我可以给你针对性的自动化建议！&lt;/div&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;</description><pubDate>Sat, 23 May 2026 13:43:52 +0800</pubDate></item><item><title>为人工抓取数据革命做准备需要深思熟虑的策略（附python源码）</title><link>https://alexob.com/?id=372</link><description>&lt;div class=&quot;ybc-p&quot;&gt;“人工抓取数据革命”并不是指完全取代人工，而是&lt;strong&gt;将人类从重复、低效的“数据搬运工”角色中解放出来&lt;/strong&gt;，转向更高价值的决策、分析和治理工作。这场革命的核心是构建一套&lt;strong&gt;人机协同的智能数据采集体系&lt;/strong&gt;。&lt;/div&gt;&lt;h2&gt;一、 战略蓝图：从“人工抓取”到“智能治理”&lt;/h2&gt;&lt;div class=&quot;ybc-p&quot;&gt;单纯的技术工具替换治标不治本。你需要构建一个包含&lt;strong&gt;流程、技术、数据、组织&lt;/strong&gt;四个维度的完整策略。&lt;/div&gt;&lt;div class=&quot;hyc-common-markdown__table-wrapper&quot; data-has-scroll=&quot;false&quot; style=&quot;font-size: 16px; border-collapse: separate; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;div style=&quot;font-size: 16px; border-collapse: separate; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;table&gt;&lt;thead style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;tr style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot; class=&quot;firstRow&quot;&gt;&lt;th style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;维度&lt;/div&gt;&lt;/th&gt;&lt;th style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;现状（痛点）&lt;/div&gt;&lt;/th&gt;&lt;th style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;革命目标（解决方案）&lt;/div&gt;&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;tr style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;strong style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;流程&lt;/strong&gt;&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;依赖人工重复操作，易出错，无标准&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;strong style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;自动化流水线&lt;/strong&gt;：定义SOP，状态可追踪&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;strong style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;技术&lt;/strong&gt;&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;手工复制粘贴、简单脚本&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;strong style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;低代码/自适应工具&lt;/strong&gt;：RPA + AI解析 + 自愈机制&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;strong style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;数据&lt;/strong&gt;&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;原始、杂乱、质量不可控&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;strong style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;结构化资产&lt;/strong&gt;：自动校验、清洗、入仓&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;strong style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;组织&lt;/strong&gt;&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;业务人员等数据，IT/分析人员疲于奔命&lt;/div&gt;&lt;/td&gt;&lt;td style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 10.7143px 12.8571px 10.7143px 0px; border: 1px solid rgb(224, 224, 224);&quot;&gt;&lt;div class=&quot;ybc-p&quot; style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;&lt;strong style=&quot;font-size: 16px; border-collapse: collapse; border-spacing: 0px; padding: 0px;&quot;&gt;数据民主化&lt;/strong&gt;：业务人员自助获取，IT负责平台建设&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;/div&gt;&lt;h2&gt;二、 技术架构：构建“抗打击”的采集系统&lt;/h2&gt;&lt;div class=&quot;ybc-p&quot;&gt;一个能应对复杂网络环境的采集系统，需要具备以下核心能力：&lt;/div&gt;&lt;ol class=&quot;ybc-ol-component ybc-ol-component_1 list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;身份与反爬对抗&lt;/strong&gt;：动态Token管理、人机行为模拟、IP轮询。&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;解析韧性&lt;/strong&gt;：多模式解析（HTML/JSON/PDF），AI视觉辅助，动态适配网站改版。&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;自愈与监控&lt;/strong&gt;：自动重试机制、异常报警、数据质量校验。&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;pre class=&quot;ybc-pre-component ybc-pre-component_not-math&quot;&gt;#&amp;nbsp;革命性数据采集系统核心架构&amp;nbsp;(Core&amp;nbsp;Architecture)
import&amp;nbsp;requests
from&amp;nbsp;selenium&amp;nbsp;import&amp;nbsp;webdriver
from&amp;nbsp;bs4&amp;nbsp;import&amp;nbsp;BeautifulSoup
import&amp;nbsp;pandas&amp;nbsp;as&amp;nbsp;pd
import&amp;nbsp;time
import&amp;nbsp;random
import&amp;nbsp;logging
from&amp;nbsp;typing&amp;nbsp;import&amp;nbsp;Optional,&amp;nbsp;Dict,&amp;nbsp;List
#&amp;nbsp;封装好API供应商demo&amp;nbsp;url=https://console.open.onebound.cn/console/?i=Lex
class&amp;nbsp;AntiBotConfig:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;反爬策略配置&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;__init__(self):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.user_agents&amp;nbsp;=&amp;nbsp;[
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;Mozilla/5.0&amp;nbsp;(Windows&amp;nbsp;NT&amp;nbsp;10.0;&amp;nbsp;Win64;&amp;nbsp;x64)&amp;nbsp;AppleWebKit/537.36&amp;quot;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;Mozilla/5.0&amp;nbsp;(Macintosh;&amp;nbsp;Intel&amp;nbsp;Mac&amp;nbsp;OS&amp;nbsp;X&amp;nbsp;10_15_7)&amp;nbsp;AppleWebKit/605.1.15&amp;quot;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.delay_range&amp;nbsp;=&amp;nbsp;(1,&amp;nbsp;3)&amp;nbsp;&amp;nbsp;#&amp;nbsp;随机延迟秒数
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.retry_times&amp;nbsp;=&amp;nbsp;3

class&amp;nbsp;DataExtractor:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;多模态数据提取器（支持HTML,&amp;nbsp;JSON,&amp;nbsp;API）&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@staticmethod
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;extract_from_html(html:&amp;nbsp;str,&amp;nbsp;config:&amp;nbsp;Dict)&amp;nbsp;-&amp;gt;&amp;nbsp;List[Dict]:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;从HTML提取&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;soup&amp;nbsp;=&amp;nbsp;BeautifulSoup(html,&amp;nbsp;&amp;#39;html.parser&amp;#39;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;data&amp;nbsp;=&amp;nbsp;[]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;items&amp;nbsp;=&amp;nbsp;soup.select(config[&amp;#39;container_selector&amp;#39;])
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;item&amp;nbsp;in&amp;nbsp;items:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;row&amp;nbsp;=&amp;nbsp;{}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;field,&amp;nbsp;selector&amp;nbsp;in&amp;nbsp;config[&amp;#39;field_selectors&amp;#39;].items():
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;elem&amp;nbsp;=&amp;nbsp;item.select_one(selector)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;row[field]&amp;nbsp;=&amp;nbsp;elem.get_text(strip=True)&amp;nbsp;if&amp;nbsp;elem&amp;nbsp;else&amp;nbsp;None
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;data.append(row)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;data

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@staticmethod
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;extract_from_json(response_text:&amp;nbsp;str,&amp;nbsp;json_path:&amp;nbsp;List[str])&amp;nbsp;-&amp;gt;&amp;nbsp;List[Dict]:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;从JSON响应提取（支持API）&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;import&amp;nbsp;json
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;data&amp;nbsp;=&amp;nbsp;json.loads(response_text)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;支持多级路径解析，如&amp;nbsp;[&amp;#39;data&amp;#39;,&amp;nbsp;&amp;#39;list&amp;#39;]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;key&amp;nbsp;in&amp;nbsp;json_path:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;data&amp;nbsp;=&amp;nbsp;data.get(key,&amp;nbsp;[])
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;data&amp;nbsp;if&amp;nbsp;isinstance(data,&amp;nbsp;list)&amp;nbsp;else&amp;nbsp;[data]

class&amp;nbsp;IntelligentCrawler:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;智能爬虫核心类（带抗反爬与自愈）&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;__init__(self,&amp;nbsp;anti_bot_config:&amp;nbsp;AntiBotConfig):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.session&amp;nbsp;=&amp;nbsp;requests.Session()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.anti_bot&amp;nbsp;=&amp;nbsp;anti_bot_config
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.logger&amp;nbsp;=&amp;nbsp;logging.getLogger(__name__)

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;_human_like_delay(self):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;模拟人类操作延迟&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;time.sleep(random.uniform(*self.anti_bot.delay_range))

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;_rotate_user_agent(self):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;轮换User-Agent&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.session.headers.update({
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;User-Agent&amp;#39;:&amp;nbsp;random.choice(self.anti_bot.user_agents)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;})

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;fetch_with_retry(self,&amp;nbsp;url:&amp;nbsp;str,&amp;nbsp;method=&amp;#39;GET&amp;#39;,&amp;nbsp;**kwargs)&amp;nbsp;-&amp;gt;&amp;nbsp;Optional[requests.Response]:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;带重试机制的请求&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;attempt&amp;nbsp;in&amp;nbsp;range(self.anti_bot.retry_times):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self._rotate_user_agent()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;response&amp;nbsp;=&amp;nbsp;self.session.request(method,&amp;nbsp;url,&amp;nbsp;**kwargs)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;response.status_code&amp;nbsp;==&amp;nbsp;200:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;response
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;elif&amp;nbsp;response.status_code&amp;nbsp;==&amp;nbsp;429:&amp;nbsp;&amp;nbsp;#&amp;nbsp;被限流
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.logger.warning(f&amp;quot;Rate&amp;nbsp;limited,&amp;nbsp;retrying...&amp;nbsp;Attempt&amp;nbsp;{attempt+1}&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;time.sleep(5&amp;nbsp;*&amp;nbsp;(attempt&amp;nbsp;+&amp;nbsp;1))&amp;nbsp;&amp;nbsp;#&amp;nbsp;指数退避
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.logger.error(f&amp;quot;HTTP&amp;nbsp;{response.status_code}:&amp;nbsp;{url}&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;except&amp;nbsp;requests.RequestException&amp;nbsp;as&amp;nbsp;e:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.logger.error(f&amp;quot;Request&amp;nbsp;failed&amp;nbsp;(Attempt&amp;nbsp;{attempt+1}):&amp;nbsp;{e}&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self._human_like_delay()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;None

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;crawl(self,&amp;nbsp;url:&amp;nbsp;str,&amp;nbsp;extract_config:&amp;nbsp;Dict)&amp;nbsp;-&amp;gt;&amp;nbsp;pd.DataFrame:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;执行采集任务&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;response&amp;nbsp;=&amp;nbsp;self.fetch_with_retry(url)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;not&amp;nbsp;response:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;pd.DataFrame()

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;智能判断内容类型并解析
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;content_type&amp;nbsp;=&amp;nbsp;response.headers.get(&amp;#39;content-type&amp;#39;,&amp;nbsp;&amp;#39;&amp;#39;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;&amp;#39;json&amp;#39;&amp;nbsp;in&amp;nbsp;content_type:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;data&amp;nbsp;=&amp;nbsp;DataExtractor.extract_from_json(response.text,&amp;nbsp;extract_config.get(&amp;#39;json_path&amp;#39;,&amp;nbsp;[]))
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;data&amp;nbsp;=&amp;nbsp;DataExtractor.extract_from_html(response.text,&amp;nbsp;extract_config)

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;pd.DataFrame(data)

#&amp;nbsp;实战示例：采集电商产品数据
if&amp;nbsp;__name__&amp;nbsp;==&amp;nbsp;&amp;quot;__main__&amp;quot;:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;logging.basicConfig(level=logging.INFO)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;1.&amp;nbsp;初始化配置
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;config&amp;nbsp;=&amp;nbsp;AntiBotConfig()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;crawler&amp;nbsp;=&amp;nbsp;IntelligentCrawler(config)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;2.&amp;nbsp;定义采集规则（可配置化）
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;job_config&amp;nbsp;=&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;url&amp;#39;:&amp;nbsp;&amp;#39;https://httpbin.org/json&amp;#39;,&amp;nbsp;&amp;nbsp;#&amp;nbsp;示例API，实际替换为目标URL
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;json_path&amp;#39;:&amp;nbsp;[&amp;#39;slideshow&amp;#39;,&amp;nbsp;&amp;#39;slides&amp;#39;]&amp;nbsp;&amp;nbsp;#&amp;nbsp;指定JSON数据路径
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;3.&amp;nbsp;执行采集
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;df&amp;nbsp;=&amp;nbsp;crawler.crawl(job_config[&amp;#39;url&amp;#39;],&amp;nbsp;job_config)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;4.&amp;nbsp;输出结果
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;not&amp;nbsp;df.empty:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(&amp;quot;✅&amp;nbsp;采集成功！数据预览：&amp;quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(df.head())
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;自动保存（可扩展为直接入数据库）
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;df.to_csv(&amp;#39;crawled_data.csv&amp;#39;,&amp;nbsp;index=False,&amp;nbsp;encoding=&amp;#39;utf-8-sig&amp;#39;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(&amp;quot;❌&amp;nbsp;采集失败，请检查配置或网络。&amp;quot;)&lt;/pre&gt;&lt;h2&gt;三、 进阶武器：RPA + AI 视觉辅助&lt;/h2&gt;&lt;div class=&quot;ybc-p&quot;&gt;对于无法通过API或简单爬虫获取的数据（如复杂验证码、Canvas渲染、客户端软件），需要引入&lt;strong&gt;RPA (Robotic Process Automation)&lt;/strong&gt; 和计算机视觉。&lt;/div&gt;&lt;pre class=&quot;ybc-pre-component ybc-pre-component_not-math&quot;&gt;#&amp;nbsp;RPA&amp;nbsp;+&amp;nbsp;AI&amp;nbsp;视觉辅助采集示例（基于&amp;nbsp;pyautogui）
#&amp;nbsp;适用场景：内网系统、桌面软件、图形验证码
import&amp;nbsp;pyautogui
import&amp;nbsp;cv2
import&amp;nbsp;numpy&amp;nbsp;as&amp;nbsp;np
#&amp;nbsp;封装好API供应商demo&amp;nbsp;url=https://console.open.onebound.cn/console/?i=Lex
class&amp;nbsp;VisionAssistedRPA:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;视觉辅助RPA（用于抓取桌面软件或网页截图数据）&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;locate_and_click(self,&amp;nbsp;template_image_path:&amp;nbsp;str,&amp;nbsp;confidence=0.8):
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;在屏幕上查找图片并点击（模拟人工操作按钮）&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;screenshot&amp;nbsp;=&amp;nbsp;pyautogui.screenshot()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;screenshot_cv&amp;nbsp;=&amp;nbsp;cv2.cvtColor(np.array(screenshot),&amp;nbsp;cv2.COLOR_RGB2BGR)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;template&amp;nbsp;=&amp;nbsp;cv2.imread(template_image_path)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;模板匹配
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;result&amp;nbsp;=&amp;nbsp;cv2.matchTemplate(screenshot_cv,&amp;nbsp;template,&amp;nbsp;cv2.TM_CCOEFF_NORMED)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;min_val,&amp;nbsp;max_val,&amp;nbsp;min_loc,&amp;nbsp;max_loc&amp;nbsp;=&amp;nbsp;cv2.minMaxLoc(result)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;max_val&amp;nbsp;&amp;gt;=&amp;nbsp;confidence:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;计算中心点并点击
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;h,&amp;nbsp;w&amp;nbsp;=&amp;nbsp;template.shape[:2]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;center_x&amp;nbsp;=&amp;nbsp;max_loc[0]&amp;nbsp;+&amp;nbsp;w&amp;nbsp;//&amp;nbsp;2
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;center_y&amp;nbsp;=&amp;nbsp;max_loc[1]&amp;nbsp;+&amp;nbsp;h&amp;nbsp;//&amp;nbsp;2
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pyautogui.click(center_x,&amp;nbsp;center_y)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;True
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;False
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;extract_text_from_region(self,&amp;nbsp;region:&amp;nbsp;tuple)&amp;nbsp;-&amp;gt;&amp;nbsp;str:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;&amp;quot;&amp;quot;从屏幕指定区域OCR识别文本&amp;quot;&amp;quot;&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;截取区域&amp;nbsp;(left,&amp;nbsp;top,&amp;nbsp;width,&amp;nbsp;height)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;screenshot&amp;nbsp;=&amp;nbsp;pyautogui.screenshot(region=region)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;此处可接入Tesseract、百度OCR或Azure&amp;nbsp;OCR
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;text&amp;nbsp;=&amp;nbsp;pytesseract.image_to_string(screenshot)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;return&amp;nbsp;text.strip()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;&amp;quot;OCR&amp;nbsp;Text&amp;nbsp;Result&amp;quot;&amp;nbsp;&amp;nbsp;#&amp;nbsp;示例返回

#&amp;nbsp;使用流程：
#&amp;nbsp;1.&amp;nbsp;启动目标软件/网页
#&amp;nbsp;2.&amp;nbsp;rpa&amp;nbsp;=&amp;nbsp;VisionAssistedRPA()
#&amp;nbsp;3.&amp;nbsp;rpa.locate_and_click(&amp;#39;button_template.png&amp;#39;)&amp;nbsp;&amp;nbsp;#&amp;nbsp;点击“导出”按钮
#&amp;nbsp;4.&amp;nbsp;data&amp;nbsp;=&amp;nbsp;rpa.extract_text_from_region((100,&amp;nbsp;200,&amp;nbsp;300,&amp;nbsp;400))&amp;nbsp;#&amp;nbsp;抓取数据区域&lt;/pre&gt;&lt;h2&gt;四、 实施路线图：四步走策略&lt;/h2&gt;&lt;ol class=&quot;ybc-ol-component ybc-ol-component_1 list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;第一阶段（1-3个月）：标准化与自动化&lt;/strong&gt;&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;ul class=&quot;ybc-ul-component list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;目标&lt;/strong&gt;：将重复性最高、规则最固定的数据源自动化。&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;动作&lt;/strong&gt;：建立采集SOP，开发基础爬虫，实现&lt;strong&gt;无人值守&lt;/strong&gt;采集。&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;第二阶段（3-6个月）：平台化与监控&lt;/strong&gt;&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;ul class=&quot;ybc-ul-component list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;目标&lt;/strong&gt;：构建统一的数据采集平台，业务人员可自助配置任务。&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;动作&lt;/strong&gt;：开发Web管理界面，添加任务调度、失败告警（邮件/钉钉）。&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;第三阶段（6-12个月）：智能化与韧性&lt;/strong&gt;&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;ul class=&quot;ybc-ul-component list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;目标&lt;/strong&gt;：系统能自动适应网站改版，具备自我修复能力。&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;动作&lt;/strong&gt;：引入AI解析（如Diffbot、ScrapeGraphAI），建立规则库。&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;第四阶段（持续）：数据资产化&lt;/strong&gt;&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;ul class=&quot;ybc-ul-component list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;目标&lt;/strong&gt;：采集即入湖，直接服务于BI和AI模型。&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;动作&lt;/strong&gt;：对接数据仓库（如Snowflake、Doris），建立数据血缘。&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/ol&gt;&lt;h2&gt;五、 避坑指南：法律与风控&lt;/h2&gt;&lt;ul class=&quot;ybc-ul-component list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;合规性&lt;/strong&gt;：严格遵守 &lt;code class=&quot;hyc-common-markdown__code__inline&quot;&gt;robots.txt&lt;/code&gt;，避免对中小网站造成流量压力。商业数据抓取需评估《数据安全法》风险。&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;风控机制&lt;/strong&gt;：设置速率限制（Rate Limiting），避免被封IP。重要数据源建议购买官方API。&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span class=&quot;ybc-li-component__dot-wp&quot;&gt;&lt;/span&gt;&lt;span class=&quot;ybc-li-component_content&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;数据治理&lt;/strong&gt;：建立数据质量监控看板，对缺失率、异常值进行实时告警。&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class=&quot;ybc-p&quot;&gt;&lt;strong&gt;这场革命的核心&lt;/strong&gt;不是消灭人工，而是让人工去做机器做不到的事——&lt;strong&gt;思考业务逻辑、优化采集策略、解读数据价值&lt;/strong&gt;。把“抓取”交给机器，把“洞察”留给人。&lt;/div&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;</description><pubDate>Sat, 23 May 2026 11:17:07 +0800</pubDate></item></channel></rss>