akshare-proxy-patch 0.2.1__tar.gz → 0.2.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.
Potentially problematic release.
This version of akshare-proxy-patch might be problematic. Click here for more details.
- {akshare_proxy_patch-0.2.1 → akshare_proxy_patch-0.2.2}/PKG-INFO +1 -1
- akshare_proxy_patch-0.2.2/akshare_proxy_patch/__init__.py +100 -0
- {akshare_proxy_patch-0.2.1 → akshare_proxy_patch-0.2.2}/akshare_proxy_patch.egg-info/PKG-INFO +1 -1
- {akshare_proxy_patch-0.2.1 → akshare_proxy_patch-0.2.2}/pyproject.toml +1 -1
- {akshare_proxy_patch-0.2.1 → akshare_proxy_patch-0.2.2}/setup.py +1 -1
- akshare_proxy_patch-0.2.1/akshare_proxy_patch/__init__.py +0 -93
- {akshare_proxy_patch-0.2.1 → akshare_proxy_patch-0.2.2}/LICENSE +0 -0
- {akshare_proxy_patch-0.2.1 → akshare_proxy_patch-0.2.2}/README.md +0 -0
- {akshare_proxy_patch-0.2.1 → akshare_proxy_patch-0.2.2}/akshare_proxy_patch.egg-info/SOURCES.txt +0 -0
- {akshare_proxy_patch-0.2.1 → akshare_proxy_patch-0.2.2}/akshare_proxy_patch.egg-info/dependency_links.txt +0 -0
- {akshare_proxy_patch-0.2.1 → akshare_proxy_patch-0.2.2}/akshare_proxy_patch.egg-info/requires.txt +0 -0
- {akshare_proxy_patch-0.2.1 → akshare_proxy_patch-0.2.2}/akshare_proxy_patch.egg-info/top_level.txt +0 -0
- {akshare_proxy_patch-0.2.1 → akshare_proxy_patch-0.2.2}/setup.cfg +0 -0
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import time
|
|
2
|
+
import threading
|
|
3
|
+
import requests
|
|
4
|
+
from requests.adapters import HTTPAdapter
|
|
5
|
+
from copy import deepcopy
|
|
6
|
+
|
|
7
|
+
# --- 全局配置与状态 ---
|
|
8
|
+
__version__ = "1.0.2"
|
|
9
|
+
_original_send = HTTPAdapter.send
|
|
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 = 20
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
_cache = AuthCache()
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def get_auth_config_with_cache(auth_url, auth_token):
|
|
25
|
+
now = time.time()
|
|
26
|
+
|
|
27
|
+
# 检查缓存是否有效 (双重检查锁前置)
|
|
28
|
+
if _cache.data and now < _cache.expire_at:
|
|
29
|
+
return _cache.data
|
|
30
|
+
|
|
31
|
+
# 缓存失效,加锁更新
|
|
32
|
+
with _cache.lock:
|
|
33
|
+
# 再次检查,防止多个线程同时穿透锁
|
|
34
|
+
if _cache.data and now < _cache.expire_at:
|
|
35
|
+
return _cache.data
|
|
36
|
+
|
|
37
|
+
try:
|
|
38
|
+
resp = _auth_session.get(
|
|
39
|
+
auth_url,
|
|
40
|
+
params={"token": auth_token, "version": __version__},
|
|
41
|
+
timeout=5,
|
|
42
|
+
)
|
|
43
|
+
data = resp.json()
|
|
44
|
+
if data.get("ua"):
|
|
45
|
+
_cache.data = data
|
|
46
|
+
_cache.expire_at = now + _cache.ttl
|
|
47
|
+
return data
|
|
48
|
+
print(f"授权失败: {data.get('error_msg')}")
|
|
49
|
+
except Exception as e:
|
|
50
|
+
print(f"请求授权接口异常: {e}")
|
|
51
|
+
|
|
52
|
+
return _cache.data
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def install_patch(auth_ip, auth_token):
|
|
56
|
+
def patched_send(self, request, **kwargs):
|
|
57
|
+
# 排除非目标域名,减少性能损耗
|
|
58
|
+
url = request.url or ""
|
|
59
|
+
if not any(
|
|
60
|
+
d in url
|
|
61
|
+
for d in [
|
|
62
|
+
"fund.eastmoney.com",
|
|
63
|
+
"push2.eastmoney.com",
|
|
64
|
+
"push2his.eastmoney.com",
|
|
65
|
+
]
|
|
66
|
+
):
|
|
67
|
+
return _original_send(self, request, **kwargs)
|
|
68
|
+
|
|
69
|
+
auth_url = f"http://{auth_ip}:47001/api/akshare-auth"
|
|
70
|
+
|
|
71
|
+
for _ in range(30):
|
|
72
|
+
auth_res = get_auth_config_with_cache(auth_url, auth_token)
|
|
73
|
+
if not auth_res:
|
|
74
|
+
time.sleep(0.5)
|
|
75
|
+
continue
|
|
76
|
+
|
|
77
|
+
request.headers["User-Agent"] = auth_res["ua"]
|
|
78
|
+
request.headers["Cookie"] = (
|
|
79
|
+
f"nid18={auth_res['nid18']}; nid18_create_time={auth_res['nid18_create_time']}"
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
# 动态注入代理
|
|
83
|
+
kwargs["proxies"] = {
|
|
84
|
+
"http": auth_res["proxy"],
|
|
85
|
+
"https": auth_res["proxy"],
|
|
86
|
+
}
|
|
87
|
+
kwargs["timeout"] = 8
|
|
88
|
+
|
|
89
|
+
try:
|
|
90
|
+
resp = _original_send(self, request, **kwargs)
|
|
91
|
+
if resp.ok:
|
|
92
|
+
return resp
|
|
93
|
+
except Exception:
|
|
94
|
+
with _cache.lock:
|
|
95
|
+
_cache.expire_at = 0
|
|
96
|
+
time.sleep(0.1)
|
|
97
|
+
|
|
98
|
+
return _original_send(self, request, **kwargs)
|
|
99
|
+
|
|
100
|
+
HTTPAdapter.send = patched_send
|
|
@@ -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.2.
|
|
8
|
+
version="0.2.2", # 版本号
|
|
9
9
|
author="cheapproxy.net",
|
|
10
10
|
author_email="emezxyj1@gmail.com",
|
|
11
11
|
description="AkShare 报错全局Hook",
|
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
import time
|
|
2
|
-
import threading
|
|
3
|
-
import requests
|
|
4
|
-
from copy import deepcopy
|
|
5
|
-
from requests.adapters import HTTPAdapter
|
|
6
|
-
|
|
7
|
-
# 备份原始 send
|
|
8
|
-
_original_send = HTTPAdapter.send
|
|
9
|
-
|
|
10
|
-
# 线程局部状态
|
|
11
|
-
_thread_state = threading.local()
|
|
12
|
-
|
|
13
|
-
# 独立 Session:专门用于授权请求(不走 hook)
|
|
14
|
-
_auth_session = requests.Session()
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
def get_auth_config_realtime(auth_url, auth_token):
|
|
18
|
-
"""实时获取授权信息(不走全局 hook)"""
|
|
19
|
-
try:
|
|
20
|
-
resp = _auth_session.get(
|
|
21
|
-
auth_url,
|
|
22
|
-
params={"token": auth_token},
|
|
23
|
-
timeout=5,
|
|
24
|
-
)
|
|
25
|
-
data = resp.json()
|
|
26
|
-
if data.get("ua"):
|
|
27
|
-
return data
|
|
28
|
-
error_msg = (
|
|
29
|
-
data.get("error_msg")
|
|
30
|
-
or "接口授权失败,请登录 https://cheapproxy.net 联系客服获取授权码"
|
|
31
|
-
)
|
|
32
|
-
print(f"========={error_msg}========")
|
|
33
|
-
except Exception as e:
|
|
34
|
-
print(f"=========接口授权失败,{e}========")
|
|
35
|
-
return None
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
def install_patch(auth_ip, auth_token):
|
|
39
|
-
def patched_send(self, request, **kwargs):
|
|
40
|
-
# 如果明确标记跳过 hook,直接原逻辑
|
|
41
|
-
if getattr(_thread_state, "skip_hook", False):
|
|
42
|
-
return _original_send(self, request, **kwargs)
|
|
43
|
-
|
|
44
|
-
url = request.url or ""
|
|
45
|
-
|
|
46
|
-
is_target = any(
|
|
47
|
-
d in url
|
|
48
|
-
for d in (
|
|
49
|
-
"fund.eastmoney.com",
|
|
50
|
-
"push2.eastmoney.com",
|
|
51
|
-
"push2his.eastmoney.com",
|
|
52
|
-
)
|
|
53
|
-
)
|
|
54
|
-
|
|
55
|
-
# 非目标域名直接放行
|
|
56
|
-
if not is_target:
|
|
57
|
-
return _original_send(self, request, **kwargs)
|
|
58
|
-
|
|
59
|
-
auth_url = f"http://{auth_ip}:47001/api/akshare-auth"
|
|
60
|
-
|
|
61
|
-
# 每次请求都用“独立副本”
|
|
62
|
-
new_request = deepcopy(request)
|
|
63
|
-
new_kwargs = deepcopy(kwargs)
|
|
64
|
-
|
|
65
|
-
for _ in range(30):
|
|
66
|
-
try:
|
|
67
|
-
auth_res = get_auth_config_realtime(auth_url, auth_token)
|
|
68
|
-
if auth_res:
|
|
69
|
-
new_request.headers = deepcopy(request.headers)
|
|
70
|
-
new_request.headers["User-Agent"] = auth_res["ua"]
|
|
71
|
-
new_request.headers["Cookie"] = (
|
|
72
|
-
f"nid18={auth_res['nid18']}; "
|
|
73
|
-
f"nid18_create_time={auth_res['nid18_create_time']}"
|
|
74
|
-
)
|
|
75
|
-
|
|
76
|
-
proxy = auth_res["proxy"]
|
|
77
|
-
new_kwargs["proxies"] = {
|
|
78
|
-
"http": proxy,
|
|
79
|
-
"https": proxy,
|
|
80
|
-
}
|
|
81
|
-
new_kwargs["timeout"] = 8
|
|
82
|
-
|
|
83
|
-
resp = _original_send(self, new_request, **new_kwargs)
|
|
84
|
-
if resp.ok:
|
|
85
|
-
return resp
|
|
86
|
-
|
|
87
|
-
except Exception:
|
|
88
|
-
time.sleep(0.01)
|
|
89
|
-
|
|
90
|
-
# 兜底:30 次都失败,走原请求
|
|
91
|
-
return _original_send(self, request, **kwargs)
|
|
92
|
-
|
|
93
|
-
HTTPAdapter.send = patched_send
|
|
File without changes
|
|
File without changes
|
{akshare_proxy_patch-0.2.1 → akshare_proxy_patch-0.2.2}/akshare_proxy_patch.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
{akshare_proxy_patch-0.2.1 → akshare_proxy_patch-0.2.2}/akshare_proxy_patch.egg-info/requires.txt
RENAMED
|
File without changes
|
{akshare_proxy_patch-0.2.1 → akshare_proxy_patch-0.2.2}/akshare_proxy_patch.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|