mcp-query-table 0.3.9__py3-none-any.whl → 0.3.11__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 +2 -2
- mcp_query_table/_version.py +1 -1
- mcp_query_table/server.py +4 -3
- mcp_query_table/sites/eastmoney.py +8 -4
- mcp_query_table/sites/iwencai.py +8 -4
- mcp_query_table/sites/tdx.py +4 -3
- mcp_query_table/tool.py +14 -6
- {mcp_query_table-0.3.9.dist-info → mcp_query_table-0.3.11.dist-info}/METADATA +15 -3
- mcp_query_table-0.3.11.dist-info/RECORD +19 -0
- mcp_query_table-0.3.9.dist-info/RECORD +0 -19
- {mcp_query_table-0.3.9.dist-info → mcp_query_table-0.3.11.dist-info}/WHEEL +0 -0
- {mcp_query_table-0.3.9.dist-info → mcp_query_table-0.3.11.dist-info}/licenses/LICENSE +0 -0
mcp_query_table/__main__.py
CHANGED
|
@@ -17,9 +17,9 @@ 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')
|
|
21
21
|
parser.add_argument("--transport", type=str, help="传输类型",
|
|
22
|
-
default='stdio', choices=['stdio', 'sse'])
|
|
22
|
+
default='stdio', choices=['stdio', 'sse', 'streamable-http'])
|
|
23
23
|
parser.add_argument("--host", type=str, help="MCP服务端绑定地址",
|
|
24
24
|
default='0.0.0.0')
|
|
25
25
|
parser.add_argument("--port", type=int, help="MCP服务端绑定端口",
|
mcp_query_table/_version.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "0.3.
|
|
1
|
+
__version__ = "0.3.11"
|
mcp_query_table/server.py
CHANGED
|
@@ -22,9 +22,9 @@ class QueryServer:
|
|
|
22
22
|
devtools=False,
|
|
23
23
|
headless=True)
|
|
24
24
|
|
|
25
|
-
async def query(self, query_input: str, query_type: QueryType, max_page: int, site: Site):
|
|
25
|
+
async def query(self, query_input: str, query_type: QueryType, max_page: int, rename: bool, site: Site):
|
|
26
26
|
page = await self.browser.get_page()
|
|
27
|
-
df = await qt_query(page, query_input, query_type, max_page, site)
|
|
27
|
+
df = await qt_query(page, query_input, query_type, max_page, rename, site)
|
|
28
28
|
self.browser.release_page(page)
|
|
29
29
|
|
|
30
30
|
if self.format == 'csv':
|
|
@@ -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
|
@@ -80,7 +80,7 @@ class Pagination:
|
|
|
80
80
|
datas.extend(v)
|
|
81
81
|
return datas
|
|
82
82
|
|
|
83
|
-
def get_dataframe(self):
|
|
83
|
+
def get_dataframe(self, rename: bool):
|
|
84
84
|
columns = {x['key']: x['index_name'] for x in self.columns}
|
|
85
85
|
dtypes = {x['key']: convert_type(x['type']) for x in self.columns}
|
|
86
86
|
|
|
@@ -94,7 +94,10 @@ class Pagination:
|
|
|
94
94
|
except ValueError:
|
|
95
95
|
logger.info("转换失败 {}:{}", k, v)
|
|
96
96
|
|
|
97
|
-
|
|
97
|
+
if rename:
|
|
98
|
+
return df.rename(columns=columns)
|
|
99
|
+
else:
|
|
100
|
+
return df
|
|
98
101
|
|
|
99
102
|
|
|
100
103
|
P = Pagination()
|
|
@@ -148,7 +151,8 @@ async def on_response(response):
|
|
|
148
151
|
async def query(page: Page,
|
|
149
152
|
w: str = "收盘价>1000元",
|
|
150
153
|
type_: QueryType = 'stock',
|
|
151
|
-
max_page: int = 5
|
|
154
|
+
max_page: int = 5,
|
|
155
|
+
rename: bool = False) -> pd.DataFrame:
|
|
152
156
|
querytype = _querytype_.get(type_, None)
|
|
153
157
|
assert querytype is not None, f"不支持的类型:{type_}"
|
|
154
158
|
|
|
@@ -168,4 +172,4 @@ async def query(page: Page,
|
|
|
168
172
|
await page.get_by_text("下页").click()
|
|
169
173
|
await on_response(await response_info.value)
|
|
170
174
|
|
|
171
|
-
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
|
@@ -66,8 +66,8 @@ def get_user_data_dir(user_data_dir) -> Optional[str]:
|
|
|
66
66
|
"""获取浏览器可用户目录"""
|
|
67
67
|
browsers = {
|
|
68
68
|
"default": user_data_dir,
|
|
69
|
-
"chrome.exe": rf'C:\Users\{getpass.getuser()}\AppData\Local\Google\Chrome\User Data
|
|
70
|
-
"msedge.exe": rf"C:\Users\{getpass.getuser()}\AppData\Local\Microsoft\Edge\User Data
|
|
69
|
+
"chrome.exe": rf'C:\Users\{getpass.getuser()}\AppData\Local\Google\Chrome\User Data', # 使用默认配置文件时无法创建CDP
|
|
70
|
+
"msedge.exe": rf"C:\Users\{getpass.getuser()}\AppData\Local\Microsoft\Edge\User Data",
|
|
71
71
|
}
|
|
72
72
|
for k, v in browsers.items():
|
|
73
73
|
if v is None:
|
|
@@ -136,6 +136,10 @@ class BrowserManager:
|
|
|
136
136
|
command = [executable_path, f'--remote-debugging-port={port}', '--start-maximized']
|
|
137
137
|
if self.devtools:
|
|
138
138
|
command.append('--auto-open-devtools-for-tabs')
|
|
139
|
+
if self.user_data_dir:
|
|
140
|
+
command.append(f'--user-data-dir={self.user_data_dir}')
|
|
141
|
+
else:
|
|
142
|
+
logger.warning('Chrome必须另行指定`--user-data-dir`才能创建CDP连接')
|
|
139
143
|
|
|
140
144
|
for i in range(2):
|
|
141
145
|
try:
|
|
@@ -249,7 +253,9 @@ async def query(
|
|
|
249
253
|
query_input: str = "收盘价>100元",
|
|
250
254
|
query_type: QueryType = QueryType.CNStock,
|
|
251
255
|
max_page: int = 5,
|
|
252
|
-
|
|
256
|
+
rename: bool = False,
|
|
257
|
+
site: Site = Site.THS,
|
|
258
|
+
) -> pd.DataFrame:
|
|
253
259
|
"""查询表格
|
|
254
260
|
|
|
255
261
|
Parameters
|
|
@@ -262,6 +268,8 @@ async def query(
|
|
|
262
268
|
查询类型, by default QueryType.astock
|
|
263
269
|
max_page : int, optional
|
|
264
270
|
最大页数, by default 5
|
|
271
|
+
rename: bool
|
|
272
|
+
是否重命名列名, by default False
|
|
265
273
|
site : Site, optional
|
|
266
274
|
站点, by default Site.iwencai
|
|
267
275
|
|
|
@@ -275,13 +283,13 @@ async def query(
|
|
|
275
283
|
|
|
276
284
|
if site == Site.EastMoney:
|
|
277
285
|
from mcp_query_table.sites.eastmoney import query
|
|
278
|
-
return await query(page, query_input, query_type, max_page)
|
|
286
|
+
return await query(page, query_input, query_type, max_page, rename)
|
|
279
287
|
if site == Site.THS:
|
|
280
288
|
from mcp_query_table.sites.iwencai import query
|
|
281
|
-
return await query(page, query_input, query_type, max_page)
|
|
289
|
+
return await query(page, query_input, query_type, max_page, rename)
|
|
282
290
|
if site == Site.TDX:
|
|
283
291
|
from mcp_query_table.sites.tdx import query
|
|
284
|
-
return await query(page, query_input, query_type, max_page)
|
|
292
|
+
return await query(page, query_input, query_type, max_page, rename)
|
|
285
293
|
|
|
286
294
|
raise ValueError(f"未支持的站点:{site}")
|
|
287
295
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mcp_query_table
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.11
|
|
4
4
|
Summary: query table from website, support MCP
|
|
5
5
|
Author-email: wukan <wu-kan@163.com>
|
|
6
6
|
License: MIT License
|
|
@@ -137,6 +137,8 @@ if __name__ == '__main__':
|
|
|
137
137
|
- `endpoint`以`ws://`开头,连接远程`Playwright Server`。也是无头模式,但无法指定`user_data_dir`,所以使用受限
|
|
138
138
|
- 参考:https://playwright.dev/python/docs/docker#running-the-playwright-server
|
|
139
139
|
|
|
140
|
+
`Chrome`新版的安全策略使用默认`user_data_dir`时将无法创建`CDP`服务,建议重新复制配置目录到其他地方
|
|
141
|
+
|
|
140
142
|
## MCP支持
|
|
141
143
|
|
|
142
144
|
确保可以在控制台中执行`python -m mcp_query_table -h`。如果不能,可能要先`pip install mcp_query_table`
|
|
@@ -172,7 +174,7 @@ if __name__ == '__main__':
|
|
|
172
174
|
先在控制台中执行如下命令,启动`MCP`服务
|
|
173
175
|
|
|
174
176
|
```commandline
|
|
175
|
-
python -m mcp_query_table --format markdown --transport sse --port 8000 --endpoint http://127.0.0.1:9222
|
|
177
|
+
python -m mcp_query_table --format markdown --transport sse --port 8000 --endpoint http://127.0.0.1:9222 --user_data_dir "D:\user-data-dir"
|
|
176
178
|
```
|
|
177
179
|
|
|
178
180
|
然后就可以连接到`MCP`服务了
|
|
@@ -188,6 +190,14 @@ python -m mcp_query_table --format markdown --transport sse --port 8000 --endpoi
|
|
|
188
190
|
}
|
|
189
191
|
```
|
|
190
192
|
|
|
193
|
+
### Streamable HTTP方式
|
|
194
|
+
|
|
195
|
+
```commandline
|
|
196
|
+
python -m mcp_query_table --format markdown --transport streamable-http --port 8000 --endpoint http://127.0.0.1:9222 --user_data_dir "D:\user-data-dir"
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
连接的地址是`http://127.0.0.1:8000/mcp`
|
|
200
|
+
|
|
191
201
|
## 使用`MCP Inspector`进行调试
|
|
192
202
|
|
|
193
203
|
```commandline
|
|
@@ -221,5 +231,7 @@ npx @modelcontextprotocol/inspector python -m mcp_query_table --format markdown
|
|
|
221
231
|

|
|
222
232
|
|
|
223
233
|
## 参考
|
|
234
|
+
|
|
224
235
|
- [Selenium webdriver无法附加到edge实例,edge的--remote-debugging-port选项无效](https://blog.csdn.net/qq_30576521/article/details/142370538)
|
|
225
|
-
- https://github.com/AtuboDad/playwright_stealth/issues/31
|
|
236
|
+
- https://github.com/AtuboDad/playwright_stealth/issues/31
|
|
237
|
+
- https://github.com/browser-use/browser-use/issues/1520
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
mcp_query_table/__init__.py,sha256=K-0DU2hpeRvM9ZAuky0aWZtJLuOgKg7ZRd-pL9noc0o,330
|
|
2
|
+
mcp_query_table/__main__.py,sha256=Hl70DkzAY1wJNnrirjiMRXHhemptXXy_1Q3sASMTWSk,1472
|
|
3
|
+
mcp_query_table/_version.py,sha256=TESjMH0a_iUkwdfWT4nyzKizSFmmCY2omxnS2XyT97Y,23
|
|
4
|
+
mcp_query_table/enums.py,sha256=7bu0m0zJBIfiS-eHGURw1ZHWNXgsq6gH1SztUhCgF-Y,678
|
|
5
|
+
mcp_query_table/server.py,sha256=re3UnNAe75IJAH8oyJZAzYAzp_rg3uH1vIroKJ7k69w,3871
|
|
6
|
+
mcp_query_table/tool.py,sha256=3wUZfvfA_4fNmc5sWi60gdGuqT5y7ZPKt-Nibw9NzY4,11737
|
|
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.11.dist-info/METADATA,sha256=s7yPOuqh4HbNpdz5CjRo5INmcSGwxm0neIr0XrM2quA,9830
|
|
17
|
+
mcp_query_table-0.3.11.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
18
|
+
mcp_query_table-0.3.11.dist-info/licenses/LICENSE,sha256=rbvv_CTd7biGwT21tvhgQ2zkbPFXOoON7WFQWEdElBA,1063
|
|
19
|
+
mcp_query_table-0.3.11.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=K0r7y8PD9y9pFg3bAQxNo21KlQpGz1jqGg_zptPfenM,1461
|
|
3
|
-
mcp_query_table/_version.py,sha256=xmkmdvq15kb61xdtCoa1YARnvHBnUgI-0GWIJYvHNeA,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=dW6Hcv7aB-hBotd7OBzCWQrpRck1h5812y6sRCUENVA,11380
|
|
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=LImjpYVuM5YnXwnNzB2hkKfHofocZZScetGqMOCHZpk,4477
|
|
14
|
-
mcp_query_table/sites/iwencai.py,sha256=FlIQOAN6wPz0B8w5DFX-EHekPO5HPIYdLMhiX1dYV7s,5057
|
|
15
|
-
mcp_query_table/sites/tdx.py,sha256=P-GNFUsS5_INy3sicaZbUBdudgQBZuhu_QyVvyw4yDg,4126
|
|
16
|
-
mcp_query_table-0.3.9.dist-info/METADATA,sha256=w6Kk_cokNDdnTgr7APF6IhlSVOHJTrDAO0uGdhTaNvA,9353
|
|
17
|
-
mcp_query_table-0.3.9.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
18
|
-
mcp_query_table-0.3.9.dist-info/licenses/LICENSE,sha256=rbvv_CTd7biGwT21tvhgQ2zkbPFXOoON7WFQWEdElBA,1063
|
|
19
|
-
mcp_query_table-0.3.9.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|