akshare 1.15.5__py3-none-any.whl → 1.15.6__py3-none-any.whl

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 might be problematic. Click here for more details.

akshare/__init__.py CHANGED
@@ -2915,9 +2915,10 @@ amac_manager_cancelled_info # 中国证券投资基金业协会-信息公示-诚
2915
2915
  1.15.3 fix: fix stock_share_change_cninfo interface
2916
2916
  1.15.4 fix: fix stock_allotment_cninfo interface
2917
2917
  1.15.5 fix: fix stock_individual_spot_xq interface
2918
+ 1.15.6 fix: fix qdii_e_index_jsl interface
2918
2919
  """
2919
2920
 
2920
- __version__ = "1.15.5"
2921
+ __version__ = "1.15.6"
2921
2922
  __author__ = "AKFamily"
2922
2923
 
2923
2924
  import sys
@@ -5381,6 +5382,18 @@ from akshare.fund.fund_xq import (
5381
5382
  fund_individual_detail_hold_xq,
5382
5383
  )
5383
5384
 
5385
+ """
5386
+ 异常处理模块
5387
+ """
5388
+ from .exceptions import (
5389
+ AkshareException,
5390
+ APIError,
5391
+ DataParsingError,
5392
+ InvalidParameterError,
5393
+ NetworkError,
5394
+ RateLimitError,
5395
+ )
5396
+
5384
5397
  """
5385
5398
  Pro API 设置
5386
5399
  """
akshare/exceptions.py ADDED
@@ -0,0 +1,43 @@
1
+ """
2
+ AKShare 异常处理模块
3
+ """
4
+
5
+
6
+ class AkshareException(Exception):
7
+ """Base exception for akshare library"""
8
+
9
+ def __init__(self, message):
10
+ self.message = message
11
+ super().__init__(self.message)
12
+
13
+
14
+ class APIError(AkshareException):
15
+ """Raised when API request fails"""
16
+
17
+ def __init__(self, message, status_code=None):
18
+ self.status_code = status_code
19
+ super().__init__(f"API Error: {message} (Status code: {status_code})")
20
+
21
+
22
+ class DataParsingError(AkshareException):
23
+ """Raised when data parsing fails"""
24
+
25
+ pass
26
+
27
+
28
+ class InvalidParameterError(AkshareException):
29
+ """Raised when an invalid parameter is provided"""
30
+
31
+ pass
32
+
33
+
34
+ class NetworkError(AkshareException):
35
+ """Raised when network-related issues occur"""
36
+
37
+ pass
38
+
39
+
40
+ class RateLimitError(AkshareException):
41
+ """Raised when API rate limit is exceeded"""
42
+
43
+ pass
akshare/qdii/qdii_jsl.py CHANGED
@@ -7,7 +7,8 @@ Desc: 集思录-T+0 QDII
7
7
  """
8
8
 
9
9
  import pandas as pd
10
- import requests
10
+
11
+ from akshare.request import make_request_with_retry_json
11
12
 
12
13
 
13
14
  def qdii_e_index_jsl() -> pd.DataFrame:
@@ -22,8 +23,7 @@ def qdii_e_index_jsl() -> pd.DataFrame:
22
23
  "___jsl": "LST___t=1728207798534",
23
24
  "rp": "22",
24
25
  }
25
- r = requests.get(url, params=params)
26
- data_json = r.json()
26
+ data_json = make_request_with_retry_json(url, params)
27
27
  temp_df = pd.DataFrame([item["cell"] for item in data_json["rows"]])
