Name | mercapi-shops JSON |
Version |
0.0.2
JSON |
| download |
home_page | None |
Summary | Unofficial Mercari-Shops (mercari-shops.com) async client |
upload_time | 2025-07-30 09:42:22 |
maintainer | None |
docs_url | None |
author | EricMeteorite |
requires_python | >=3.9 |
license | MIT License
Copyright (c) 2025 EricMeteorite
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
keywords |
mercari
mercari-shops
graphql
async
httpx
|
VCS |
 |
bugtrack_url |
|
requirements |
No requirements were recorded.
|
Travis-CI |
No Travis.
|
coveralls test coverage |
No coveralls.
|
# mercapi-shops


Async client for **mercari-shops.com** (enterprise sellers on Mercari).
非官方 Mercari Shops(企业商户)GraphQL 异步客户端。
- Python 3.9+
- 基于 `httpx` 异步请求
- 类型完备(PEP 561,内置 `py.typed`)
> ✅ 面向企业商家(mercari-shops.com)的**异步** Python API。
>
> ✅ 提供 GraphQL `search()`(可分页,全量)与店铺总页首屏抓取 `landing()`(低延迟)两种能力。
>
> ✅ 已在生产脚本中验证:支持按店铺 + 关键词抓取、分页、可选在库筛选、客户端价格排序。
>
> ✅ 需要时可传入站点 cookies(如 `__cf_bm`, `_cfuvid`)。
---
## Installation
**From source (editable):**
```bash
#Local installation
pip install -U pip build
pip install -e .
```
**From PyPi:**
```bash
#pip installation
pip install mercapi-shops
```
## Quick Start
```bash
import asyncio
from mercapi_shops import MercapiShops
SHOP_ID = "d2uUKgmbjTGT7BzBGUnXxe" # 示例:MANDARAKE
async def main():
async with MercapiShops() as api:
# 1) GraphQL 搜索(可分页、全量)
res = await api.search(
"アゾン",
shop_id=SHOP_ID,
in_stock=True, # 仅在库(本地过滤)
order_by="PRICE_ASC", # 价格升序(本地兜底排序)
# local_keyword="..." # 可选:二次本地过滤(NFKC+lower,空白分词 AND)
)
print("First page:", len(res.items))
for p in res.items[:5]:
print(p.id, p.name, p.price, p.inStock, p.assets[0].imageUrl if p.assets else None)
if res.pageInfo.hasNextPage:
res2 = await res.next_page()
print("Next page:", len(res2.items))
# 2) 店铺总页首屏(低延迟,更快发现“新上架”,但非全量)
latest = await api.landing(
shop_id=SHOP_ID,
in_stock=None, # True / False / None
keyword="アゾン", # 本地关键词过滤(NFKC+lower,空白分词 AND)
limit=120
)
print("Landing size:", len(latest))
for p in latest[:5]:
print(p.id, p.name, p.price, p.inStock, p.assets[0].imageUrl if p.assets else None)
asyncio.run(main())
```
## 功能特性
**GraphQL search()**
> - 支持分页(pageInfo.hasNextPage / await results.next_page())。
>
> - 支持本地在库过滤 in_stock=True/False/None。
>
> - 支持价格本地排序兜底:PRICE_ASC / PRICE_DESC(CREATED_AT 依赖后端,不做本地兜底)。
>
> - 可选 local_keyword 二次本地过滤,不影响后端请求。
**landing() 店铺总页首屏抓取**
> - 通常更快出现最新上架商品(低延迟)。
>
> - 仅抓取店铺总页首屏,不分页,非全量。
>
> - 支持 in_stock 本地过滤与 keyword 本地关键词过滤。
**图片 URL 归一化**
> - 自动解析/展开 /_next/image?url=...、相对地址等,输出可直连的绝对 URL,方便下载与消息推送。
**类型完备**
> - 内置 py.typed,对 ShopProduct / ShopProductAsset / ShopSearchResults / PageInfo 等提供静态类型。
## 版本变更
**v0.0.2**
- 新增:landing(shop_id, in_stock, keyword, limit),快速抓取店铺总页首屏;
- 新增:search(..., local_keyword=...) 二次本地过滤;
- 改进:图片 URL 归一化(解析 /_next/image?url=... 与相对链接 → 绝对直链);
- 改进:更健壮地解析 Next.js / Apollo 存储与 __ref,提升首屏解析成功率;
- 完善类型与文档。
## 许可协议
**MIT License**
## 免责声明
>本项目为非官方客户端,仅用于技术研究与个人工具整合,请勿用于任何商业用途。
>
>请遵守目标站点的服务条款与法律法规,自行承担使用风险。
Raw data
{
"_id": null,
"home_page": null,
"name": "mercapi-shops",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.9",
"maintainer_email": null,
"keywords": "mercari, mercari-shops, graphql, async, httpx",
"author": "EricMeteorite",
"author_email": null,
"download_url": "https://files.pythonhosted.org/packages/8e/38/9c312bc14e12cdf6b4150823170b4b7152c44b35626875ccc7bd2554498c/mercapi_shops-0.0.2.tar.gz",
"platform": null,
"description": "# mercapi-shops\r\n\r\n\r\n\r\n\r\nAsync client for **mercari-shops.com** (enterprise sellers on Mercari). \r\n\u975e\u5b98\u65b9 Mercari Shops\uff08\u4f01\u4e1a\u5546\u6237\uff09GraphQL \u5f02\u6b65\u5ba2\u6237\u7aef\u3002\r\n\r\n- Python 3.9+\r\n- \u57fa\u4e8e `httpx` \u5f02\u6b65\u8bf7\u6c42\r\n- \u7c7b\u578b\u5b8c\u5907\uff08PEP 561\uff0c\u5185\u7f6e `py.typed`\uff09\r\n\r\n> \u2705 \u9762\u5411\u4f01\u4e1a\u5546\u5bb6\uff08mercari-shops.com\uff09\u7684**\u5f02\u6b65** Python API\u3002 \r\n> \r\n> \u2705 \u63d0\u4f9b GraphQL `search()`\uff08\u53ef\u5206\u9875\uff0c\u5168\u91cf\uff09\u4e0e\u5e97\u94fa\u603b\u9875\u9996\u5c4f\u6293\u53d6 `landing()`\uff08\u4f4e\u5ef6\u8fdf\uff09\u4e24\u79cd\u80fd\u529b\u3002\r\n> \r\n> \u2705 \u5df2\u5728\u751f\u4ea7\u811a\u672c\u4e2d\u9a8c\u8bc1\uff1a\u652f\u6301\u6309\u5e97\u94fa + \u5173\u952e\u8bcd\u6293\u53d6\u3001\u5206\u9875\u3001\u53ef\u9009\u5728\u5e93\u7b5b\u9009\u3001\u5ba2\u6237\u7aef\u4ef7\u683c\u6392\u5e8f\u3002 \r\n> \r\n> \u2705 \u9700\u8981\u65f6\u53ef\u4f20\u5165\u7ad9\u70b9 cookies\uff08\u5982 `__cf_bm`, `_cfuvid`\uff09\u3002\r\n\r\n---\r\n\r\n## Installation\r\n\r\n**From source (editable):**\r\n```bash\r\n#Local installation\r\npip install -U pip build\r\npip install -e .\r\n```\r\n**From PyPi:**\r\n```bash\r\n#pip installation\r\npip install mercapi-shops\r\n```\r\n## Quick Start\r\n```bash\r\nimport asyncio\r\nfrom mercapi_shops import MercapiShops\r\n\r\nSHOP_ID = \"d2uUKgmbjTGT7BzBGUnXxe\" # \u793a\u4f8b\uff1aMANDARAKE\r\n\r\nasync def main():\r\n async with MercapiShops() as api:\r\n # 1) GraphQL \u641c\u7d22\uff08\u53ef\u5206\u9875\u3001\u5168\u91cf\uff09\r\n res = await api.search(\r\n \"\u30a2\u30be\u30f3\",\r\n shop_id=SHOP_ID,\r\n in_stock=True, # \u4ec5\u5728\u5e93\uff08\u672c\u5730\u8fc7\u6ee4\uff09\r\n order_by=\"PRICE_ASC\", # \u4ef7\u683c\u5347\u5e8f\uff08\u672c\u5730\u515c\u5e95\u6392\u5e8f\uff09\r\n # local_keyword=\"...\" # \u53ef\u9009\uff1a\u4e8c\u6b21\u672c\u5730\u8fc7\u6ee4\uff08NFKC+lower\uff0c\u7a7a\u767d\u5206\u8bcd AND\uff09\r\n )\r\n print(\"First page:\", len(res.items))\r\n for p in res.items[:5]:\r\n print(p.id, p.name, p.price, p.inStock, p.assets[0].imageUrl if p.assets else None)\r\n\r\n if res.pageInfo.hasNextPage:\r\n res2 = await res.next_page()\r\n print(\"Next page:\", len(res2.items))\r\n\r\n # 2) \u5e97\u94fa\u603b\u9875\u9996\u5c4f\uff08\u4f4e\u5ef6\u8fdf\uff0c\u66f4\u5feb\u53d1\u73b0\u201c\u65b0\u4e0a\u67b6\u201d\uff0c\u4f46\u975e\u5168\u91cf\uff09\r\n latest = await api.landing(\r\n shop_id=SHOP_ID,\r\n in_stock=None, # True / False / None\r\n keyword=\"\u30a2\u30be\u30f3\", # \u672c\u5730\u5173\u952e\u8bcd\u8fc7\u6ee4\uff08NFKC+lower\uff0c\u7a7a\u767d\u5206\u8bcd AND\uff09\r\n limit=120\r\n )\r\n print(\"Landing size:\", len(latest))\r\n for p in latest[:5]:\r\n print(p.id, p.name, p.price, p.inStock, p.assets[0].imageUrl if p.assets else None)\r\n\r\nasyncio.run(main())\r\n\r\n\r\n```\r\n\r\n## \u529f\u80fd\u7279\u6027\r\n**GraphQL search()**\r\n\r\n> - \u652f\u6301\u5206\u9875\uff08pageInfo.hasNextPage / await results.next_page()\uff09\u3002\r\n> \r\n> - \u652f\u6301\u672c\u5730\u5728\u5e93\u8fc7\u6ee4 in_stock=True/False/None\u3002\r\n> \r\n> - \u652f\u6301\u4ef7\u683c\u672c\u5730\u6392\u5e8f\u515c\u5e95\uff1aPRICE_ASC / PRICE_DESC\uff08CREATED_AT \u4f9d\u8d56\u540e\u7aef\uff0c\u4e0d\u505a\u672c\u5730\u515c\u5e95\uff09\u3002\r\n> \r\n> - \u53ef\u9009 local_keyword \u4e8c\u6b21\u672c\u5730\u8fc7\u6ee4\uff0c\u4e0d\u5f71\u54cd\u540e\u7aef\u8bf7\u6c42\u3002\r\n\r\n**landing() \u5e97\u94fa\u603b\u9875\u9996\u5c4f\u6293\u53d6**\r\n\r\n> - \u901a\u5e38\u66f4\u5feb\u51fa\u73b0\u6700\u65b0\u4e0a\u67b6\u5546\u54c1\uff08\u4f4e\u5ef6\u8fdf\uff09\u3002\r\n> \r\n> - \u4ec5\u6293\u53d6\u5e97\u94fa\u603b\u9875\u9996\u5c4f\uff0c\u4e0d\u5206\u9875\uff0c\u975e\u5168\u91cf\u3002\r\n> \r\n> - \u652f\u6301 in_stock \u672c\u5730\u8fc7\u6ee4\u4e0e keyword \u672c\u5730\u5173\u952e\u8bcd\u8fc7\u6ee4\u3002\r\n\r\n**\u56fe\u7247 URL \u5f52\u4e00\u5316**\r\n\r\n> - \u81ea\u52a8\u89e3\u6790/\u5c55\u5f00 /_next/image?url=...\u3001\u76f8\u5bf9\u5730\u5740\u7b49\uff0c\u8f93\u51fa\u53ef\u76f4\u8fde\u7684\u7edd\u5bf9 URL\uff0c\u65b9\u4fbf\u4e0b\u8f7d\u4e0e\u6d88\u606f\u63a8\u9001\u3002\r\n\r\n**\u7c7b\u578b\u5b8c\u5907**\r\n\r\n> - \u5185\u7f6e py.typed\uff0c\u5bf9 ShopProduct / ShopProductAsset / ShopSearchResults / PageInfo \u7b49\u63d0\u4f9b\u9759\u6001\u7c7b\u578b\u3002\r\n\r\n\r\n## \u7248\u672c\u53d8\u66f4\r\n**v0.0.2**\r\n- \u65b0\u589e\uff1alanding(shop_id, in_stock, keyword, limit)\uff0c\u5feb\u901f\u6293\u53d6\u5e97\u94fa\u603b\u9875\u9996\u5c4f\uff1b\r\n- \u65b0\u589e\uff1asearch(..., local_keyword=...) \u4e8c\u6b21\u672c\u5730\u8fc7\u6ee4\uff1b\r\n- \u6539\u8fdb\uff1a\u56fe\u7247 URL \u5f52\u4e00\u5316\uff08\u89e3\u6790 /_next/image?url=... \u4e0e\u76f8\u5bf9\u94fe\u63a5 \u2192 \u7edd\u5bf9\u76f4\u94fe\uff09\uff1b\r\n- \u6539\u8fdb\uff1a\u66f4\u5065\u58ee\u5730\u89e3\u6790 Next.js / Apollo \u5b58\u50a8\u4e0e __ref\uff0c\u63d0\u5347\u9996\u5c4f\u89e3\u6790\u6210\u529f\u7387\uff1b\r\n- \u5b8c\u5584\u7c7b\u578b\u4e0e\u6587\u6863\u3002\r\n\r\n\r\n## \u8bb8\u53ef\u534f\u8bae\r\n**MIT License**\r\n\r\n## \u514d\u8d23\u58f0\u660e\r\n\r\n>\u672c\u9879\u76ee\u4e3a\u975e\u5b98\u65b9\u5ba2\u6237\u7aef\uff0c\u4ec5\u7528\u4e8e\u6280\u672f\u7814\u7a76\u4e0e\u4e2a\u4eba\u5de5\u5177\u6574\u5408\uff0c\u8bf7\u52ff\u7528\u4e8e\u4efb\u4f55\u5546\u4e1a\u7528\u9014\u3002\r\n> \r\n>\u8bf7\u9075\u5b88\u76ee\u6807\u7ad9\u70b9\u7684\u670d\u52a1\u6761\u6b3e\u4e0e\u6cd5\u5f8b\u6cd5\u89c4\uff0c\u81ea\u884c\u627f\u62c5\u4f7f\u7528\u98ce\u9669\u3002\r\n",
"bugtrack_url": null,
"license": "MIT License\r\n \r\n Copyright (c) 2025 EricMeteorite\r\n \r\n Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \u201cSoftware\u201d), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\r\n \r\n The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\r\n \r\n THE SOFTWARE IS PROVIDED \u201cAS IS\u201d, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r\n \r\n ",
"summary": "Unofficial Mercari-Shops (mercari-shops.com) async client",
"version": "0.0.2",
"project_urls": {
"Homepage": "https://github.com/EricMeteorite",
"Issues": "https://github.com/EricMeteorite/mercapi_shops/issues",
"Repository": "https://github.com/EricMeteorite/mercapi_shops"
},
"split_keywords": [
"mercari",
" mercari-shops",
" graphql",
" async",
" httpx"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "9e108d616c32c2e6ba6772d59b552f5828082885a17f1f87c10673d472defb6e",
"md5": "c5fd9985ab572c892f01deb9f2dfd544",
"sha256": "109c3619917e1f0781f37b758bf4c6a9648d30b4bbd0ecdb671e9f40217bafe8"
},
"downloads": -1,
"filename": "mercapi_shops-0.0.2-py3-none-any.whl",
"has_sig": false,
"md5_digest": "c5fd9985ab572c892f01deb9f2dfd544",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.9",
"size": 13905,
"upload_time": "2025-07-30T09:42:20",
"upload_time_iso_8601": "2025-07-30T09:42:20.814660Z",
"url": "https://files.pythonhosted.org/packages/9e/10/8d616c32c2e6ba6772d59b552f5828082885a17f1f87c10673d472defb6e/mercapi_shops-0.0.2-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "8e389c312bc14e12cdf6b4150823170b4b7152c44b35626875ccc7bd2554498c",
"md5": "479e76114feec078b72de55faa6aeb61",
"sha256": "59e20464df523e4f0c1f01515adee8a385d7a6b51e5f543ece81fb80045d6413"
},
"downloads": -1,
"filename": "mercapi_shops-0.0.2.tar.gz",
"has_sig": false,
"md5_digest": "479e76114feec078b72de55faa6aeb61",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.9",
"size": 14411,
"upload_time": "2025-07-30T09:42:22",
"upload_time_iso_8601": "2025-07-30T09:42:22.760940Z",
"url": "https://files.pythonhosted.org/packages/8e/38/9c312bc14e12cdf6b4150823170b4b7152c44b35626875ccc7bd2554498c/mercapi_shops-0.0.2.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-07-30 09:42:22",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "EricMeteorite",
"github_project": "mercapi_shops",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"lcname": "mercapi-shops"
}