mcp-query-table 0.3.8__py3-none-any.whl → 0.3.10__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.
- mcp_query_table/__main__.py +1 -1
- mcp_query_table/_version.py +1 -1
- mcp_query_table/server.py +2 -1
- mcp_query_table/sites/eastmoney.py +8 -4
- mcp_query_table/sites/iwencai.py +8 -8
- mcp_query_table/sites/tdx.py +4 -3
- mcp_query_table/tool.py +13 -5
- mcp_query_table/utils.py +0 -17
- {mcp_query_table-0.3.8.dist-info → mcp_query_table-0.3.10.dist-info}/METADATA +2 -3
- mcp_query_table-0.3.10.dist-info/RECORD +19 -0
- mcp_query_table-0.3.8.dist-info/RECORD +0 -19
- {mcp_query_table-0.3.8.dist-info → mcp_query_table-0.3.10.dist-info}/WHEEL +0 -0
- {mcp_query_table-0.3.8.dist-info → mcp_query_table-0.3.10.dist-info}/licenses/LICENSE +0 -0
mcp_query_table/__main__.py
CHANGED
|
@@ -17,7 +17,7 @@ def main():
|
|
|
17
17
|
parser.add_argument("--executable_path", type=str, help="浏览器路径",
|
|
18
18
|
nargs="?", default=r'C:\Program Files\Google\Chrome\Application\chrome.exe')
|
|
19
19
|
parser.add_argument("--user_data_dir", type=str, help="浏览器用户数据目录",
|
|
20
|
-
nargs="?", default=rf'C:\Users\{getpass.getuser()}\AppData\Local\Google\Chrome\User Data')
|
|
20
|
+
nargs="?", default=rf'C:\Users\{getpass.getuser()}\AppData\Local\Google\Chrome\User Data\Default')
|
|
21
21
|
parser.add_argument("--transport", type=str, help="传输类型",
|
|
22
22
|
default='stdio', choices=['stdio', 'sse'])
|
|
23
23
|
parser.add_argument("--host", type=str, help="MCP服务端绑定地址",
|
mcp_query_table/_version.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "0.3.
|
|
1
|
+
__version__ = "0.3.10"
|
mcp_query_table/server.py
CHANGED
|
@@ -53,9 +53,10 @@ async def query(
|
|
|
53
53
|
query_type: Annotated[QueryType, Field(default=QueryType.CNStock,
|
|
54
54
|
description="查询类型。支持`A股`、`指数`、`基金`、`港股`、`美股`等")],
|
|
55
55
|
max_page: Annotated[int, Field(default=1, ge=1, le=10, description="最大页数。只查第一页即可")],
|
|
56
|
+
rename: Annotated[bool, Field(default=False, description="是否重命名列名")],
|
|
56
57
|
site: Annotated[Site, Field(default=Site.THS, description="站点。支持`东方财富`、`通达信`、`同花顺`")]
|
|
57
58
|
) -> str:
|
|
58
|
-
return await qsv.query(query_input, query_type, max_page, site)
|
|
59
|
+
return await qsv.query(query_input, query_type, max_page, rename, site)
|
|
59
60
|
|
|
60
61
|
|
|
61
62
|
# chat功能不通过mcp暴露,因为在Cline等客户端中本就有LLM功能,反而导致返回的数据没有正确提交
|
|
@@ -81,7 +81,7 @@ class Pagination:
|
|
|
81
81
|
datas.extend(v)
|
|
82
82
|
return datas
|
|
83
83
|
|
|
84
|
-
def get_dataframe(self):
|
|
84
|
+
def get_dataframe(self, rename: bool):
|
|
85
85
|
columns = {x['key']: x['title'] for x in self.columns}
|
|
86
86
|
dtypes = {x['key']: convert_type(x['dataType']) for x in self.columns}
|
|
87
87
|
|
|
@@ -98,7 +98,10 @@ class Pagination:
|
|
|
98
98
|
except ValueError:
|
|
99
99
|
logger.info("转换失败 {}:{}", k, v)
|
|
100
100
|
|
|
101
|
-
|
|
101
|
+
if rename:
|
|
102
|
+
return df.rename(columns=columns)
|
|
103
|
+
else:
|
|
104
|
+
return df
|
|
102
105
|
|
|
103
106
|
|
|
104
107
|
P = Pagination()
|
|
@@ -121,7 +124,8 @@ async def on_response(response):
|
|
|
121
124
|
async def query(page: Page,
|
|
122
125
|
q: str = "收盘价>100元",
|
|
123
126
|
type_: QueryType = 'stock',
|
|
124
|
-
max_page: int = 5
|
|
127
|
+
max_page: int = 5,
|
|
128
|
+
rename: bool = True) -> pd.DataFrame:
|
|
125
129
|
type = _type_.get(type_, None)
|
|
126
130
|
assert type is not None, f"不支持的类型:{type_}"
|
|
127
131
|
|
|
@@ -141,4 +145,4 @@ async def query(page: Page,
|
|
|
141
145
|
await page.get_by_role("button", name="下一页").click()
|
|
142
146
|
await on_response(await response_info.value)
|
|
143
147
|
|
|
144
|
-
return P.get_dataframe()
|
|
148
|
+
return P.get_dataframe(rename)
|
mcp_query_table/sites/iwencai.py
CHANGED
|
@@ -10,10 +10,8 @@ import re
|
|
|
10
10
|
import pandas as pd
|
|
11
11
|
from loguru import logger
|
|
12
12
|
from playwright.async_api import Page
|
|
13
|
-
from playwright_stealth import stealth_async
|
|
14
13
|
|
|
15
14
|
from mcp_query_table.enums import QueryType
|
|
16
|
-
from mcp_query_table.utils import FixedConfig
|
|
17
15
|
|
|
18
16
|
# 初次查询页面
|
|
19
17
|
_PAGE1_ = 'https://www.iwencai.com/customized/chart/get-robot-data'
|
|
@@ -82,7 +80,7 @@ class Pagination:
|
|
|
82
80
|
datas.extend(v)
|
|
83
81
|
return datas
|
|
84
82
|
|
|
85
|
-
def get_dataframe(self):
|
|
83
|
+
def get_dataframe(self, rename: bool):
|
|
86
84
|
columns = {x['key']: x['index_name'] for x in self.columns}
|
|
87
85
|
dtypes = {x['key']: convert_type(x['type']) for x in self.columns}
|
|
88
86
|
|
|
@@ -96,7 +94,10 @@ class Pagination:
|
|
|
96
94
|
except ValueError:
|
|
97
95
|
logger.info("转换失败 {}:{}", k, v)
|
|
98
96
|
|
|
99
|
-
|
|
97
|
+
if rename:
|
|
98
|
+
return df.rename(columns=columns)
|
|
99
|
+
else:
|
|
100
|
+
return df
|
|
100
101
|
|
|
101
102
|
|
|
102
103
|
P = Pagination()
|
|
@@ -150,12 +151,11 @@ async def on_response(response):
|
|
|
150
151
|
async def query(page: Page,
|
|
151
152
|
w: str = "收盘价>1000元",
|
|
152
153
|
type_: QueryType = 'stock',
|
|
153
|
-
max_page: int = 5
|
|
154
|
+
max_page: int = 5,
|
|
155
|
+
rename: bool = False) -> pd.DataFrame:
|
|
154
156
|
querytype = _querytype_.get(type_, None)
|
|
155
157
|
assert querytype is not None, f"不支持的类型:{type_}"
|
|
156
158
|
|
|
157
|
-
await stealth_async(page, FixedConfig())
|
|
158
|
-
|
|
159
159
|
await page.route(re.compile(r'.*\.(?:jpg|jpeg|png|gif|webp)(?:$|\?)'), lambda route: route.abort())
|
|
160
160
|
|
|
161
161
|
P.reset()
|
|
@@ -172,4 +172,4 @@ async def query(page: Page,
|
|
|
172
172
|
await page.get_by_text("下页").click()
|
|
173
173
|
await on_response(await response_info.value)
|
|
174
174
|
|
|
175
|
-
return P.get_dataframe()
|
|
175
|
+
return P.get_dataframe(rename)
|
mcp_query_table/sites/tdx.py
CHANGED
|
@@ -78,7 +78,7 @@ class Pagination:
|
|
|
78
78
|
datas.extend(v)
|
|
79
79
|
return datas
|
|
80
80
|
|
|
81
|
-
def get_dataframe(self):
|
|
81
|
+
def get_dataframe(self, rename: bool):
|
|
82
82
|
dtypes = [convert_type(x) for x in self.dtypes]
|
|
83
83
|
df = pd.DataFrame(self.get_list(), columns=self.columns)
|
|
84
84
|
for i, v in enumerate(dtypes):
|
|
@@ -128,7 +128,8 @@ async def on_response2(response):
|
|
|
128
128
|
async def query(page: Page,
|
|
129
129
|
message: str = "收盘价>100元",
|
|
130
130
|
type_: QueryType = 'AG',
|
|
131
|
-
max_page: int = 5
|
|
131
|
+
max_page: int = 5,
|
|
132
|
+
rename: bool = False) -> pd.DataFrame:
|
|
132
133
|
queryType = _queryType_.get(type_, None)
|
|
133
134
|
assert queryType is not None, f"不支持的类型:{type_}"
|
|
134
135
|
|
|
@@ -147,4 +148,4 @@ async def query(page: Page,
|
|
|
147
148
|
await page.get_by_role("button", name="下一页").click()
|
|
148
149
|
await on_response1(await response_info.value)
|
|
149
150
|
|
|
150
|
-
return P.get_dataframe()
|
|
151
|
+
return P.get_dataframe(rename)
|
mcp_query_table/tool.py
CHANGED
|
@@ -4,11 +4,12 @@ import sys
|
|
|
4
4
|
import time
|
|
5
5
|
from pathlib import Path
|
|
6
6
|
from typing import Optional
|
|
7
|
-
from urllib.parse import urlparse
|
|
7
|
+
from urllib.parse import urlparse, quote
|
|
8
8
|
|
|
9
9
|
import pandas as pd
|
|
10
10
|
from loguru import logger
|
|
11
11
|
from playwright.async_api import async_playwright, Playwright, Page
|
|
12
|
+
from playwright_stealth import Stealth
|
|
12
13
|
|
|
13
14
|
from mcp_query_table.enums import QueryType, Site, Provider
|
|
14
15
|
|
|
@@ -204,6 +205,8 @@ class BrowserManager:
|
|
|
204
205
|
self.context = await self.browser.new_context()
|
|
205
206
|
else:
|
|
206
207
|
self.context = self.browser.contexts[0]
|
|
208
|
+
# 爱问财,无头模式,需要使用 stealth 插件
|
|
209
|
+
await Stealth().apply_stealth_async(self.context)
|
|
207
210
|
|
|
208
211
|
# 复用打开的page
|
|
209
212
|
for page in self.context.pages:
|
|
@@ -246,7 +249,9 @@ async def query(
|
|
|
246
249
|
query_input: str = "收盘价>100元",
|
|
247
250
|
query_type: QueryType = QueryType.CNStock,
|
|
248
251
|
max_page: int = 5,
|
|
249
|
-
|
|
252
|
+
rename: bool = False,
|
|
253
|
+
site: Site = Site.THS,
|
|
254
|
+
) -> pd.DataFrame:
|
|
250
255
|
"""查询表格
|
|
251
256
|
|
|
252
257
|
Parameters
|
|
@@ -259,6 +264,8 @@ async def query(
|
|
|
259
264
|
查询类型, by default QueryType.astock
|
|
260
265
|
max_page : int, optional
|
|
261
266
|
最大页数, by default 5
|
|
267
|
+
rename: bool
|
|
268
|
+
是否重命名列名, by default False
|
|
262
269
|
site : Site, optional
|
|
263
270
|
站点, by default Site.iwencai
|
|
264
271
|
|
|
@@ -268,16 +275,17 @@ async def query(
|
|
|
268
275
|
查询结果
|
|
269
276
|
|
|
270
277
|
"""
|
|
278
|
+
query_input = quote(query_input.strip(), safe='')
|
|
271
279
|
|
|
272
280
|
if site == Site.EastMoney:
|
|
273
281
|
from mcp_query_table.sites.eastmoney import query
|
|
274
|
-
return await query(page, query_input, query_type, max_page)
|
|
282
|
+
return await query(page, query_input, query_type, max_page, rename)
|
|
275
283
|
if site == Site.THS:
|
|
276
284
|
from mcp_query_table.sites.iwencai import query
|
|
277
|
-
return await query(page, query_input, query_type, max_page)
|
|
285
|
+
return await query(page, query_input, query_type, max_page, rename)
|
|
278
286
|
if site == Site.TDX:
|
|
279
287
|
from mcp_query_table.sites.tdx import query
|
|
280
|
-
return await query(page, query_input, query_type, max_page)
|
|
288
|
+
return await query(page, query_input, query_type, max_page, rename)
|
|
281
289
|
|
|
282
290
|
raise ValueError(f"未支持的站点:{site}")
|
|
283
291
|
|
mcp_query_table/utils.py
CHANGED
|
@@ -1,10 +1,6 @@
|
|
|
1
|
-
import random
|
|
2
|
-
import string
|
|
3
1
|
from pathlib import Path
|
|
4
2
|
from typing import List, Tuple
|
|
5
3
|
|
|
6
|
-
from playwright_stealth import StealthConfig
|
|
7
|
-
|
|
8
4
|
|
|
9
5
|
def is_image(path: str) -> bool:
|
|
10
6
|
"""判断是否是图片文件"""
|
|
@@ -36,16 +32,3 @@ class GlobalVars:
|
|
|
36
32
|
|
|
37
33
|
def get_text(self):
|
|
38
34
|
return self.text
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
# https://github.com/AtuboDad/playwright_stealth/issues/31#issuecomment-2342541305
|
|
42
|
-
class FixedConfig(StealthConfig):
|
|
43
|
-
|
|
44
|
-
@property
|
|
45
|
-
def enabled_scripts(self):
|
|
46
|
-
key = "".join(random.choices(string.ascii_letters, k=10))
|
|
47
|
-
for script in super().enabled_scripts:
|
|
48
|
-
if "const opts" in script:
|
|
49
|
-
yield script.replace("const opts", f"window.{key}")
|
|
50
|
-
continue
|
|
51
|
-
yield script.replace("opts", f"window.{key}")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mcp_query_table
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.10
|
|
4
4
|
Summary: query table from website, support MCP
|
|
5
5
|
Author-email: wukan <wu-kan@163.com>
|
|
6
6
|
License: MIT License
|
|
@@ -33,8 +33,7 @@ Requires-Dist: loguru
|
|
|
33
33
|
Requires-Dist: mcp
|
|
34
34
|
Requires-Dist: pandas
|
|
35
35
|
Requires-Dist: playwright
|
|
36
|
-
Requires-Dist: playwright-stealth
|
|
37
|
-
Requires-Dist: setuptools
|
|
36
|
+
Requires-Dist: playwright-stealth>=2.0.0
|
|
38
37
|
Requires-Dist: tabulate
|
|
39
38
|
Description-Content-Type: text/markdown
|
|
40
39
|
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
mcp_query_table/__init__.py,sha256=K-0DU2hpeRvM9ZAuky0aWZtJLuOgKg7ZRd-pL9noc0o,330
|
|
2
|
+
mcp_query_table/__main__.py,sha256=K0r7y8PD9y9pFg3bAQxNo21KlQpGz1jqGg_zptPfenM,1461
|
|
3
|
+
mcp_query_table/_version.py,sha256=h9TycTJK2pK49s87IMbNRq4lTqRt3xctcJl2jxCe3sU,23
|
|
4
|
+
mcp_query_table/enums.py,sha256=7bu0m0zJBIfiS-eHGURw1ZHWNXgsq6gH1SztUhCgF-Y,678
|
|
5
|
+
mcp_query_table/server.py,sha256=hMmFYBRZX0oz2jJQcRQJaMe-jfXS25yXayNTymv5v1A,3849
|
|
6
|
+
mcp_query_table/tool.py,sha256=w1MTaYkNU68jxrsgUIRkXCGKUj_Nlj82HRpPuvqEn9A,11509
|
|
7
|
+
mcp_query_table/utils.py,sha256=MUKcklPF9TkABhM8wN0-kW0iy9AlmjL6oycZyxB_Qk8,722
|
|
8
|
+
mcp_query_table/providers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
9
|
+
mcp_query_table/providers/baidu.py,sha256=S75D2zbpqG1r4Rxz7pJf5u2ZHNLO8nqV-LPEjlACtHg,3390
|
|
10
|
+
mcp_query_table/providers/n.py,sha256=SLalpwHSdkXNoMCLQEx1TEFlo50dS7I9JNli5jz8w6k,3202
|
|
11
|
+
mcp_query_table/providers/yuanbao.py,sha256=1wRMy7Z2JraM3MrgLDSdyg-EqX-D26ysx7CW1GFtVho,3292
|
|
12
|
+
mcp_query_table/sites/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
13
|
+
mcp_query_table/sites/eastmoney.py,sha256=wuM1rJkuQKrtL0a6ZyslMohPtucSgrs_jjaZWdkxhZo,4593
|
|
14
|
+
mcp_query_table/sites/iwencai.py,sha256=oCxNuGxiYcaMREHGpNoqspmCLlXSkvTFw2_EsmJSzlw,5174
|
|
15
|
+
mcp_query_table/sites/tdx.py,sha256=-u-rzhmYPW1m3zUFQsd-RUztafC43gQPhtmB6OuqA4M,4184
|
|
16
|
+
mcp_query_table-0.3.10.dist-info/METADATA,sha256=-93cA3U5J968vFZAhveZYx52hrjh5mms5iDFRxmGl_Y,9354
|
|
17
|
+
mcp_query_table-0.3.10.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
18
|
+
mcp_query_table-0.3.10.dist-info/licenses/LICENSE,sha256=rbvv_CTd7biGwT21tvhgQ2zkbPFXOoON7WFQWEdElBA,1063
|
|
19
|
+
mcp_query_table-0.3.10.dist-info/RECORD,,
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
mcp_query_table/__init__.py,sha256=K-0DU2hpeRvM9ZAuky0aWZtJLuOgKg7ZRd-pL9noc0o,330
|
|
2
|
-
mcp_query_table/__main__.py,sha256=oePptyDeLtOHcR0XZxx-O12hO6LSe6cplb4gaJBG4rI,1453
|
|
3
|
-
mcp_query_table/_version.py,sha256=7dTW0A5-FkrEuNOotvR8oW59M2lvIwYouVqfJzvXpKk,22
|
|
4
|
-
mcp_query_table/enums.py,sha256=7bu0m0zJBIfiS-eHGURw1ZHWNXgsq6gH1SztUhCgF-Y,678
|
|
5
|
-
mcp_query_table/server.py,sha256=D2-7ZmutijphasbLMosg9P5EOhJTB4RvC9-zmvCvc5k,3749
|
|
6
|
-
mcp_query_table/tool.py,sha256=PpsDFwaKQ9NsfqSMCvWm1p0MSyxT1Uwpve198TOP8FQ,11157
|
|
7
|
-
mcp_query_table/utils.py,sha256=VjKYLRPEa-W3qAOaNSJa9GnezrAAYykn4XY-R4P5NJg,1264
|
|
8
|
-
mcp_query_table/providers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
9
|
-
mcp_query_table/providers/baidu.py,sha256=S75D2zbpqG1r4Rxz7pJf5u2ZHNLO8nqV-LPEjlACtHg,3390
|
|
10
|
-
mcp_query_table/providers/n.py,sha256=SLalpwHSdkXNoMCLQEx1TEFlo50dS7I9JNli5jz8w6k,3202
|
|
11
|
-
mcp_query_table/providers/yuanbao.py,sha256=1wRMy7Z2JraM3MrgLDSdyg-EqX-D26ysx7CW1GFtVho,3292
|
|
12
|
-
mcp_query_table/sites/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
13
|
-
mcp_query_table/sites/eastmoney.py,sha256=LImjpYVuM5YnXwnNzB2hkKfHofocZZScetGqMOCHZpk,4477
|
|
14
|
-
mcp_query_table/sites/iwencai.py,sha256=43sBrVCXgiIybv25lEwTS6dlR2jXXceSBVGCOb03woE,5194
|
|
15
|
-
mcp_query_table/sites/tdx.py,sha256=P-GNFUsS5_INy3sicaZbUBdudgQBZuhu_QyVvyw4yDg,4126
|
|
16
|
-
mcp_query_table-0.3.8.dist-info/METADATA,sha256=4nnj_OrLYG0SMPlvSn9TpNI5IOx1DNsTfsWt22sVdqs,9372
|
|
17
|
-
mcp_query_table-0.3.8.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
18
|
-
mcp_query_table-0.3.8.dist-info/licenses/LICENSE,sha256=rbvv_CTd7biGwT21tvhgQ2zkbPFXOoON7WFQWEdElBA,1063
|
|
19
|
-
mcp_query_table-0.3.8.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|