28
28
  temp_df.rename(
29
29
  columns={
@@ -94,8 +94,7 @@ def qdii_e_comm_jsl() -> pd.DataFrame:
94
94
  "___jsl": "LST___t=1728207798534",
95
95
  "rp": "22",
96
96
  }
97
- r = requests.get(url, params=params)
98
- data_json = r.json()
97
+ data_json = make_request_with_retry_json(url, params=params)
99
98
  temp_df = pd.DataFrame([item["cell"] for item in data_json["rows"]])
100
99
  temp_df.rename(
101
100
  columns={
@@ -166,8 +165,7 @@ def qdii_a_index_jsl() -> pd.DataFrame:
166
165
  "___jsl": "LST___t=1728206439242",
167
166
  "rp": "22",
168
167
  }
169
- r = requests.get(url, params=params)
170
- data_json = r.json()
168
+ data_json = make_request_with_retry_json(url, params=params)
171
169
  temp_df = pd.DataFrame([item["cell"] for item in data_json["rows"]])
172
170
  temp_df.rename(
173
171
  columns={
akshare/request.py ADDED
@@ -0,0 +1,117 @@
1
+ import time
2
+
3
+ import requests
4
+ from requests.exceptions import RequestException
5
+
6
+ from akshare.exceptions import NetworkError, APIError, RateLimitError, DataParsingError
7
+ from akshare.utils.context import config
8
+
9
+
10
+ def make_request_with_retry_json(
11
+ url, params=None, headers=None, proxies=None, max_retries=3, retry_delay=1
12
+ ):
13
+ """
14
+ 发送 HTTP GET 请求,支持重试机制和代理设置。
15
+
16
+ :param url: 请求的 URL
17
+ :param params: URL 参数 (可选)
18
+ :param headers: 请求头 (可选)
19
+ :param proxies: 代理设置 (可选)
20
+ :param max_retries: 最大重试次数
21
+ :param retry_delay: 初始重试延迟(秒)
22
+ :return: 解析后的 JSON 数据
23
+ """
24
+ if proxies is None:
25
+ proxies = config.proxies
26
+ for attempt in range(max_retries):
27
+ try:
28
+ response = requests.get(
29
+ url, params=params, headers=headers, proxies=proxies
30
+ )
31
+ if response.status_code == 200:
32
+ try:
33
+ data = response.json()
34
+ if not data:
35
+ raise DataParsingError("Empty response data")
36
+ return data
37
+ except ValueError:
38
+ raise DataParsingError("Failed to parse JSON response")
39
+ elif response.status_code == 429:
40
+ raise RateLimitError(
41
+ f"Rate limit exceeded. Status code: {response.status_code}"
42
+ )
43
+ else:
44
+ raise APIError(
45
+ f"API request failed. Status code: {response.status_code}"
46
+ )
47
+
48
+ except (RequestException, RateLimitError, APIError, DataParsingError) as e:
49
+ if attempt == max_retries - 1:
50
+ if isinstance(e, RateLimitError):
51
+ raise
52
+ elif isinstance(e, (APIError, DataParsingError)):
53
+ raise
54
+ else:
55
+ raise NetworkError(
56
+ f"Failed to connect after {max_retries} attempts: {str(e)}"
57
+ )
58
+
59
+ time.sleep(retry_delay)
60
+ retry_delay *= 2 # 指数退避策略
61
+
62
+ raise NetworkError(f"Failed to connect after {max_retries} attempts")
63
+
64
+
65
+ def make_request_with_retry_text(
66
+ url, params=None, headers=None, proxies=None, max_retries=3, retry_delay=1
67
+ ):
68
+ """
69
+ 发送 HTTP GET 请求,支持重试机制和代理设置。
70
+
71
+ :param url: 请求的 URL
72
+ :param params: URL 参数 (可选)
73
+ :param headers: 请求头 (可选)
74
+ :param proxies: 代理设置 (可选)
75
+ :param max_retries: 最大重试次数
76
+ :param retry_delay: 初始重试延迟(秒)
77
+ :return: 解析后的 JSON 数据
78
+ """
79
+ if proxies is None:
80
+ proxies = config.proxies
81
+ for attempt in range(max_retries):
82
+ try:
83
+ response = requests.get(
84
+ url, params=params, headers=headers, proxies=proxies
85
+ )
86
+ if response.status_code == 200:
87
+ try:
88
+ data = response.text
89
+ if not data:
90
+ raise DataParsingError("Empty response data")
91
+ return data
92
+ except ValueError:
93
+ raise DataParsingError("Failed to parse JSON response")
94
+ elif response.status_code == 429:
95
+ raise RateLimitError(
96
+ f"Rate limit exceeded. Status code: {response.status_code}"
97
+ )
98
+ else:
99
+ raise APIError(
100
+ f"API request failed. Status code: {response.status_code}"
101
+ )
102
+
103
+ except (RequestException, RateLimitError, APIError, DataParsingError) as e:
104
+ if attempt == max_retries - 1:
105
+ if isinstance(e, RateLimitError):
106
+ raise
107
+ elif isinstance(e, (APIError, DataParsingError)):
108
+ raise
109
+ else:
110
+ raise NetworkError(
111
+ f"Failed to connect after {max_retries} attempts: {str(e)}"
112
+ )
113
+
114
+ time.sleep(retry_delay)
115
+ retry_delay *= 2 # 指数退避策略
116
+
117
+ raise NetworkError(f"Failed to connect after {max_retries} attempts")
@@ -0,0 +1,43 @@
1
+ class AkshareConfig:
2
+ _instance = None
3
+
4
+ def __new__(cls):
5
+ if cls._instance is None:
6
+ cls._instance = super().__new__(cls)
7
+ cls._instance.proxies = None
8
+ return cls._instance
9
+
10
+ @classmethod
11
+ def set_proxies(cls, proxies):
12
+ cls().proxies = proxies
13
+
14
+ @classmethod
15
+ def get_proxies(cls):
16
+ return cls().proxies
17
+
18
+
19
+ config = AkshareConfig()
20
+
21
+
22
+ # 导出 set_proxies 函数
23
+ def set_proxies(proxies):
24
+ config.set_proxies(proxies)
25
+
26
+
27
+ def get_proxies():
28
+ return config.get_proxies()
29
+
30
+
31
+ class ProxyContext:
32
+ def __init__(self, proxies):
33
+ self.proxies = proxies
34
+ self.old_proxies = None
35
+
36
+ def __enter__(self):
37
+ self.old_proxies = config.get_proxies()
38
+ config.set_proxies(self.proxies)
39
+ return self
40
+
41
+ def __exit__(self, exc_type, exc_val, exc_tb):
42
+ config.set_proxies(self.old_proxies)
43
+ return False # 不处理异常
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: akshare
3
- Version: 1.15.5
3
+ Version: 1.15.6
4
4
  Summary: AKShare is an elegant and simple financial data interface library for Python, built for human beings!
5
5
  Home-page: https://github.com/akfamily/akshare
6
6
  Author: AKFamily
@@ -1,5 +1,7 @@
1
- akshare/__init__.py,sha256=RVQQLjzfjvxNz6LMAMY_pIQKz8qCSZzedyRMtRmv7X8,182499
1
+ akshare/__init__.py,sha256=i8uUAu291ta8SavpyTgeKrwLT1Qu3aSmxaWdO3Ca0Wo,182721
2
2
  akshare/datasets.py,sha256=-qdwaQjgBlftX84uM74KJqCYJYkQ50PV416_neA4uls,995
3
+ akshare/exceptions.py,sha256=WEJjIhSmJ_xXNW6grwV4nufE_cfmmyuhmueVGiN1VAg,878
4
+ akshare/request.py,sha256=HtFFf9MhfEibR-ETWe-1Tts6ELU4VKSqA-ghaXjegQM,4252
3
5
  akshare/air/__init__.py,sha256=RMTf1bT5EOE3ttWpn3hGu1LtUmsVxDoa0W7W0gXHOy8,81
4
6
  akshare/air/air_hebei.py,sha256=xIXNGLK7IGYqrkteM9fxnHAwWqk6PCQs6D9-ggZ7byY,4442
5
7
  akshare/air/air_zhenqi.py,sha256=FurRxuYyoZpTa2lsP6BgUJfbfMgOO26_VPuc-ekKZXs,9636
@@ -210,7 +212,7 @@ akshare/pro/client.py,sha256=p9r3fZYGgfMplQwGLo8oPAen8w65xennP5D1Ca89im4,2248
210
212
  akshare/pro/cons.py,sha256=xckSrLyYcd2pY822GH8BEE9DFo-eu7wIF2XFeIu-uwk,244
211
213
  akshare/pro/data_pro.py,sha256=xeuQ_fcJ8qOeleITkr-Yo0OjyCuWHE0ydq3q8AE5PAY,830
212
214
  akshare/qdii/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
213
- akshare/qdii/qdii_jsl.py,sha256=2zkHCQKTVg31lke9b8aRvFHTBJ3v97ds6V4JmAsnX98,7888
215
+ akshare/qdii/qdii_jsl.py,sha256=-BbTDkrevK65D3x9xSc3v8KJPT88nIuJK9K_9q3UP2A,7920
214
216
  akshare/qhkc/__init__.py,sha256=RMTf1bT5EOE3ttWpn3hGu1LtUmsVxDoa0W7W0gXHOy8,81
215
217
  akshare/qhkc/qhkc_api.py,sha256=1dGkMzxdS1p1z5aeXTeIvA2VbQzZAOP1bCZPTySkGDo,8235
216
218
  akshare/qhkc_web/__init__.py,sha256=RMTf1bT5EOE3ttWpn3hGu1LtUmsVxDoa0W7W0gXHOy8,81
@@ -372,14 +374,15 @@ akshare/tool/__init__.py,sha256=RMTf1bT5EOE3ttWpn3hGu1LtUmsVxDoa0W7W0gXHOy8,81
372
374
  akshare/tool/trade_date_hist.py,sha256=o9021QHdOEVucjynFl0jLEi1PEMlNxvDKnMsFSwRfqg,1431
373
375
  akshare/utils/__init__.py,sha256=HbKUP2vZApbeK2PTZVO_m-6kAUymfDwm2yv3Kr4R_1A,81
374
376
  akshare/utils/cons.py,sha256=PFZndkG3lMW1Qhg-wqcZmSowFXwQUsYYCLZT4s1Xkwc,225
377
+ akshare/utils/context.py,sha256=Hl4kPUzQ1CecRzu5JvTKpTpiMLfzAzYzG7F5hktlsCQ,934
375
378
  akshare/utils/demjson.py,sha256=xW2z0UGS2zzyH_dzhd765ZveuXRbfjkM7KBiI8H5fJA,241609
376
379
  akshare/utils/func.py,sha256=PDkwpyCjZCbCLSAG9wBQt-sYNtb1XlpUBvhAfuSLf3s,586
377
380
  akshare/utils/token_process.py,sha256=K4rGXjh_tgugbRcyOK2h2x0jP3PT65IIK7nxhUKhOeQ,666
378
381
  akshare/utils/tqdm.py,sha256=MuPNwcswkOGjwWQOMWXi9ZvQ_RmW4obCWRj2i7HM7FE,847
379
382
  tests/__init__.py,sha256=gNzhlO0UPjFq6Ieb38kaVIODXv4cTDByrdohAZnDYt4,82
380
383
  tests/test_func.py,sha256=j1MGYbZI2if2j_LY1S4FLsf4qfq4NwVqD5wmRlv5Log,832
381
- akshare-1.15.5.dist-info/LICENSE,sha256=mmSZCPgfHiVw34LXuFArd-SUgQtBJ_QsIlh-kWlDHfs,1073
382
- akshare-1.15.5.dist-info/METADATA,sha256=_JK5l9jVCLzQX1T_0BpvithT4dW3YYrG__POzHYrj-c,14162
383
- akshare-1.15.5.dist-info/WHEEL,sha256=OVMc5UfuAQiSplgO0_WdW7vXVGAt9Hdd6qtN4HotdyA,91
384
- akshare-1.15.5.dist-info/top_level.txt,sha256=jsf9ZzZPmHaISTVumQPsAw7vv7Yv-PdEVW70SMEelQQ,14
385
- akshare-1.15.5.dist-info/RECORD,,
384
+ akshare-1.15.6.dist-info/LICENSE,sha256=mmSZCPgfHiVw34LXuFArd-SUgQtBJ_QsIlh-kWlDHfs,1073
385
+ akshare-1.15.6.dist-info/METADATA,sha256=STv32lzoJVQVkspXzHNp_pJy1n5c0Vvm-jXh8WbZrMU,14162
386
+ akshare-1.15.6.dist-info/WHEEL,sha256=OVMc5UfuAQiSplgO0_WdW7vXVGAt9Hdd6qtN4HotdyA,91
387
+ akshare-1.15.6.dist-info/top_level.txt,sha256=jsf9ZzZPmHaISTVumQPsAw7vv7Yv-PdEVW70SMEelQQ,14
388
+ akshare-1.15.6.dist-info/RECORD,,