zhihu-toolkit 0.1.0__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.
Files changed (136) hide show
  1. zhihu_toolkit-0.1.0/.github/workflows/ci.yml +35 -0
  2. zhihu_toolkit-0.1.0/.github/workflows/publish.yml +34 -0
  3. zhihu_toolkit-0.1.0/.gitignore +15 -0
  4. zhihu_toolkit-0.1.0/.pre-commit-config.yaml +7 -0
  5. zhihu_toolkit-0.1.0/LICENSE +21 -0
  6. zhihu_toolkit-0.1.0/PKG-INFO +225 -0
  7. zhihu_toolkit-0.1.0/README.md +165 -0
  8. zhihu_toolkit-0.1.0/autocomp.py +142 -0
  9. zhihu_toolkit-0.1.0/pyproject.toml +103 -0
  10. zhihu_toolkit-0.1.0/setup.cfg +4 -0
  11. zhihu_toolkit-0.1.0/src/zhihu_cli/__init__.py +19 -0
  12. zhihu_toolkit-0.1.0/src/zhihu_cli/commands/__init__.py +25 -0
  13. zhihu_toolkit-0.1.0/src/zhihu_cli/commands/_helpers.py +212 -0
  14. zhihu_toolkit-0.1.0/src/zhihu_cli/commands/agora.py +636 -0
  15. zhihu_toolkit-0.1.0/src/zhihu_cli/commands/ai.py +334 -0
  16. zhihu_toolkit-0.1.0/src/zhihu_cli/commands/auth.py +291 -0
  17. zhihu_toolkit-0.1.0/src/zhihu_cli/commands/browse.py +1003 -0
  18. zhihu_toolkit-0.1.0/src/zhihu_cli/commands/chat.py +315 -0
  19. zhihu_toolkit-0.1.0/src/zhihu_cli/commands/config.py +283 -0
  20. zhihu_toolkit-0.1.0/src/zhihu_cli/commands/consult.py +394 -0
  21. zhihu_toolkit-0.1.0/src/zhihu_cli/commands/convert.py +143 -0
  22. zhihu_toolkit-0.1.0/src/zhihu_cli/commands/daemon.py +101 -0
  23. zhihu_toolkit-0.1.0/src/zhihu_cli/commands/download.py +424 -0
  24. zhihu_toolkit-0.1.0/src/zhihu_cli/commands/draft.py +313 -0
  25. zhihu_toolkit-0.1.0/src/zhihu_cli/commands/interact.py +517 -0
  26. zhihu_toolkit-0.1.0/src/zhihu_cli/commands/interact_comment_interactive.py +617 -0
  27. zhihu_toolkit-0.1.0/src/zhihu_cli/commands/listen.py +63 -0
  28. zhihu_toolkit-0.1.0/src/zhihu_cli/commands/people.py +369 -0
  29. zhihu_toolkit-0.1.0/src/zhihu_cli/commands/profile.py +126 -0
  30. zhihu_toolkit-0.1.0/src/zhihu_cli/commands/publish.py +108 -0
  31. zhihu_toolkit-0.1.0/src/zhihu_cli/commands/scrape.py +145 -0
  32. zhihu_toolkit-0.1.0/src/zhihu_cli/commands/search.py +118 -0
  33. zhihu_toolkit-0.1.0/src/zhihu_cli/commands/stats.py +81 -0
  34. zhihu_toolkit-0.1.0/src/zhihu_cli/commands/tools.py +660 -0
  35. zhihu_toolkit-0.1.0/src/zhihu_cli/content/__init__.py +22 -0
  36. zhihu_toolkit-0.1.0/src/zhihu_cli/content/download_contents.py +744 -0
  37. zhihu_toolkit-0.1.0/src/zhihu_cli/content/handlers/__init__.py +104 -0
  38. zhihu_toolkit-0.1.0/src/zhihu_cli/content/handlers/_session_core.py +271 -0
  39. zhihu_toolkit-0.1.0/src/zhihu_cli/content/handlers/agora.py +337 -0
  40. zhihu_toolkit-0.1.0/src/zhihu_cli/content/handlers/ai_direct.py +426 -0
  41. zhihu_toolkit-0.1.0/src/zhihu_cli/content/handlers/article.py +79 -0
  42. zhihu_toolkit-0.1.0/src/zhihu_cli/content/handlers/auth_login.py +312 -0
  43. zhihu_toolkit-0.1.0/src/zhihu_cli/content/handlers/cache_manager.py +332 -0
  44. zhihu_toolkit-0.1.0/src/zhihu_cli/content/handlers/captcha.py +216 -0
  45. zhihu_toolkit-0.1.0/src/zhihu_cli/content/handlers/chat.py +917 -0
  46. zhihu_toolkit-0.1.0/src/zhihu_cli/content/handlers/chat_commands.py +91 -0
  47. zhihu_toolkit-0.1.0/src/zhihu_cli/content/handlers/chat_commands_builtin.py +271 -0
  48. zhihu_toolkit-0.1.0/src/zhihu_cli/content/handlers/collection.py +141 -0
  49. zhihu_toolkit-0.1.0/src/zhihu_cli/content/handlers/comments.py +325 -0
  50. zhihu_toolkit-0.1.0/src/zhihu_cli/content/handlers/consult.py +316 -0
  51. zhihu_toolkit-0.1.0/src/zhihu_cli/content/handlers/draft.py +252 -0
  52. zhihu_toolkit-0.1.0/src/zhihu_cli/content/handlers/feed.py +198 -0
  53. zhihu_toolkit-0.1.0/src/zhihu_cli/content/handlers/following.py +225 -0
  54. zhihu_toolkit-0.1.0/src/zhihu_cli/content/handlers/hot.py +52 -0
  55. zhihu_toolkit-0.1.0/src/zhihu_cli/content/handlers/imchat.py +175 -0
  56. zhihu_toolkit-0.1.0/src/zhihu_cli/content/handlers/notifications.py +54 -0
  57. zhihu_toolkit-0.1.0/src/zhihu_cli/content/handlers/people.py +398 -0
  58. zhihu_toolkit-0.1.0/src/zhihu_cli/content/handlers/pin.py +59 -0
  59. zhihu_toolkit-0.1.0/src/zhihu_cli/content/handlers/publishing.py +266 -0
  60. zhihu_toolkit-0.1.0/src/zhihu_cli/content/handlers/question.py +231 -0
  61. zhihu_toolkit-0.1.0/src/zhihu_cli/content/handlers/question_log.py +200 -0
  62. zhihu_toolkit-0.1.0/src/zhihu_cli/content/handlers/read_history.py +53 -0
  63. zhihu_toolkit-0.1.0/src/zhihu_cli/content/handlers/report.py +94 -0
  64. zhihu_toolkit-0.1.0/src/zhihu_cli/content/handlers/request_tool.py +142 -0
  65. zhihu_toolkit-0.1.0/src/zhihu_cli/content/handlers/requests.py +215 -0
  66. zhihu_toolkit-0.1.0/src/zhihu_cli/content/handlers/search.py +212 -0
  67. zhihu_toolkit-0.1.0/src/zhihu_cli/content/handlers/segment_comments.py +91 -0
  68. zhihu_toolkit-0.1.0/src/zhihu_cli/content/handlers/stats.py +132 -0
  69. zhihu_toolkit-0.1.0/src/zhihu_cli/content/handlers/upload_image.py +152 -0
  70. zhihu_toolkit-0.1.0/src/zhihu_cli/content/handlers/upvoter.py +71 -0
  71. zhihu_toolkit-0.1.0/src/zhihu_cli/content/handlers/waterfall.py +118 -0
  72. zhihu_toolkit-0.1.0/src/zhihu_cli/content/handlers/yanxuan.py +388 -0
  73. zhihu_toolkit-0.1.0/src/zhihu_cli/content/handlers/zvideo.py +214 -0
  74. zhihu_toolkit-0.1.0/src/zhihu_cli/content/universal_converter.py +130 -0
  75. zhihu_toolkit-0.1.0/src/zhihu_cli/content/utils/__init__.py +6 -0
  76. zhihu_toolkit-0.1.0/src/zhihu_cli/content/utils/html2markdown.py +505 -0
  77. zhihu_toolkit-0.1.0/src/zhihu_cli/content/utils/markdown2html.py +41 -0
  78. zhihu_toolkit-0.1.0/src/zhihu_cli/content/utils/wait.py +33 -0
  79. zhihu_toolkit-0.1.0/src/zhihu_cli/content/utils/zse.py +618 -0
  80. zhihu_toolkit-0.1.0/src/zhihu_cli/creator_tools/__init__.py +0 -0
  81. zhihu_toolkit-0.1.0/src/zhihu_cli/creator_tools/_smoothing.py +39 -0
  82. zhihu_toolkit-0.1.0/src/zhihu_cli/creator_tools/analyze_monthly_income.py +156 -0
  83. zhihu_toolkit-0.1.0/src/zhihu_cli/creator_tools/derivative_analysis.py +77 -0
  84. zhihu_toolkit-0.1.0/src/zhihu_cli/creator_tools/growth_level.py +114 -0
  85. zhihu_toolkit-0.1.0/src/zhihu_cli/creator_tools/parse_content_datas.py +286 -0
  86. zhihu_toolkit-0.1.0/src/zhihu_cli/creator_tools/parse_daily_metrics.py +131 -0
  87. zhihu_toolkit-0.1.0/src/zhihu_cli/creator_tools/parse_follower_detail.py +82 -0
  88. zhihu_toolkit-0.1.0/src/zhihu_cli/creator_tools/parse_follower_profile.py +129 -0
  89. zhihu_toolkit-0.1.0/src/zhihu_cli/creator_tools/parse_income_range.py +205 -0
  90. zhihu_toolkit-0.1.0/src/zhihu_cli/creator_tools/parse_score_detail.py +159 -0
  91. zhihu_toolkit-0.1.0/src/zhihu_cli/creator_tools/parse_zhihu_incomes.py +125 -0
  92. zhihu_toolkit-0.1.0/src/zhihu_cli/creator_tools/plot_content_metrics.py +520 -0
  93. zhihu_toolkit-0.1.0/src/zhihu_cli/creator_tools/plot_follower_detail.py +150 -0
  94. zhihu_toolkit-0.1.0/src/zhihu_cli/creator_tools/plot_zhihu_incomes.py +83 -0
  95. zhihu_toolkit-0.1.0/src/zhihu_cli/creator_tools/plot_zhihu_incomes_advanced.py +103 -0
  96. zhihu_toolkit-0.1.0/src/zhihu_cli/creator_tools/salt.py +252 -0
  97. zhihu_toolkit-0.1.0/src/zhihu_cli/creator_tools/stats_content_metrics.py +771 -0
  98. zhihu_toolkit-0.1.0/src/zhihu_cli/creator_tools/weekday_income_analysis.py +73 -0
  99. zhihu_toolkit-0.1.0/src/zhihu_cli/daemon/__init__.py +27 -0
  100. zhihu_toolkit-0.1.0/src/zhihu_cli/daemon/lifecycle.py +273 -0
  101. zhihu_toolkit-0.1.0/src/zhihu_cli/daemon/protocol.py +248 -0
  102. zhihu_toolkit-0.1.0/src/zhihu_cli/daemon/proxy.py +637 -0
  103. zhihu_toolkit-0.1.0/src/zhihu_cli/daemon/server.py +526 -0
  104. zhihu_toolkit-0.1.0/src/zhihu_cli/extensions/__init__.py +46 -0
  105. zhihu_toolkit-0.1.0/src/zhihu_cli/extensions/crank/__init__.py +21 -0
  106. zhihu_toolkit-0.1.0/src/zhihu_cli/extensions/crank/archiver.py +589 -0
  107. zhihu_toolkit-0.1.0/src/zhihu_cli/extensions/crank/classifier/__init__.py +14 -0
  108. zhihu_toolkit-0.1.0/src/zhihu_cli/extensions/crank/classifier/config.py +88 -0
  109. zhihu_toolkit-0.1.0/src/zhihu_cli/extensions/crank/classifier/data_loader.py +50 -0
  110. zhihu_toolkit-0.1.0/src/zhihu_cli/extensions/crank/classifier/dataset.py +190 -0
  111. zhihu_toolkit-0.1.0/src/zhihu_cli/extensions/crank/classifier/discovery.py +145 -0
  112. zhihu_toolkit-0.1.0/src/zhihu_cli/extensions/crank/classifier/model.py +175 -0
  113. zhihu_toolkit-0.1.0/src/zhihu_cli/extensions/crank/classifier/text_cleaner.py +81 -0
  114. zhihu_toolkit-0.1.0/src/zhihu_cli/extensions/crank/classifier/train.py +226 -0
  115. zhihu_toolkit-0.1.0/src/zhihu_cli/extensions/crank/monitor.py +1063 -0
  116. zhihu_toolkit-0.1.0/src/zhihu_cli/main.py +67 -0
  117. zhihu_toolkit-0.1.0/src/zhihu_cli/nlp_tools/__init__.py +17 -0
  118. zhihu_toolkit-0.1.0/src/zhihu_cli/nlp_tools/cluster_visualizer.py +275 -0
  119. zhihu_toolkit-0.1.0/src/zhihu_cli/nlp_tools/cooccurrence_network.py +236 -0
  120. zhihu_toolkit-0.1.0/src/zhihu_cli/nlp_tools/count_answer_words.py +138 -0
  121. zhihu_toolkit-0.1.0/src/zhihu_cli/nlp_tools/graph.py +750 -0
  122. zhihu_toolkit-0.1.0/src/zhihu_cli/nlp_tools/stop_words.txt +83 -0
  123. zhihu_toolkit-0.1.0/src/zhihu_cli/nlp_tools/wordcloud_generator.py +139 -0
  124. zhihu_toolkit-0.1.0/src/zhihu_cli/output.py +266 -0
  125. zhihu_toolkit-0.1.0/src/zhihu_cli/prompts/__init__.py +44 -0
  126. zhihu_toolkit-0.1.0/src/zhihu_cli/prompts/agora_vote.txt +12 -0
  127. zhihu_toolkit-0.1.0/src/zhihu_cli/prompts/commit_message.txt +1 -0
  128. zhihu_toolkit-0.1.0/src/zhihu_cli/prompts/series_naming.txt +1 -0
  129. zhihu_toolkit-0.1.0/src/zhihu_toolkit.egg-info/PKG-INFO +225 -0
  130. zhihu_toolkit-0.1.0/src/zhihu_toolkit.egg-info/SOURCES.txt +134 -0
  131. zhihu_toolkit-0.1.0/src/zhihu_toolkit.egg-info/dependency_links.txt +1 -0
  132. zhihu_toolkit-0.1.0/src/zhihu_toolkit.egg-info/entry_points.txt +2 -0
  133. zhihu_toolkit-0.1.0/src/zhihu_toolkit.egg-info/requires.txt +38 -0
  134. zhihu_toolkit-0.1.0/src/zhihu_toolkit.egg-info/scm_file_list.json +130 -0
  135. zhihu_toolkit-0.1.0/src/zhihu_toolkit.egg-info/scm_version.json +8 -0
  136. zhihu_toolkit-0.1.0/src/zhihu_toolkit.egg-info/top_level.txt +1 -0
