akshare-proxy-patch 0.3.0__tar.gz → 0.4.1__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.
Potentially problematic release.
This version of akshare-proxy-patch might be problematic. Click here for more details.
- {akshare_proxy_patch-0.3.0 → akshare_proxy_patch-0.4.1}/PKG-INFO +10 -10
- {akshare_proxy_patch-0.3.0 → akshare_proxy_patch-0.4.1}/README.md +9 -9
- akshare_proxy_patch-0.4.1/akshare_proxy_patch/__init__.py +164 -0
- {akshare_proxy_patch-0.3.0 → akshare_proxy_patch-0.4.1}/akshare_proxy_patch/yfinance.py +11 -0
- {akshare_proxy_patch-0.3.0 → akshare_proxy_patch-0.4.1}/akshare_proxy_patch.egg-info/PKG-INFO +10 -10
- {akshare_proxy_patch-0.3.0 → akshare_proxy_patch-0.4.1}/pyproject.toml +1 -1
- {akshare_proxy_patch-0.3.0 → akshare_proxy_patch-0.4.1}/setup.py +1 -1
- akshare_proxy_patch-0.3.0/akshare_proxy_patch/__init__.py +0 -125
- {akshare_proxy_patch-0.3.0 → akshare_proxy_patch-0.4.1}/LICENSE +0 -0
- {akshare_proxy_patch-0.3.0 → akshare_proxy_patch-0.4.1}/akshare_proxy_patch.egg-info/SOURCES.txt +0 -0
- {akshare_proxy_patch-0.3.0 → akshare_proxy_patch-0.4.1}/akshare_proxy_patch.egg-info/dependency_links.txt +0 -0
- {akshare_proxy_patch-0.3.0 → akshare_proxy_patch-0.4.1}/akshare_proxy_patch.egg-info/requires.txt +0 -0
- {akshare_proxy_patch-0.3.0 → akshare_proxy_patch-0.4.1}/akshare_proxy_patch.egg-info/top_level.txt +0 -0
- {akshare_proxy_patch-0.3.0 → akshare_proxy_patch-0.4.1}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: akshare-proxy-patch
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.1
|
|
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
|
|
@@ -21,13 +21,13 @@ Dynamic: requires-python
|
|
|
21
21
|
|
|
22
22
|
# AkShare Proxy Patch
|
|
23
23
|
|
|
24
|
-
> 针对 [
|
|
24
|
+
> 针对 [akshare](https://github.com/akfamily/akshare)、[efinance](https://github.com/Micro-sheep/efinance)、[yfinance](https://github.com/ranaroussi/yfinance) 的🐒插件补丁,解决 `stock_zh_a_spot_em`、`stock_zh_a_hist`、`get_realtime_quotes` 等接口报错问题和 Yahoo `YFRateLimitError` 问题。
|
|
25
25
|
|
|
26
26
|
## ✨ 特性
|
|
27
27
|
|
|
28
|
-
- `
|
|
29
|
-
- `efinance`
|
|
30
|
-
- `yfinance` Yahoo接口报错问题
|
|
28
|
+
- 解决 `akshare` 接口报错问题
|
|
29
|
+
- 解决 `efinance` 接口报错问题
|
|
30
|
+
- 解决 `yfinance` Yahoo接口报错问题
|
|
31
31
|
|
|
32
32
|
## 📦 安装
|
|
33
33
|
|
|
@@ -36,14 +36,14 @@ Dynamic: requires-python
|
|
|
36
36
|
2. 安装 `akshare-proxy-patch` 插件
|
|
37
37
|
|
|
38
38
|
```
|
|
39
|
-
pip install akshare-proxy-patch==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`
|
|
46
|
+
2. `akshare` 或 `efinance` 用户:在 **Python 文件顶部**添加如下代码,并替换 `你的TOKEN`。调用非常简单,不需要使用 AI 魔改。
|
|
47
47
|
|
|
48
48
|
```
|
|
49
49
|
# python 文件顶部添加如下代码
|
|
@@ -75,7 +75,7 @@ import efinance as ef
|
|
|
75
75
|
ef.stock.get_realtime_quotes()
|
|
76
76
|
```
|
|
77
77
|
|
|
78
|
-
3. `yfinance`
|
|
78
|
+
3. `yfinance` 用户:在 Python 文件顶部添加如下代码,并替换 `你的TOKEN`。调用非常简单,不需要使用 AI 魔改。
|
|
79
79
|
|
|
80
80
|
```
|
|
81
81
|
# python 文件顶部添加如下代码
|
|
@@ -149,11 +149,11 @@ if __name__ == '__main__':
|
|
|
149
149
|
|
|
150
150
|
## ❓ 我没使用 akshare 或 efinance,能集成插件吗?
|
|
151
151
|
|
|
152
|
-
- 如果使用 Python 语言的 `requests`
|
|
152
|
+
- 如果使用 Python 语言的 `requests` 库请求接口,插件能自动 hook 住请求,正常工作。
|
|
153
153
|
- 如果您使用其他语言或 python 的其他库,可 [手动提取代理](http://101.201.173.125:47001/api/akshare-auth?token=&version=0.2.13) 自行实现封控解除。
|
|
154
154
|
|
|
155
155
|
## 💬 使用问题交流群
|
|
156
156
|
|
|
157
157
|
如使用时遇到问题,或对插件有什么意见或建议,可进群交流:
|
|
158
158
|
|
|
159
|
-

|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# AkShare Proxy Patch
|
|
2
2
|
|
|
3
|
-
> 针对 [
|
|
3
|
+
> 针对 [akshare](https://github.com/akfamily/akshare)、[efinance](https://github.com/Micro-sheep/efinance)、[yfinance](https://github.com/ranaroussi/yfinance) 的🐒插件补丁,解决 `stock_zh_a_spot_em`、`stock_zh_a_hist`、`get_realtime_quotes` 等接口报错问题和 Yahoo `YFRateLimitError` 问题。
|
|
4
4
|
|
|
5
5
|
## ✨ 特性
|
|
6
6
|
|
|
7
|
-
- `
|
|
8
|
-
- `efinance`
|
|
9
|
-
- `yfinance` Yahoo接口报错问题
|
|
7
|
+
- 解决 `akshare` 接口报错问题
|
|
8
|
+
- 解决 `efinance` 接口报错问题
|
|
9
|
+
- 解决 `yfinance` Yahoo接口报错问题
|
|
10
10
|
|
|
11
11
|
## 📦 安装
|
|
12
12
|
|
|
@@ -15,14 +15,14 @@
|
|
|
15
15
|
2. 安装 `akshare-proxy-patch` 插件
|
|
16
16
|
|
|
17
17
|
```
|
|
18
|
-
pip install akshare-proxy-patch==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`
|
|
25
|
+
2. `akshare` 或 `efinance` 用户:在 **Python 文件顶部**添加如下代码,并替换 `你的TOKEN`。调用非常简单,不需要使用 AI 魔改。
|
|
26
26
|
|
|
27
27
|
```
|
|
28
28
|
# python 文件顶部添加如下代码
|
|
@@ -54,7 +54,7 @@ import efinance as ef
|
|
|
54
54
|
ef.stock.get_realtime_quotes()
|
|
55
55
|
```
|
|
56
56
|
|
|
57
|
-
3. `yfinance`
|
|
57
|
+
3. `yfinance` 用户:在 Python 文件顶部添加如下代码,并替换 `你的TOKEN`。调用非常简单,不需要使用 AI 魔改。
|
|
58
58
|
|
|
59
59
|
```
|
|
60
60
|
# python 文件顶部添加如下代码
|
|
@@ -128,11 +128,11 @@ if __name__ == '__main__':
|
|
|
128
128
|
|
|
129
129
|
## ❓ 我没使用 akshare 或 efinance,能集成插件吗?
|
|
130
130
|
|
|
131
|
-
- 如果使用 Python 语言的 `requests`
|
|
131
|
+
- 如果使用 Python 语言的 `requests` 库请求接口,插件能自动 hook 住请求,正常工作。
|
|
132
132
|
- 如果您使用其他语言或 python 的其他库,可 [手动提取代理](http://101.201.173.125:47001/api/akshare-auth?token=&version=0.2.13) 自行实现封控解除。
|
|
133
133
|
|
|
134
134
|
## 💬 使用问题交流群
|
|
135
135
|
|
|
136
136
|
如使用时遇到问题,或对插件有什么意见或建议,可进群交流:
|
|
137
137
|
|
|
138
|
-

|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import time
|
|
2
|
+
import random
|
|
3
|
+
import threading
|
|
4
|
+
import sys
|
|
5
|
+
|
|
6
|
+
# 1. 导入必要的库
|
|
7
|
+
try:
|
|
8
|
+
from curl_cffi import requests as curl_requests
|
|
9
|
+
from curl_cffi.requests import BrowserType
|
|
10
|
+
from curl_cffi.requests.errors import RequestsError as RequestException
|
|
11
|
+
except ImportError:
|
|
12
|
+
raise ImportError("请执行 pip install curl_cffi 来安装依赖")
|
|
13
|
+
|
|
14
|
+
import requests as std_requests
|
|
15
|
+
|
|
16
|
+
__version__ = "0.4.1"
|
|
17
|
+
|
|
18
|
+
# 授权接口固定使用标准 requests,避免干扰
|
|
19
|
+
_auth_session = std_requests.Session()
|
|
20
|
+
|
|
21
|
+
target_browsers = [
|
|
22
|
+
b
|
|
23
|
+
for b in BrowserType.__dict__.values()
|
|
24
|
+
if isinstance(b, str) and (b.startswith("chrome") or b.startswith("edge"))
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class AuthCache:
|
|
29
|
+
def __init__(self):
|
|
30
|
+
self.data = None
|
|
31
|
+
self.expire_at = 0
|
|
32
|
+
self.lock = threading.Lock()
|
|
33
|
+
self.ttl = 28
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
_cache = AuthCache()
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def get_auth_config_with_cache(auth_url, auth_token):
|
|
40
|
+
now = time.time()
|
|
41
|
+
if _cache.data and now < _cache.expire_at:
|
|
42
|
+
return _cache.data
|
|
43
|
+
with _cache.lock:
|
|
44
|
+
if _cache.data and now < _cache.expire_at:
|
|
45
|
+
return _cache.data
|
|
46
|
+
try:
|
|
47
|
+
resp = _auth_session.get(
|
|
48
|
+
auth_url,
|
|
49
|
+
params={"token": auth_token, "version": __version__},
|
|
50
|
+
timeout=(1.5, 3),
|
|
51
|
+
)
|
|
52
|
+
data = resp.json()
|
|
53
|
+
if data.get("ua"):
|
|
54
|
+
_cache.data = data
|
|
55
|
+
_cache.expire_at = now + _cache.ttl
|
|
56
|
+
return data
|
|
57
|
+
print(f"授权失败: {data.get('error_msg')}")
|
|
58
|
+
except:
|
|
59
|
+
pass
|
|
60
|
+
return _cache.data
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
default_hook_domains = [
|
|
64
|
+
"fund.eastmoney.com",
|
|
65
|
+
"push2.eastmoney.com",
|
|
66
|
+
"push2his.eastmoney.com",
|
|
67
|
+
"emweb.securities.eastmoney.com",
|
|
68
|
+
]
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def install_patch(
|
|
72
|
+
auth_ip, auth_token="", retry=30, hook_domains=default_hook_domains, timeout=5
|
|
73
|
+
):
|
|
74
|
+
# --- 核心改进:备份原始 Session 避开递归死循环 ---
|
|
75
|
+
if not hasattr(std_requests, "_OriginalSession"):
|
|
76
|
+
std_requests._OriginalSession = std_requests.Session
|
|
77
|
+
|
|
78
|
+
_CFFIBaseSession = curl_requests.Session
|
|
79
|
+
|
|
80
|
+
# 这里的基类改为 std_requests.Session,确保对第三方库的 isinstance 检查通过
|
|
81
|
+
class PatchedSession(std_requests._OriginalSession):
|
|
82
|
+
def request(self, method, url, **kwargs):
|
|
83
|
+
is_target = any(d in (url or "") for d in hook_domains)
|
|
84
|
+
clean_url = (url or "").split("?")[0].lower()
|
|
85
|
+
|
|
86
|
+
# --- 情况 1:非目标域名,使用原始 requests 逻辑 ---
|
|
87
|
+
if (
|
|
88
|
+
not is_target
|
|
89
|
+
or clean_url.endswith(".js")
|
|
90
|
+
or clean_url.endswith(".html")
|
|
91
|
+
):
|
|
92
|
+
kwargs.pop("impersonate", None) # 移除 curl_cffi 特有参数
|
|
93
|
+
# 显式调用备份的原始 Session 方法,彻底避免递归
|
|
94
|
+
return std_requests._OriginalSession.request(
|
|
95
|
+
self, method, url, **kwargs
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
# --- 情况 2:目标域名,逻辑保持不变 (走 curl_cffi) ---
|
|
99
|
+
auth_url = f"http://{auth_ip}:47001/api/akshare-auth"
|
|
100
|
+
|
|
101
|
+
# 这里的逻辑和之前完全一致
|
|
102
|
+
for i in range(retry):
|
|
103
|
+
auth_res = get_auth_config_with_cache(auth_url, auth_token)
|
|
104
|
+
if not auth_res:
|
|
105
|
+
time.sleep(0.05)
|
|
106
|
+
continue
|
|
107
|
+
|
|
108
|
+
headers = kwargs.get("headers") or {}
|
|
109
|
+
headers["User-Agent"] = auth_res["ua"]
|
|
110
|
+
kwargs["headers"] = headers
|
|
111
|
+
kwargs["proxies"] = {
|
|
112
|
+
"http": auth_res["proxy"],
|
|
113
|
+
"https": auth_res["proxy"],
|
|
114
|
+
}
|
|
115
|
+
kwargs["timeout"] = timeout
|
|
116
|
+
kwargs["impersonate"] = random.choice(target_browsers)
|
|
117
|
+
|
|
118
|
+
try:
|
|
119
|
+
# 对于目标域名,利用 curl_cffi 的 Session 来发起请求
|
|
120
|
+
with _CFFIBaseSession() as cffi_s:
|
|
121
|
+
resp = cffi_s.request(method, url, **kwargs)
|
|
122
|
+
if resp.status_code == 200:
|
|
123
|
+
return resp
|
|
124
|
+
with _cache.lock:
|
|
125
|
+
_cache.expire_at = 0
|
|
126
|
+
except:
|
|
127
|
+
with _cache.lock:
|
|
128
|
+
_cache.expire_at = 0
|
|
129
|
+
time.sleep(0.05)
|
|
130
|
+
|
|
131
|
+
return std_requests._OriginalSession.request(self, method, url, **kwargs)
|
|
132
|
+
|
|
133
|
+
# 定义补丁包装函数
|
|
134
|
+
def patched_get(url, params=None, **kwargs):
|
|
135
|
+
with PatchedSession() as s:
|
|
136
|
+
return s.get(url, params=params, **kwargs)
|
|
137
|
+
|
|
138
|
+
def patched_post(url, data=None, json=None, **kwargs):
|
|
139
|
+
with PatchedSession() as s:
|
|
140
|
+
return s.post(url, data=data, json=json, **kwargs)
|
|
141
|
+
|
|
142
|
+
def patched_request(method, url, **kwargs):
|
|
143
|
+
with PatchedSession() as s:
|
|
144
|
+
return s.request(method, url, **kwargs)
|
|
145
|
+
|
|
146
|
+
# --- 最小化原地注入 ---
|
|
147
|
+
# 仅修改标准 requests 模块的成员引用,不替换 sys.modules["requests"]
|
|
148
|
+
std_requests.Session = PatchedSession
|
|
149
|
+
std_requests.get = patched_get
|
|
150
|
+
std_requests.post = patched_post
|
|
151
|
+
std_requests.request = patched_request
|
|
152
|
+
|
|
153
|
+
# 同步修改 curl_requests 以保持库内部一致性
|
|
154
|
+
curl_requests.Session = PatchedSession
|
|
155
|
+
curl_requests.get = patched_get
|
|
156
|
+
curl_requests.post = patched_post
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def install_yfinance_patch(
|
|
160
|
+
auth_ip, auth_token="", retry=30, hook_domains=["finance.yahoo.com"]
|
|
161
|
+
):
|
|
162
|
+
from .yfinance import install_yfinance_patch_main
|
|
163
|
+
|
|
164
|
+
install_yfinance_patch_main(auth_ip, auth_token, retry, hook_domains)
|
|
@@ -93,3 +93,14 @@ def install_yfinance_patch_main(auth_ip, auth_token="", retry=30, hook_domains=[
|
|
|
93
93
|
return _original_request(self, method, url, **kwargs)
|
|
94
94
|
|
|
95
95
|
requests.Session.request = patched_request
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def uninstall_yfinance_patch_main():
|
|
99
|
+
"""
|
|
100
|
+
恢复 requests.Session.request 到原始状态
|
|
101
|
+
"""
|
|
102
|
+
if hasattr(requests.Session, "request"):
|
|
103
|
+
requests.Session.request = _original_request
|
|
104
|
+
print("yfinance_patch 已成功卸载")
|
|
105
|
+
else:
|
|
106
|
+
print("未发现 yfinance_patch 或已处于原始状态。")
|
{akshare_proxy_patch-0.3.0 → akshare_proxy_patch-0.4.1}/akshare_proxy_patch.egg-info/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: akshare-proxy-patch
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.1
|
|
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
|
|
@@ -21,13 +21,13 @@ Dynamic: requires-python
|
|
|
21
21
|
|
|
22
22
|
# AkShare Proxy Patch
|
|
23
23
|
|
|
24
|
-
> 针对 [
|
|
24
|
+
> 针对 [akshare](https://github.com/akfamily/akshare)、[efinance](https://github.com/Micro-sheep/efinance)、[yfinance](https://github.com/ranaroussi/yfinance) 的🐒插件补丁,解决 `stock_zh_a_spot_em`、`stock_zh_a_hist`、`get_realtime_quotes` 等接口报错问题和 Yahoo `YFRateLimitError` 问题。
|
|
25
25
|
|
|
26
26
|
## ✨ 特性
|
|
27
27
|
|
|
28
|
-
- `
|
|
29
|
-
- `efinance`
|
|
30
|
-
- `yfinance` Yahoo接口报错问题
|
|
28
|
+
- 解决 `akshare` 接口报错问题
|
|
29
|
+
- 解决 `efinance` 接口报错问题
|
|
30
|
+
- 解决 `yfinance` Yahoo接口报错问题
|
|
31
31
|
|
|
32
32
|
## 📦 安装
|
|
33
33
|
|
|
@@ -36,14 +36,14 @@ Dynamic: requires-python
|
|
|
36
36
|
2. 安装 `akshare-proxy-patch` 插件
|
|
37
37
|
|
|
38
38
|
```
|
|
39
|
-
pip install akshare-proxy-patch==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`
|
|
46
|
+
2. `akshare` 或 `efinance` 用户:在 **Python 文件顶部**添加如下代码,并替换 `你的TOKEN`。调用非常简单,不需要使用 AI 魔改。
|
|
47
47
|
|
|
48
48
|
```
|
|
49
49
|
# python 文件顶部添加如下代码
|
|
@@ -75,7 +75,7 @@ import efinance as ef
|
|
|
75
75
|
ef.stock.get_realtime_quotes()
|
|
76
76
|
```
|
|
77
77
|
|
|
78
|
-
3. `yfinance`
|
|
78
|
+
3. `yfinance` 用户:在 Python 文件顶部添加如下代码,并替换 `你的TOKEN`。调用非常简单,不需要使用 AI 魔改。
|
|
79
79
|
|
|
80
80
|
```
|
|
81
81
|
# python 文件顶部添加如下代码
|
|
@@ -149,11 +149,11 @@ if __name__ == '__main__':
|
|
|
149
149
|
|
|
150
150
|
## ❓ 我没使用 akshare 或 efinance,能集成插件吗?
|
|
151
151
|
|
|
152
|
-
- 如果使用 Python 语言的 `requests`
|
|
152
|
+
- 如果使用 Python 语言的 `requests` 库请求接口,插件能自动 hook 住请求,正常工作。
|
|
153
153
|
- 如果您使用其他语言或 python 的其他库,可 [手动提取代理](http://101.201.173.125:47001/api/akshare-auth?token=&version=0.2.13) 自行实现封控解除。
|
|
154
154
|
|
|
155
155
|
## 💬 使用问题交流群
|
|
156
156
|
|
|
157
157
|
如使用时遇到问题,或对插件有什么意见或建议,可进群交流:
|
|
158
158
|
|
|
159
|
-

|
|
@@ -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.
|
|
8
|
+
version="0.4.1",
|
|
9
9
|
author="cheapproxy.net",
|
|
10
10
|
author_email="emezxyj1@gmail.com",
|
|
11
11
|
description="AkShare 和 efinance 报错全局Hook",
|
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
import time
|
|
2
|
-
import threading
|
|
3
|
-
import requests
|
|
4
|
-
from urllib.parse import urlparse
|
|
5
|
-
from .yfinance import install_yfinance_patch_main
|
|
6
|
-
|
|
7
|
-
__version__ = "0.3.0"
|
|
8
|
-
# 备份 Session 的原始 request 方法
|
|
9
|
-
_original_request = requests.Session.request
|
|
10
|
-
_auth_session = requests.Session()
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
class AuthCache:
|
|
14
|
-
def __init__(self):
|
|
15
|
-
self.data = None
|
|
16
|
-
self.expire_at = 0
|
|
17
|
-
self.lock = threading.Lock()
|
|
18
|
-
self.ttl = 28
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
_cache = AuthCache()
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
def get_auth_config_with_cache(auth_url, auth_token):
|
|
25
|
-
now = time.time()
|
|
26
|
-
# 1. 检查缓存是否有效
|
|
27
|
-
if _cache.data and now < _cache.expire_at:
|
|
28
|
-
return _cache.data
|
|
29
|
-
|
|
30
|
-
# 2. 缓存失效,加锁更新
|
|
31
|
-
with _cache.lock:
|
|
32
|
-
if _cache.data and now < _cache.expire_at:
|
|
33
|
-
return _cache.data
|
|
34
|
-
|
|
35
|
-
try:
|
|
36
|
-
resp = _auth_session.get(
|
|
37
|
-
auth_url,
|
|
38
|
-
params={"token": auth_token, "version": __version__},
|
|
39
|
-
timeout=(1.5, 3),
|
|
40
|
-
)
|
|
41
|
-
data = resp.json()
|
|
42
|
-
if data.get("ua"):
|
|
43
|
-
_cache.data = data
|
|
44
|
-
_cache.expire_at = now + _cache.ttl
|
|
45
|
-
return data
|
|
46
|
-
print(f"授权失败: {data.get('error_msg')}")
|
|
47
|
-
except Exception as e:
|
|
48
|
-
print(f"请求授权接口异常: {e}")
|
|
49
|
-
|
|
50
|
-
return _cache.data
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
# 如果访问的 URL 包含以下域名,走代理
|
|
54
|
-
default_hook_domains = [
|
|
55
|
-
"fund.eastmoney.com",
|
|
56
|
-
"push2.eastmoney.com",
|
|
57
|
-
"push2his.eastmoney.com",
|
|
58
|
-
"emweb.securities.eastmoney.com",
|
|
59
|
-
]
|
|
60
|
-
|
|
61
|
-
default_yfinance_hook_domains = ["finance.yahoo.com"]
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
def install_patch(auth_ip, auth_token="", retry=30, hook_domains=default_hook_domains):
|
|
65
|
-
def patched_request(self, method, url, **kwargs):
|
|
66
|
-
# 排除非目标域名
|
|
67
|
-
is_target = any(d in (url or "") for d in hook_domains)
|
|
68
|
-
is_js = urlparse(url or "").path.lower().endswith(".js")
|
|
69
|
-
is_html = urlparse(url or "").path.lower().endswith(".html")
|
|
70
|
-
|
|
71
|
-
if not is_target or is_js or is_html:
|
|
72
|
-
return _original_request(self, method, url, **kwargs)
|
|
73
|
-
|
|
74
|
-
auth_url = f"http://{auth_ip}:47001/api/akshare-auth"
|
|
75
|
-
|
|
76
|
-
# 重试逻辑
|
|
77
|
-
for _ in range(retry):
|
|
78
|
-
auth_res = get_auth_config_with_cache(auth_url, auth_token)
|
|
79
|
-
if not auth_res:
|
|
80
|
-
time.sleep(0.05)
|
|
81
|
-
continue
|
|
82
|
-
|
|
83
|
-
# 处理 Headers:确保不破坏业务代码传入的 headers
|
|
84
|
-
headers = kwargs.get("headers") or {}
|
|
85
|
-
headers["User-Agent"] = auth_res["ua"]
|
|
86
|
-
headers["Cookie"] = (
|
|
87
|
-
f"nid18={auth_res['nid18']}; nid18_create_time={auth_res['nid18_create_time']}"
|
|
88
|
-
)
|
|
89
|
-
kwargs["headers"] = headers
|
|
90
|
-
kwargs["proxies"] = {
|
|
91
|
-
"http": auth_res["proxy"],
|
|
92
|
-
"https": auth_res["proxy"],
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
kwargs["timeout"] = (2.5, 5)
|
|
96
|
-
|
|
97
|
-
try:
|
|
98
|
-
# 调用原始 request 方法
|
|
99
|
-
resp = _original_request(self, method, url, **kwargs)
|
|
100
|
-
if resp.ok:
|
|
101
|
-
try:
|
|
102
|
-
content_type = resp.headers.get("Content-Type").lower()
|
|
103
|
-
if "json" not in content_type:
|
|
104
|
-
return resp
|
|
105
|
-
_ = resp.json()
|
|
106
|
-
return resp
|
|
107
|
-
except:
|
|
108
|
-
pass
|
|
109
|
-
with _cache.lock:
|
|
110
|
-
_cache.expire_at = 0
|
|
111
|
-
time.sleep(0.05)
|
|
112
|
-
except Exception:
|
|
113
|
-
with _cache.lock:
|
|
114
|
-
_cache.expire_at = 0
|
|
115
|
-
time.sleep(0.05)
|
|
116
|
-
|
|
117
|
-
return _original_request(self, method, url, **kwargs)
|
|
118
|
-
|
|
119
|
-
requests.Session.request = patched_request
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
def install_yfinance_patch(
|
|
123
|
-
auth_ip, auth_token="", retry=30, hook_domains=default_yfinance_hook_domains
|
|
124
|
-
):
|
|
125
|
-
install_yfinance_patch_main(auth_ip, auth_token, retry, hook_domains)
|
|
File without changes
|
{akshare_proxy_patch-0.3.0 → akshare_proxy_patch-0.4.1}/akshare_proxy_patch.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
{akshare_proxy_patch-0.3.0 → akshare_proxy_patch-0.4.1}/akshare_proxy_patch.egg-info/requires.txt
RENAMED
|
File without changes
|
{akshare_proxy_patch-0.3.0 → akshare_proxy_patch-0.4.1}/akshare_proxy_patch.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|