akshare-proxy-patch 0.4.0__tar.gz → 0.4.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: akshare-proxy-patch
3
- Version: 0.4.0
3
+ Version: 0.4.2
4
4
  Summary: 针对 AkShare 和 efinance 的底层补丁,自动为东财等接口注入代理认证头,从而避免 `stock_zh_a_spot_em` 等方法报错。
5
5
  Home-page: https://github.com/helloyie/akshare-proxy-patch
6
6
  Author: cheapproxy.net
@@ -36,17 +36,18 @@ Dynamic: requires-python
36
36
  2. 安装 `akshare-proxy-patch` 插件
37
37
 
38
38
  ```
39
- pip install akshare-proxy-patch==0.4.0
39
+ pip install akshare-proxy-patch==0.4.1
40
40
  ```
41
41
 
42
42
  ## 🚀 使用方法(akshare / efinance / yfinance)
43
43
 
44
44
  1. [点击前往插件官网](https://ak.cheapproxy.net/dashboard/akshare) 获取 `TOKEN`。
45
45
 
46
- 2. `akshare` 或 `efinance` 用户:在 **Python 文件顶部**添加如下代码,并替换 `你的TOKEN`。调用非常简单,不需要使用 AI 魔改。
46
+ 2. `akshare` 或 `efinance` 用户:在 **Python 文件最顶部**添加如下代码,并替换 `你的TOKEN`。调用非常简单,不需要使用 AI 魔改。
47
47
 
48
48
  ```
49
49
  # python 文件顶部添加如下代码
50
+ # 一定要放到最顶部!不能在 akshare 或 efinance 之后引入!
50
51
  import akshare_proxy_patch
51
52
 
52
53
  akshare_proxy_patch.install_patch(
@@ -79,6 +80,7 @@ ef.stock.get_realtime_quotes()
79
80
 
80
81
  ```
81
82
  # python 文件顶部添加如下代码
83
+ # 一定要放到最顶部!不能在 akshare 或 efinance 之后引入!
82
84
  import akshare_proxy_patch
83
85
 
84
86
  akshare_proxy_patch.install_yfinance_patch(
@@ -109,6 +111,47 @@ data = yf.download("AAPL", start="2017-01-01", end="2017-04-30")
109
111
  - 可点击 `ak` 或 `ef` 函数查看接口源码对应的 `URL`,根据封控情况细化可以降低积分消耗。
110
112
  - 如只封控 `stock_zh_a_spot_em` 这个接口,`hook_domains` 可设置为 `["https://82.push2.eastmoney.com/api/qt/clist/get"]`。
111
113
 
114
+ ## 如何灵活禁用/启用插件?
115
+
116
+ 加入如下代码后插件就会被禁用:
117
+
118
+ ```
119
+ import importlib, requests;importlib.reload(requests)
120
+ ```
121
+
122
+ 下面是插件启用 --> 禁用 --> 再次启用的例子:
123
+
124
+ ```
125
+ ##### 1. 启用插件
126
+ import akshare_proxy_patch
127
+
128
+ akshare_proxy_patch.install_patch(
129
+ "101.201.173.125",
130
+ auth_token='你的TOKEN',
131
+ retry=30,
132
+ # 封控的域名列表,可自行调整
133
+ hook_domains=[
134
+ "fund.eastmoney.com",
135
+ "push2.eastmoney.com",
136
+ "push2his.eastmoney.com",
137
+ "emweb.securities.eastmoney.com",
138
+ ],
139
+ )
140
+ import akshare as ak
141
+ df = ak.fund_etf_hist_em()
142
+
143
+ ###### 2. 禁用插件
144
+ import importlib, requests;importlib.reload(requests)
145
+
146
+ # 禁用后测试
147
+ try:
148
+ df = ak.fund_etf_hist_em()
149
+ except Exception as e:
150
+ print('插件被禁用了,这里可能会报错')
151
+
152
+ ##### 3. 再次启用插件,重复上述 1、2 的代码即可
153
+ ```
154
+
112
155
  ## 🛠️ 如何在 aktools 内集成插件?
113
156
 
114
157
  `aktools` 想要集成插件,需要新建一个 `akt.py` 替换官方的 `python -m aktools` 启动命令,下面是 `akt.py` 内容:
@@ -150,10 +193,10 @@ if __name__ == '__main__':
150
193
  ## ❓ 我没使用 akshare 或 efinance,能集成插件吗?
151
194
 
152
195
  - 如果使用 Python 语言的 `requests` 库请求接口,插件能自动 hook 住请求,正常工作。
153
- - 如果您使用其他语言或 python 的其他库,可 [手动提取代理](http://101.201.173.125:47001/api/akshare-auth?token=&version=0.2.13) 自行实现封控解除。
196
+ - 如果您使用其他语言或 python 的其他库,可 [手动提取代理](http://101.201.173.125:47001/api/akshare-auth?token=XXX&version=0.4.1) 自行实现封控解除。
154
197
 
155
198
  ## 💬 使用问题交流群
156
199
 
157
200
  如使用时遇到问题,或对插件有什么意见或建议,可进群交流:
158
201
 
159
- ![YpRjixvpykLmzPtrX0kIkdPlvffOFJvF.webp](https://cdn.nodeimage.com/i/YpRjixvpykLmzPtrX0kIkdPlvffOFJvF.webp)
202
+ ![5TZKxn1xMXE84yE4Df8wmWC5a6BNy7gs.webp](https://cdn.nodeimage.com/i/5TZKxn1xMXE84yE4Df8wmWC5a6BNy7gs.webp)
@@ -15,17 +15,18 @@
15
15
  2. 安装 `akshare-proxy-patch` 插件
16
16
 
17
17
  ```
18
- pip install akshare-proxy-patch==0.4.0
18
+ pip install akshare-proxy-patch==0.4.1
19
19
  ```
20
20
 
21
21
  ## 🚀 使用方法(akshare / efinance / yfinance)
22
22
 
23
23
  1. [点击前往插件官网](https://ak.cheapproxy.net/dashboard/akshare) 获取 `TOKEN`。
24
24
 
25
- 2. `akshare` 或 `efinance` 用户:在 **Python 文件顶部**添加如下代码,并替换 `你的TOKEN`。调用非常简单,不需要使用 AI 魔改。
25
+ 2. `akshare` 或 `efinance` 用户:在 **Python 文件最顶部**添加如下代码,并替换 `你的TOKEN`。调用非常简单,不需要使用 AI 魔改。
26
26
 
27
27
  ```
28
28
  # python 文件顶部添加如下代码
29
+ # 一定要放到最顶部!不能在 akshare 或 efinance 之后引入!
29
30
  import akshare_proxy_patch
30
31
 
31
32
  akshare_proxy_patch.install_patch(
@@ -58,6 +59,7 @@ ef.stock.get_realtime_quotes()
58
59
 
59
60
  ```
60
61
  # python 文件顶部添加如下代码
62
+ # 一定要放到最顶部!不能在 akshare 或 efinance 之后引入!
61
63
  import akshare_proxy_patch
62
64
 
63
65
  akshare_proxy_patch.install_yfinance_patch(
@@ -88,6 +90,47 @@ data = yf.download("AAPL", start="2017-01-01", end="2017-04-30")
88
90
  - 可点击 `ak` 或 `ef` 函数查看接口源码对应的 `URL`,根据封控情况细化可以降低积分消耗。
89
91
  - 如只封控 `stock_zh_a_spot_em` 这个接口,`hook_domains` 可设置为 `["https://82.push2.eastmoney.com/api/qt/clist/get"]`。
90
92
 
93
+ ## 如何灵活禁用/启用插件?
94
+
95
+ 加入如下代码后插件就会被禁用:
96
+
97
+ ```
98
+ import importlib, requests;importlib.reload(requests)
99
+ ```
100
+
101
+ 下面是插件启用 --> 禁用 --> 再次启用的例子:
102
+
103
+ ```
104
+ ##### 1. 启用插件
105
+ import akshare_proxy_patch
106
+
107
+ akshare_proxy_patch.install_patch(
108
+ "101.201.173.125",
109
+ auth_token='你的TOKEN',
110
+ retry=30,
111
+ # 封控的域名列表,可自行调整
112
+ hook_domains=[
113
+ "fund.eastmoney.com",
114
+ "push2.eastmoney.com",
115
+ "push2his.eastmoney.com",
116
+ "emweb.securities.eastmoney.com",
117
+ ],
118
+ )
119
+ import akshare as ak
120
+ df = ak.fund_etf_hist_em()
121
+
122
+ ###### 2. 禁用插件
123
+ import importlib, requests;importlib.reload(requests)
124
+
125
+ # 禁用后测试
126
+ try:
127
+ df = ak.fund_etf_hist_em()
128
+ except Exception as e:
129
+ print('插件被禁用了,这里可能会报错')
130
+
131
+ ##### 3. 再次启用插件,重复上述 1、2 的代码即可
132
+ ```
133
+
91
134
  ## 🛠️ 如何在 aktools 内集成插件?
92
135
 
93
136
  `aktools` 想要集成插件,需要新建一个 `akt.py` 替换官方的 `python -m aktools` 启动命令,下面是 `akt.py` 内容:
@@ -129,10 +172,10 @@ if __name__ == '__main__':
129
172
  ## ❓ 我没使用 akshare 或 efinance,能集成插件吗?
130
173
 
131
174
  - 如果使用 Python 语言的 `requests` 库请求接口,插件能自动 hook 住请求,正常工作。
132
- - 如果您使用其他语言或 python 的其他库,可 [手动提取代理](http://101.201.173.125:47001/api/akshare-auth?token=&version=0.2.13) 自行实现封控解除。
175
+ - 如果您使用其他语言或 python 的其他库,可 [手动提取代理](http://101.201.173.125:47001/api/akshare-auth?token=XXX&version=0.4.1) 自行实现封控解除。
133
176
 
134
177
  ## 💬 使用问题交流群
135
178
 
136
179
  如使用时遇到问题,或对插件有什么意见或建议,可进群交流:
137
180
 
138
- ![YpRjixvpykLmzPtrX0kIkdPlvffOFJvF.webp](https://cdn.nodeimage.com/i/YpRjixvpykLmzPtrX0kIkdPlvffOFJvF.webp)
181
+ ![5TZKxn1xMXE84yE4Df8wmWC5a6BNy7gs.webp](https://cdn.nodeimage.com/i/5TZKxn1xMXE84yE4Df8wmWC5a6BNy7gs.webp)
@@ -13,7 +13,7 @@ except ImportError:
13
13
 
14
14
  import requests as std_requests
15
15
 
16
- __version__ = "0.4.0"
16
+ __version__ = "0.4.2"
17
17
 
18
18
  # 授权接口固定使用标准 requests,避免干扰
19
19
  _auth_session = std_requests.Session()
@@ -69,85 +69,73 @@ default_hook_domains = [
69
69
 
70
70
 
71
71
  def install_patch(
72
- auth_ip, auth_token="", retry=30, hook_domains=default_hook_domains, timeout=5
72
+ auth_ip,
73
+ auth_token="",
74
+ retry=30,
75
+ hook_domains=default_hook_domains,
76
+ timeout=5,
77
+ cookie="",
73
78
  ):
74
- # 获取原始的 curl_cffi Session 类
75
- # 1. 解决 Linux 下的 AttributeError: 'curl_cffi.requests' has no attribute 'adapters'
76
- # 动态将标准 requests 的子模块挂载到 curl_requests 上
77
- needed_submodules = [
78
- "adapters",
79
- "auth",
80
- "cookies",
81
- "exceptions",
82
- "models",
83
- "status_codes",
84
- "structures",
85
- "utils",
86
- "packages",
87
- ]
88
-
89
- setattr(curl_requests, "RequestException", RequestException)
90
- for sub in needed_submodules:
91
- if not hasattr(curl_requests, sub):
92
- # 优先从标准 requests 借用这些定义,保证 akshare 里的 isinstance 或常量检查能过
93
- setattr(curl_requests, sub, getattr(std_requests, sub, None))
94
-
95
- _BaseSession = curl_requests.Session
96
-
97
- # 定义兼容 Windows 调用的子类
98
- class PatchedSession(_BaseSession):
99
- def mount(self, prefix, adapter):
100
- pass
79
+ # --- 核心改进:备份原始 Session 避开递归死循环 ---
80
+ if not hasattr(std_requests, "_OriginalSession"):
81
+ std_requests._OriginalSession = std_requests.Session
82
+
83
+ _CFFIBaseSession = curl_requests.Session
101
84
 
85
+ # 这里的基类改为 std_requests.Session,确保对第三方库的 isinstance 检查通过
86
+ class PatchedSession(std_requests._OriginalSession):
102
87
  def request(self, method, url, **kwargs):
103
88
  is_target = any(d in (url or "") for d in hook_domains)
104
89
  clean_url = (url or "").split("?")[0].lower()
90
+
91
+ # --- 情况 1:非目标域名,使用原始 requests 逻辑 ---
105
92
  if (
106
93
  not is_target
107
94
  or clean_url.endswith(".js")
108
95
  or clean_url.endswith(".html")
109
96
  ):
110
- return super().request(method, url, **kwargs)
97
+ kwargs.pop("impersonate", None) # 移除 curl_cffi 特有参数
98
+ # 显式调用备份的原始 Session 方法,彻底避免递归
99
+ return std_requests._OriginalSession.request(
100
+ self, method, url, **kwargs
101
+ )
111
102
 
103
+ # --- 情况 2:目标域名,逻辑保持不变 (走 curl_cffi) ---
112
104
  auth_url = f"http://{auth_ip}:47001/api/akshare-auth"
113
105
 
106
+ # 这里的逻辑和之前完全一致
114
107
  for i in range(retry):
115
108
  auth_res = get_auth_config_with_cache(auth_url, auth_token)
116
109
  if not auth_res:
117
110
  time.sleep(0.05)
118
111
  continue
119
112
 
120
- # 适配参数
121
113
  headers = kwargs.get("headers") or {}
122
- headers["User-Agent"] = auth_res["ua"]
114
+ headers["Cookie"] = cookie or auth_res.get("cookie", "")
123
115
  kwargs["headers"] = headers
124
116
  kwargs["proxies"] = {
125
117
  "http": auth_res["proxy"],
126
118
  "https": auth_res["proxy"],
127
119
  }
128
120
  kwargs["timeout"] = timeout
129
-
130
121
  kwargs["impersonate"] = random.choice(target_browsers)
131
- # print(auth_res["proxy"], i, "=============")
132
122
 
133
123
  try:
134
- # 关键:调用 curl_cffi 的原生 C 实现
135
- resp = super().request(method, url, **kwargs)
136
- if resp.status_code == 200:
137
- # 业务逻辑验证...
138
- return resp
139
- with _cache.lock:
140
- _cache.expire_at = 0
124
+ # 对于目标域名,利用 curl_cffi 的 Session 来发起请求
125
+ with _CFFIBaseSession() as cffi_s:
126
+ resp = cffi_s.request(method, url, **kwargs)
127
+ if resp.status_code == 200:
128
+ return resp
129
+ with _cache.lock:
130
+ _cache.expire_at = 0
141
131
  except:
142
132
  with _cache.lock:
143
133
  _cache.expire_at = 0
144
134
  time.sleep(0.05)
145
135
 
146
- return super().request(method, url, **kwargs)
136
+ return std_requests._OriginalSession.request(self, method, url, **kwargs)
147
137
 
148
- # --- 核心改造:针对 Windows 的原地注入 ---
149
-
150
- # 定义顶层包装函数
138
+ # 定义补丁包装函数
151
139
  def patched_get(url, params=None, **kwargs):
152
140
  with PatchedSession() as s:
153
141
  return s.get(url, params=params, **kwargs)
@@ -156,23 +144,22 @@ def install_patch(
156
144
  with PatchedSession() as s:
157
145
  return s.post(url, data=data, json=json, **kwargs)
158
146
 
159
- # 1. 替换 curl_requests 的成员
147
+ def patched_request(method, url, **kwargs):
148
+ with PatchedSession() as s:
149
+ return s.request(method, url, **kwargs)
150
+
151
+ # --- 最小化原地注入 ---
152
+ # 仅修改标准 requests 模块的成员引用,不替换 sys.modules["requests"]
153
+ std_requests.Session = PatchedSession
154
+ std_requests.get = patched_get
155
+ std_requests.post = patched_post
156
+ std_requests.request = patched_request
157
+
158
+ # 同步修改 curl_requests 以保持库内部一致性
160
159
  curl_requests.Session = PatchedSession
161
160
  curl_requests.get = patched_get
162
161
  curl_requests.post = patched_post
163
162
 
164
- # 2. 【核心】原地修改 sys.modules 中的 requests 对象
165
- # 即使 akshare 已经加载了 requests,我们直接修改 requests 模块的内容
166
- if "requests" in sys.modules:
167
- req_mod = sys.modules["requests"]
168
- req_mod.Session = PatchedSession
169
- req_mod.get = patched_get
170
- req_mod.post = patched_post
171
- req_mod.request = patched_get # 部分库直接调 request
172
-
173
- # 3. 确保后续导入重定向
174
- sys.modules["requests"] = curl_requests
175
-
176
163
 
177
164
  def install_yfinance_patch(
178
165
  auth_ip, auth_token="", retry=30, hook_domains=["finance.yahoo.com"]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: akshare-proxy-patch
3
- Version: 0.4.0
3
+ Version: 0.4.2
4
4
  Summary: 针对 AkShare 和 efinance 的底层补丁,自动为东财等接口注入代理认证头,从而避免 `stock_zh_a_spot_em` 等方法报错。
5
5
  Home-page: https://github.com/helloyie/akshare-proxy-patch
6
6
  Author: cheapproxy.net
@@ -36,17 +36,18 @@ Dynamic: requires-python
36
36
  2. 安装 `akshare-proxy-patch` 插件
37
37
 
38
38
  ```
39
- pip install akshare-proxy-patch==0.4.0
39
+ pip install akshare-proxy-patch==0.4.1
40
40
  ```
41
41
 
42
42
  ## 🚀 使用方法(akshare / efinance / yfinance)
43
43
 
44
44
  1. [点击前往插件官网](https://ak.cheapproxy.net/dashboard/akshare) 获取 `TOKEN`。
45
45
 
46
- 2. `akshare` 或 `efinance` 用户:在 **Python 文件顶部**添加如下代码,并替换 `你的TOKEN`。调用非常简单,不需要使用 AI 魔改。
46
+ 2. `akshare` 或 `efinance` 用户:在 **Python 文件最顶部**添加如下代码,并替换 `你的TOKEN`。调用非常简单,不需要使用 AI 魔改。
47
47
 
48
48
  ```
49
49
  # python 文件顶部添加如下代码
50
+ # 一定要放到最顶部!不能在 akshare 或 efinance 之后引入!
50
51
  import akshare_proxy_patch
51
52
 
52
53
  akshare_proxy_patch.install_patch(
@@ -79,6 +80,7 @@ ef.stock.get_realtime_quotes()
79
80
 
80
81
  ```
81
82
  # python 文件顶部添加如下代码
83
+ # 一定要放到最顶部!不能在 akshare 或 efinance 之后引入!
82
84
  import akshare_proxy_patch
83
85
 
84
86
  akshare_proxy_patch.install_yfinance_patch(
@@ -109,6 +111,47 @@ data = yf.download("AAPL", start="2017-01-01", end="2017-04-30")
109
111
  - 可点击 `ak` 或 `ef` 函数查看接口源码对应的 `URL`,根据封控情况细化可以降低积分消耗。
110
112
  - 如只封控 `stock_zh_a_spot_em` 这个接口,`hook_domains` 可设置为 `["https://82.push2.eastmoney.com/api/qt/clist/get"]`。
111
113
 
114
+ ## 如何灵活禁用/启用插件?
115
+
116
+ 加入如下代码后插件就会被禁用:
117
+
118
+ ```
119
+ import importlib, requests;importlib.reload(requests)
120
+ ```
121
+
122
+ 下面是插件启用 --> 禁用 --> 再次启用的例子:
123
+
124
+ ```
125
+ ##### 1. 启用插件
126
+ import akshare_proxy_patch
127
+
128
+ akshare_proxy_patch.install_patch(
129
+ "101.201.173.125",
130
+ auth_token='你的TOKEN',
131
+ retry=30,
132
+ # 封控的域名列表,可自行调整
133
+ hook_domains=[
134
+ "fund.eastmoney.com",
135
+ "push2.eastmoney.com",
136
+ "push2his.eastmoney.com",
137
+ "emweb.securities.eastmoney.com",
138
+ ],
139
+ )
140
+ import akshare as ak
141
+ df = ak.fund_etf_hist_em()
142
+
143
+ ###### 2. 禁用插件
144
+ import importlib, requests;importlib.reload(requests)
145
+
146
+ # 禁用后测试
147
+ try:
148
+ df = ak.fund_etf_hist_em()
149
+ except Exception as e:
150
+ print('插件被禁用了,这里可能会报错')
151
+
152
+ ##### 3. 再次启用插件,重复上述 1、2 的代码即可
153
+ ```
154
+
112
155
  ## 🛠️ 如何在 aktools 内集成插件?
113
156
 
114
157
  `aktools` 想要集成插件,需要新建一个 `akt.py` 替换官方的 `python -m aktools` 启动命令,下面是 `akt.py` 内容:
@@ -150,10 +193,10 @@ if __name__ == '__main__':
150
193
  ## ❓ 我没使用 akshare 或 efinance,能集成插件吗?
151
194
 
152
195
  - 如果使用 Python 语言的 `requests` 库请求接口,插件能自动 hook 住请求,正常工作。
153
- - 如果您使用其他语言或 python 的其他库,可 [手动提取代理](http://101.201.173.125:47001/api/akshare-auth?token=&version=0.2.13) 自行实现封控解除。
196
+ - 如果您使用其他语言或 python 的其他库,可 [手动提取代理](http://101.201.173.125:47001/api/akshare-auth?token=XXX&version=0.4.1) 自行实现封控解除。
154
197
 
155
198
  ## 💬 使用问题交流群
156
199
 
157
200
  如使用时遇到问题,或对插件有什么意见或建议,可进群交流:
158
201
 
159
- ![YpRjixvpykLmzPtrX0kIkdPlvffOFJvF.webp](https://cdn.nodeimage.com/i/YpRjixvpykLmzPtrX0kIkdPlvffOFJvF.webp)
202
+ ![5TZKxn1xMXE84yE4Df8wmWC5a6BNy7gs.webp](https://cdn.nodeimage.com/i/5TZKxn1xMXE84yE4Df8wmWC5a6BNy7gs.webp)
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "akshare-proxy-patch" # 包名,需在 PyPI 唯一
7
- version = "0.4.0"
7
+ version = "0.4.2"
8
8
  authors = [
9
9
  { name="cheapproxy", email="emezxyj1@gmail.com" },
10
10
  ]
@@ -5,7 +5,7 @@ with open("README.md", "r", encoding="utf-8") as fh:
5
5
 
6
6
  setup(
7
7
  name="akshare-proxy-patch", # 包名,用户 pip install 时的名称
8
- version="0.4.0",
8
+ version="0.4.2",
9
9
  author="cheapproxy.net",
10
10
  author_email="emezxyj1@gmail.com",
11
11
  description="AkShare 和 efinance 报错全局Hook",