@@ -0,0 +1,35 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ jobs:
9
+ lint:
10
+ runs-on: ubuntu-latest
11
+ steps:
12
+ - uses: actions/checkout@v4
13
+ - uses: actions/setup-python@v5
14
+ with:
15
+ python-version: "3.13"
16
+ - run: pip install ruff==0.15.9
17
+ - run: ruff check .
18
+ - run: ruff format --check .
19
+
20
+ build:
21
+ runs-on: ubuntu-latest
22
+ steps:
23
+ - uses: actions/checkout@v4
24
+ with:
25
+ fetch-depth: 0 # setuptools-scm 需要看到 tags
26
+ - uses: actions/setup-python@v5
27
+ with:
28
+ python-version: "3.13"
29
+ - run: pip install build
30
+ - run: python -m build
31
+ # 数据文件必须打进 wheel,否则 import zhihu_cli 会崩
32
+ - name: Smoke-test packaged data files
33
+ run: |
34
+ pip install --no-deps dist/*.whl
35
+ python -c "from zhihu_cli.prompts import AGORA_VOTE_SYSTEM_PROMPT; from zhihu_cli.nlp_tools import STOP_WORDS; print('data files OK')"
@@ -0,0 +1,34 @@
1
+ name: publish
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v*"
7
+
8
+ permissions:
9
+ contents: write # 创建 GitHub Release
10
+ id-token: write # 向 PyPI 做 trusted publishing (OIDC)
11
+
12
+ jobs:
13
+ publish:
14
+ runs-on: ubuntu-latest
15
+ steps:
16
+ - uses: actions/checkout@v4
17
+ with:
18
+ fetch-depth: 0 # setuptools-scm 需要看到 tags 来派生版本号
19
+ - uses: actions/setup-python@v5
20
+ with:
21
+ python-version: "3.13"
22
+ - run: pip install build
23
+ - run: python -m build
24
+ - name: Publish to PyPI
25
+ uses: pypa/gh-action-pypi-publish@release/v1
26
+ with:
27
+ attestations: true # SLSA 签名,需要 id-token: write
28
+ - name: Create GitHub Release
29
+ env:
30
+ GH_TOKEN: ${{ github.token }}
31
+ run: |
32
+ gh release create "$GITHUB_REF_NAME" dist/*.tar.gz dist/*.whl \
33
+ --title "$GITHUB_REF_NAME" \
34
+ --generate-notes
@@ -0,0 +1,15 @@
1
+ *.json
2
+ *.png
3
+ __pycache__
4
+
5
+ (draft)*
6
+ downloads
7
+ content_metrics
8
+ .cache
9
+
10
+ *egg-info
11
+ dist
12
+ build
13
+ .claude
14
+ CLAUDE.md
15
+ .swp
@@ -0,0 +1,7 @@
1
+ repos:
2
+ - repo: https://github.com/astral-sh/ruff-pre-commit
3
+ rev: v0.15.9
4
+ hooks:
5
+ - id: ruff
6
+ args: [ --fix ]
7
+ - id: ruff-format
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Kris
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,225 @@
1
+ Metadata-Version: 2.4
2
+ Name: zhihu-toolkit
3
+ Version: 0.1.0
4
+ Summary: Zhihu scraper and Markdown conversion utilities.
5
+ Author-email: KrisTHL181 <KrisTHL181@outlook.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/KrisTHL181/zhihu-cli
8
+ Project-URL: Repository, https://github.com/KrisTHL181/zhihu-cli
9
+ Project-URL: Issues, https://github.com/KrisTHL181/zhihu-cli/issues
10
+ Keywords: zhihu,scraper,cli,markdown,downloader,api
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Environment :: Console
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Intended Audience :: End Users/Desktop
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3 :: Only
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Topic :: Internet :: WWW/HTTP
21
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
22
+ Requires-Python: >=3.12
23
+ Description-Content-Type: text/markdown
24
+ License-File: LICENSE
25
+ Requires-Dist: click
26
+ Requires-Dist: curl-cffi
27
+ Requires-Dist: lxml
28
+ Requires-Dist: cssselect
29
+ Requires-Dist: pyyaml
30
+ Requires-Dist: rich
31
+ Requires-Dist: aiomqtt
32
+ Requires-Dist: textual>=2.0
33
+ Requires-Dist: qrcode
34
+ Requires-Dist: Pillow
35
+ Provides-Extra: classifier
36
+ Requires-Dist: torch>=2.0.0; extra == "classifier"
37
+ Requires-Dist: transformers>=4.30.0; extra == "classifier"
38
+ Requires-Dist: scikit-learn>=1.0.0; extra == "classifier"
39
+ Requires-Dist: jieba; extra == "classifier"
40
+ Requires-Dist: networkx; extra == "classifier"
41
+ Requires-Dist: numpy; extra == "classifier"
42
+ Provides-Extra: nlp
43
+ Requires-Dist: jieba; extra == "nlp"
44
+ Requires-Dist: matplotlib; extra == "nlp"
45
+ Requires-Dist: numpy; extra == "nlp"
46
+ Requires-Dist: pandas; extra == "nlp"
47
+ Requires-Dist: plotly; extra == "nlp"
48
+ Requires-Dist: scikit-learn; extra == "nlp"
49
+ Requires-Dist: wordcloud; extra == "nlp"
50
+ Requires-Dist: networkx; extra == "nlp"
51
+ Provides-Extra: creator
52
+ Requires-Dist: matplotlib; extra == "creator"
53
+ Requires-Dist: numpy; extra == "creator"
54
+ Requires-Dist: pandas; extra == "creator"
55
+ Requires-Dist: scipy; extra == "creator"
56
+ Requires-Dist: seaborn; extra == "creator"
57
+ Provides-Extra: notify
58
+ Requires-Dist: desktop-notifier; extra == "notify"
59
+ Dynamic: license-file
60
+
61
+ <div align="center">
62
+
63
+ # 🧢 zhihu-cli
64
+
65
+ **The terminal is your new Zhihu HQ.**
66
+
67
+ ```
68
+ browse · download · search · publish · analyze — all from the command line.
69
+ ```
70
+
71
+ [![Python 3.12+](https://img.shields.io/badge/python-3.12+-blue.svg)](https://www.python.org/downloads/)
72
+ [![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
73
+ [![GitHub Repo stars](https://img.shields.io/github/stars/KrisTHL181/zhihu-cli?style=flat)](https://github.com/KrisTHL181/zhihu-cli/stargazers)
74
+
75
+ </div>
76
+
77
+ ---
78
+
79
+ **zhihu-cli** turns your terminal into a full-featured Zhihu client. Authenticate once, then browse, search, download, publish, and analyze — without ever opening a browser.
80
+
81
+ > ⚠️ This is an **unofficial** CLI for Zhihu. Use at your own risk. Not affiliated with Zhihu Inc.
82
+
83
+ ---
84
+
85
+ ## 🚀 Quick Start
86
+
87
+ > **Requirement:** Python 3.12 or newer. Check your version with `python --version` before installing.
88
+
89
+ ```bash
90
+ # Install
91
+ pip install -e .
92
+
93
+ # Optional extras
94
+ pip install -e ".[nlp]" # word clouds, clustering
95
+ pip install -e ".[creator]" # income charts, trends
96
+ pip install -e ".[classifier]" # ML-powered content classification
97
+ ```
98
+
99
+ ### 1. Authenticate
100
+
101
+ ```bash
102
+ zhihu auth paste # paste a cURL from browser DevTools
103
+ zhihu auth login # scan a QR code with the Zhihu App
104
+ ```
105
+
106
+ ### 2. Verify
107
+
108
+ ```bash
109
+ zhihu auth status # check login status and active profile
110
+ ```
111
+
112
+ ---
113
+
114
+ ## ✨ What You Can Do
115
+
116
+ ### 📖 Read & Browse
117
+
118
+ Browse Zhihu's feeds, hot lists, questions, articles, pins, and comments — all rendered in your terminal with a Rich-powered pager. Explore the real-time trending list with excerpts, scroll through your personalized recommend feed, or dive into a question and its full answer thread without clicking a single link.
119
+
120
+ ### 💾 Download for Offline
121
+
122
+ Save any Zhihu content (articles, answers, questions, pins, videos) as clean Markdown with YAML frontmatter. Download individual pieces or batch-process from a manifest. Everything lands in `~/.zhihu-cli/downloads/`, organized by type, ready for your note-taking system or offline reading.
123
+
124
+ ### 🔍 Search
125
+
126
+ Search questions, articles, users, and topics across Zhihu. Fine-tune result depth and quantity — all from the command line.
127
+
128
+ ### ✍️ Publish & Edit
129
+
130
+ Write answers and articles in Markdown, publish them to Zhihu with one command. Need to update? Modify existing answers and articles from your local files. Markdown-to-HTML conversion happens automatically via Zhihu's own rendering pipeline.
131
+
132
+ ### 💬 Interact
133
+
134
+ Vote, thank, follow, block, and comment — full social interaction without the browser. Manage collections: create, populate, and organize them. Send and receive direct messages, and stream real-time notifications and chat via MQTT.
135
+
136
+ ### 🕸️ Scrape & Export
137
+
138
+ Batch-export your creations, activity history, answers, and articles as structured JSON. Use the universal converter to merge and normalize across formats for your own data pipeline.
139
+
140
+ ### 📊 Analyze
141
+
142
+ **Creator analytics** — pull your Zhihu income data and visualize it: monthly summaries, trend charts (with EMA), advanced indicators (Bollinger Bands, MACD), derivative analysis (velocity/acceleration/jerk), weekday breakdowns, and per-content daily metrics. Charts are saved as PNGs.
143
+
144
+ **NLP tools** — run word frequency analysis, generate word clouds, and perform K-means clustering on your downloaded content. All operate across your full Markdown library.
145
+
146
+ ### 🔐 Multi-Account
147
+
148
+ Save multiple profiles from different accounts, switch between them with a single command. Each profile keeps its own auth credentials and cookies.
149
+
150
+ ---
151
+
152
+ ## 🏗️ Architecture
153
+
154
+ ```
155
+ src/zhihu_cli/
156
+ ├── main.py # Click CLI — command group hub
157
+ ├── output.py # styled terminal output (Rich)
158
+ ├── content/
159
+ │ ├── handlers/ # one file per Zhihu domain
160
+ │ └── utils/ # HTML↔Markdown, ZSE v4 signing
161
+ ├── creator_tools/ # income analytics + plotting
162
+ ├── nlp_tools/ # word count, wordcloud, clustering
163
+ └── extensions/ # plugin system (auto-discovered)
164
+ ```
165
+
166
+ | Layer | What It Does |
167
+ |---|---|
168
+ | **🔐 Auth** | Browser Cookie + User-Agent headers from cURL paste or QR code login, cached per-profile |
169
+ | **✍️ Signing** | Every Zhihu request gets auto-signed with `x-zse-93` / `x-zse-96` headers via ZSE v4 cipher |
170
+ | **🌐 Requests** | `curl_cffi` impersonates Chrome's TLS fingerprint to avoid detection |
171
+ | **📄 Extraction** | Prefers direct API calls; falls back to HTML page scraping with `js-initialData` parsing |
172
+ | **📝 Markdown** | HTML → LaTeX preprocessing → recursive traversal → clean Markdown. Reverse for publishing |
173
+ | **🔌 Extensions** | Drop a plugin in `extensions/` with `register_cli(group)` — auto-discovered at startup |
174
+
175
+ ---
176
+
177
+ ## 🧪 Extras
178
+
179
+ ### Optional Dependencies
180
+
181
+ ```bash
182
+ pip install -e ".[nlp]" # jieba, matplotlib, wordcloud, scikit-learn...
183
+ pip install -e ".[creator]" # matplotlib, numpy, pandas, seaborn...
184
+ pip install -e ".[classifier]" # torch, transformers, scikit-learn...
185
+ ```
186
+
187
+ ### Shell Completions
188
+
189
+ ```bash
190
+ eval "$(python autocomp.py)"
191
+ ```
192
+
193
+ ---
194
+
195
+ ## 🤝 Contributing
196
+
197
+ PRs welcome! The codebase is structured for extensibility:
198
+
199
+ - **New command?** Add a file to `commands/` with a `register_<name>(group)` function, import it in `main.py`.
200
+ - **New handler?** Add a file to `content/handlers/` — follow the existing patterns.
201
+ - **New extension?** Create `extensions/<name>/` with an `__init__.py` exposing `register_cli(group)`.
202
+
203
+ Run the formatter before submitting:
204
+
205
+ ```bash
206
+ pre-commit run --all-files
207
+ ruff check .
208
+ ruff format .
209
+ ```
210
+
211
+ ---
212
+
213
+ ## 📜 License
214
+
215
+ MIT
216
+
217
+ ---
218
+
219
+ <div align="center">
220
+
221
+ *Made with ❤️ and way too many terminal sessions.*
222
+
223
+ [Report a bug](https://github.com/KrisTHL181/zhihu-cli/issues) · [Fork this repository](https://github.com/KrisTHL181/zhihu-cli/fork) · Star ⭐ this repo!
224
+
225
+ </div>
@@ -0,0 +1,165 @@
1
+ <div align="center">
2
+
3
+ # 🧢 zhihu-cli
4
+
5
+ **The terminal is your new Zhihu HQ.**
6
+
7
+ ```
8
+ browse · download · search · publish · analyze — all from the command line.
9
+ ```
10
+
11
+ [![Python 3.12+](https://img.shields.io/badge/python-3.12+-blue.svg)](https://www.python.org/downloads/)
12
+ [![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
13
+ [![GitHub Repo stars](https://img.shields.io/github/stars/KrisTHL181/zhihu-cli?style=flat)](https://github.com/KrisTHL181/zhihu-cli/stargazers)
14
+
15
+ </div>
16
+
17
+ ---
18
+
19
+ **zhihu-cli** turns your terminal into a full-featured Zhihu client. Authenticate once, then browse, search, download, publish, and analyze — without ever opening a browser.
20
+
21
+ > ⚠️ This is an **unofficial** CLI for Zhihu. Use at your own risk. Not affiliated with Zhihu Inc.
22
+
23
+ ---
24
+
25
+ ## 🚀 Quick Start
26
+
27
+ > **Requirement:** Python 3.12 or newer. Check your version with `python --version` before installing.
28
+
29
+ ```bash
30
+ # Install
31
+ pip install -e .
32
+
33
+ # Optional extras
34
+ pip install -e ".[nlp]" # word clouds, clustering
35
+ pip install -e ".[creator]" # income charts, trends
36
+ pip install -e ".[classifier]" # ML-powered content classification
37
+ ```
38
+
39
+ ### 1. Authenticate
40
+
41
+ ```bash
42
+ zhihu auth paste # paste a cURL from browser DevTools
43
+ zhihu auth login # scan a QR code with the Zhihu App
44
+ ```
45
+
46
+ ### 2. Verify
47
+
48
+ ```bash
49
+ zhihu auth status # check login status and active profile
50
+ ```
51
+
52
+ ---
53
+
54
+ ## ✨ What You Can Do
55
+
56
+ ### 📖 Read & Browse
57
+
58
+ Browse Zhihu's feeds, hot lists, questions, articles, pins, and comments — all rendered in your terminal with a Rich-powered pager. Explore the real-time trending list with excerpts, scroll through your personalized recommend feed, or dive into a question and its full answer thread without clicking a single link.
59
+
60
+ ### 💾 Download for Offline
61
+
62
+ Save any Zhihu content (articles, answers, questions, pins, videos) as clean Markdown with YAML frontmatter. Download individual pieces or batch-process from a manifest. Everything lands in `~/.zhihu-cli/downloads/`, organized by type, ready for your note-taking system or offline reading.
63
+
64
+ ### 🔍 Search
65
+
66
+ Search questions, articles, users, and topics across Zhihu. Fine-tune result depth and quantity — all from the command line.
67
+
68
+ ### ✍️ Publish & Edit
69
+
70
+ Write answers and articles in Markdown, publish them to Zhihu with one command. Need to update? Modify existing answers and articles from your local files. Markdown-to-HTML conversion happens automatically via Zhihu's own rendering pipeline.
71
+
72
+ ### 💬 Interact
73
+
74
+ Vote, thank, follow, block, and comment — full social interaction without the browser. Manage collections: create, populate, and organize them. Send and receive direct messages, and stream real-time notifications and chat via MQTT.
75
+
76
+ ### 🕸️ Scrape & Export
77
+
78
+ Batch-export your creations, activity history, answers, and articles as structured JSON. Use the universal converter to merge and normalize across formats for your own data pipeline.
79
+
80
+ ### 📊 Analyze
81
+
82
+ **Creator analytics** — pull your Zhihu income data and visualize it: monthly summaries, trend charts (with EMA), advanced indicators (Bollinger Bands, MACD), derivative analysis (velocity/acceleration/jerk), weekday breakdowns, and per-content daily metrics. Charts are saved as PNGs.
83
+
84
+ **NLP tools** — run word frequency analysis, generate word clouds, and perform K-means clustering on your downloaded content. All operate across your full Markdown library.
85
+
86
+ ### 🔐 Multi-Account
87
+
88
+ Save multiple profiles from different accounts, switch between them with a single command. Each profile keeps its own auth credentials and cookies.
89
+
90
+ ---
91
+
92
+ ## 🏗️ Architecture
93
+
94
+ ```
95
+ src/zhihu_cli/
96
+ ├── main.py # Click CLI — command group hub
97
+ ├── output.py # styled terminal output (Rich)
98
+ ├── content/
99
+ │ ├── handlers/ # one file per Zhihu domain
100
+ │ └── utils/ # HTML↔Markdown, ZSE v4 signing
101
+ ├── creator_tools/ # income analytics + plotting
102
+ ├── nlp_tools/ # word count, wordcloud, clustering
103
+ └── extensions/ # plugin system (auto-discovered)
104
+ ```
105
+
106
+ | Layer | What It Does |
107
+ |---|---|
108
+ | **🔐 Auth** | Browser Cookie + User-Agent headers from cURL paste or QR code login, cached per-profile |
109
+ | **✍️ Signing** | Every Zhihu request gets auto-signed with `x-zse-93` / `x-zse-96` headers via ZSE v4 cipher |
110
+ | **🌐 Requests** | `curl_cffi` impersonates Chrome's TLS fingerprint to avoid detection |
111
+ | **📄 Extraction** | Prefers direct API calls; falls back to HTML page scraping with `js-initialData` parsing |
112
+ | **📝 Markdown** | HTML → LaTeX preprocessing → recursive traversal → clean Markdown. Reverse for publishing |
113
+ | **🔌 Extensions** | Drop a plugin in `extensions/` with `register_cli(group)` — auto-discovered at startup |
114
+
115
+ ---
116
+
117
+ ## 🧪 Extras
118
+
119
+ ### Optional Dependencies
120
+
121
+ ```bash
122
+ pip install -e ".[nlp]" # jieba, matplotlib, wordcloud, scikit-learn...
123
+ pip install -e ".[creator]" # matplotlib, numpy, pandas, seaborn...
124
+ pip install -e ".[classifier]" # torch, transformers, scikit-learn...
125
+ ```
126
+
127
+ ### Shell Completions
128
+
129
+ ```bash
130
+ eval "$(python autocomp.py)"
131
+ ```
132
+
133
+ ---
134
+
135
+ ## 🤝 Contributing
136
+
137
+ PRs welcome! The codebase is structured for extensibility:
138
+
139
+ - **New command?** Add a file to `commands/` with a `register_<name>(group)` function, import it in `main.py`.
140
+ - **New handler?** Add a file to `content/handlers/` — follow the existing patterns.
141
+ - **New extension?** Create `extensions/<name>/` with an `__init__.py` exposing `register_cli(group)`.
142
+
143
+ Run the formatter before submitting:
144
+
145
+ ```bash
146
+ pre-commit run --all-files
147
+ ruff check .
148
+ ruff format .
149
+ ```
150
+
151
+ ---
152
+
153
+ ## 📜 License
154
+
155
+ MIT
156
+
157
+ ---
158
+
159
+ <div align="center">
160
+
161
+ *Made with ❤️ and way too many terminal sessions.*
162
+
163
+ [Report a bug](https://github.com/KrisTHL181/zhihu-cli/issues) · [Fork this repository](https://github.com/KrisTHL181/zhihu-cli/fork) · Star ⭐ this repo!
164
+
165
+ </div>
@@ -0,0 +1,142 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Shell autocompletion setup for the CLI tool.
4
+
5
+ Detects the current OS and shell, then prints the appropriate ``eval`` command
6
+ to enable Click-based shell completion. Pipe the output into your shell::
7
+
8
+ eval "$(python autocomp.py)"
9
+
10
+ Or add the printed command directly to your shell's rc file (``.zshrc``,
11
+ ``.bashrc``, ``config.fish``, or ``$PROFILE`` on PowerShell).
12
+
13
+ You can also bypass autodetection by passing an explicit shell name::
14
+
15
+ python autocomp.py --shell fish
16
+ """
17
+
18
+ from __future__ import annotations
19
+
20
+ import argparse
21
+ import os
22
+ import platform
23
+ import shutil
24
+ import sys
25
+
26
+ COMMAND_NAME = "zhihu"
27
+
28
+ # Shells that Click natively supports for completion.
29
+ _SUPPORTED_SHELLS = frozenset({"bash", "zsh", "fish", "powershell"})
30
+
31
+
32
+ def detect_shell() -> str | None:
33
+ """Best-effort detection of the active shell.
34
+
35
+ Returns one of ``"zsh"``, ``"bash"``, ``"fish"``, ``"powershell"``, or *None*.
36
+ """
37
+ system = platform.system()
38
+
39
+ # ── Windows ──────────────────────────────────────────────────────
40
+ if system == "Windows":
41
+ # PSModulePath is the most reliable PowerShell-only env var.
42
+ if "PSModulePath" in os.environ:
43
+ return "powershell"
44
+ # Fallback: check COMSPEC or SHELL for pwsh mentions.
45
+ shell = os.environ.get("SHELL", "") or os.environ.get("COMSPEC", "")
46
+ if "powershell" in shell.lower() or "pwsh" in shell.lower():
47
+ return "powershell"
48
+ return None
49
+
50
+ # ── Linux / macOS ────────────────────────────────────────────────
51
+ if system in ("Linux", "Darwin"):
52
+ # $SHELL is the login shell — accurate enough for the vast
53
+ # majority of users.
54
+ shell_path = os.environ.get("SHELL", "")
55
+ basename = os.path.basename(shell_path)
56
+ if basename in ("zsh", "bash", "fish"):
57
+ return basename
58
+ # Some distros symlink /bin/sh → bash; be tolerant.
59
+ if basename == "sh":
60
+ if os.environ.get("BASH_VERSION"):
61
+ return "bash"
62
+ if os.environ.get("ZSH_VERSION"):
63
+ return "zsh"
64
+ # Fish sets FISH_VERSION even when $SHELL doesn't point to it
65
+ # (e.g. launched as a subshell from another shell).
66
+ if os.environ.get("FISH_VERSION"):
67
+ return "fish"
68
+ return None
69
+
70
+ return None
71
+
72
+
73
+ def _detect_with_fallback(override: str | None) -> str:
74
+ """Resolve the shell name, preferring *override* when given.
75
+
76
+ :param override: Explicit shell name from ``--shell``, or *None*.
77
+ :returns: A shell name in ``_SUPPORTED_SHELLS``.
78
+ :raises SystemExit: When detection fails or the shell is unsupported.
79
+ """
80
+ if override is not None:
81
+ override = override.lower()
82
+ if override not in _SUPPORTED_SHELLS:
83
+ supported = ", ".join(sorted(_SUPPORTED_SHELLS))
84
+ sys.exit(f"Unsupported shell: {override!r}. Supported shells: {supported}.")
85
+ return override
86
+
87
+ shell = detect_shell()
88
+ if shell is not None:
89
+ return shell
90
+
91
+ system = platform.system()
92
+ shell_env = os.environ.get("SHELL", "?")
93
+ supported = ", ".join(sorted(_SUPPORTED_SHELLS))
94
+ msg = (
95
+ f"Unsupported environment: OS={system}, SHELL={shell_env}. "
96
+ f"Supported shells: {supported}. Use --shell to pick one explicitly."
97
+ )
98
+ sys.exit(msg)
99
+
100
+
101
+ def get_completion_command(shell: str) -> str:
102
+ """Return the eval-ready autocompletion command for *shell*.
103
+
104
+ :param shell: One of ``"bash"``, ``"zsh"``, ``"fish"``, ``"powershell"``.
105
+ """
106
+ if shutil.which(COMMAND_NAME) is None:
107
+ install_path = os.path.abspath(os.path.dirname(__file__))
108
+ sys.exit(f"{COMMAND_NAME} command not found. Please install it first: `pip install -e {install_path}`")
109
+
110
+ env_var = f"_{COMMAND_NAME.upper()}_COMPLETE"
111
+
112
+ if shell == "zsh":
113
+ return f'eval "$({env_var}=zsh_source {COMMAND_NAME})"'
114
+ if shell == "bash":
115
+ return f'eval "$({env_var}=bash_source {COMMAND_NAME})"'
116
+ if shell == "fish":
117
+ return f"{env_var}=fish_source {COMMAND_NAME} | source"
118
+ if shell == "powershell":
119
+ return f"& $env:{env_var}=powershell_source {COMMAND_NAME} | Out-String | Invoke-Expression"
120
+
121
+ sys.exit(f"Unsupported shell: {shell}")
122
+
123
+
124
+ def main() -> None:
125
+ parser = argparse.ArgumentParser(
126
+ description=f"Print the eval-ready shell completion command for {COMMAND_NAME}.",
127
+ )
128
+ _ = parser.add_argument(
129
+ "-s",
130
+ "--shell",
131
+ choices=sorted(_SUPPORTED_SHELLS),
132
+ default=None,
133
+ help="Shell to generate completion for (auto-detected when omitted).",
134
+ )
135
+ args = parser.parse_args()
136
+
137
+ shell = _detect_with_fallback(args.shell)
138
+ print(get_completion_command(shell))
139
+
140
+
141
+ if __name__ == "__main__":
142
+ main()