JMComic-Crawler-Python: a Python API and CLI for downloading JMComic albums
Python API for JMComic | 提供Python API访问禁漫天堂,同时支持网页端和移动端 | 禁漫天堂GitHub Actions下载器🚀
At a glance
- What is it?
- The jmcomic package wraps JMComic's web and mobile endpoints behind a sync and async Python API, a jmcomic command and a GitHub Actions workflow. It is a downloader first, with 21 bundled plugins and a config file that decides almost everything.
- Who is it for?
- Adopt jmcomic if you want a scripted, configurable downloader for JMComic albums and are comfortable editing option.yml to control domains, client type, image conversion and plugin behaviour. Do not adopt it if you need a general-purpose crawler framework, or if you expect the maintainer to treat documentation lag as a bug: the README itself says docs and examples are sometimes out of date.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 2 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 29, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What jmcomic actually downloads, and for whom
The repository describes its core function bluntly: downloading albums. Everything else in the package exists to serve that, which is why the API surface looks like a downloader rather than a general client. You hand it an album id, it fetches the chapters, decodes the images and writes processed files to disk.
The intended user is someone who can read a few lines of Python or run a shell command. The README lists three entry points with different levels of commitment: GitHub Actions for people who want a web form and no local install, the command line for people who want a one-liner, and the Python API for people who want to script or extend. It is not aimed at someone who wants a GUI.
Alongside downloading, the project implements other JMComic endpoints on an as-needed basis: login, search with all search items, comments including replies and spoiler flags, categories and rankings, album and chapter details, image decode, personal favourites, and the encryption used by the mobile app API. Those are secondary. If you only need metadata, the jmv command exists for exactly that: the README gives the scenario of pasting a car number to see what an album is, without downloading it.
Two clients, one option object, and where the configuration lives
The mechanism worth understanding is the split between Client and Option. Option holds configuration: request domain, client implementation, whether to use a disk cache, how many chapters and images download concurrently, image format conversion, download path rules, request metadata such as headers, cookies and proxies, and Chinese traditional/simplified conversion. Client does the requesting. The README states that both a web client and a mobile client are implemented and you switch between them by configuration, with an explicit trade-off given: the mobile client is not restricted by IP and has better compatibility, while the web client is IP-region restricted but more efficient.
That single sentence explains most of the operational surprises. If you run from a server in the wrong region, the web client may fail where the mobile client works, and the reverse costs you throughput. The project also documents an automatic retry and domain-switching mechanism, which matters because the target site is behind Cloudflare and the README lists bypassing that anti-crawler protection as a project feature.
Configuration can be created from a file in several formats, and the README notes that no configuration at all is still usable. Extension points are explicit: callbacks before and after album, chapter and image downloads, custom classes for Downloader, Option, Client and entities, custom logging and exception listeners, and a plugin system with 21 built-in plugins covering things like a rich progress bar, PDF merging, long-image stitching, zip/7z archives, browser cookie retrieval, subscription updates and favourites export.
Installing jmcomic and downloading your first album
The README recommends Python 3.14 and notes that CI only covers 3.10 and above, with 3.9 install-compatible but out of CI. Install from PyPI, which is also the update command:
pip install jmcomic -UIf you prefer the source tree, the README gives the git form:
pip install git+https://github.com/hect0x7/JMComic-Crawler-PythonThe shortest real use is two lines of Python. The first argument is the album id, and the README's example downloads JM123 in full:
import jmcomic
jmcomic.download_album('123')An async variant exists for the same call, run through asyncio:
import asyncio
asyncio.run(jmcomic.download_album_async('123'))If you would rather not write Python, the console script does the same job. On Windows the README suggests win+R and typing the command; on any platform it is just:
jmcomic 123To download an album and one specific chapter together, the README shows the chapter prefixed with p:
jmcomic 123 p456To control behaviour you write an option file and point the code at it. The README's example converts every downloaded image to PNG:
download:
image:
suffix: .pngThat file is then loaded explicitly, and the resulting option object is passed to the download call:
import jmcomic
option = jmcomic.create_option_by_file('D:/option.yml')
jmcomic.download_album(123, option)The CLI accepts the same file with --option, or reads the JM_OPTION_PATH environment variable if you would rather not repeat the flag. The README recommends the environment variable route and gives a PowerShell example: setx JM_OPTION_PATH "D:/a.yml". For a prettier progress bar, install rich separately; the README says the progress bar is on by default but needs that extra dependency.
The jmv command and what it will not do
jmv is a separate console script for inspection rather than download. The README describes the use case as seeing a car number somewhere and wanting to know what the album is, so jmv accepts arbitrary text and extracts the digits. Passing jmv 350234 queries that album; passing jmv 350谁还没看过234 extracts 350234 from the mixed string. The -y flag exits immediately instead of waiting for an Enter keypress, which matters when you call it from a script.
The output is a formatted block with title, id, link, author, dates, page count, view/like/comment figures, tags, characters, works and the chapter list. That is a metadata view. It does not fetch images, and the README states this directly: jmv does not download.
The limitation to plan around is that all of this depends on the remote site answering. The project's own features list names Cloudflare bypass as a capability, which is an admission that the target actively resists automated access. A change on that side can break requests until a release adapts. The README also carries a request to avoid crawling too many albums at once to reduce load on JM's servers, and that is a practical constraint as much as a courtesy: concurrency settings in the option file are the lever you have, and pushing them up is the fastest way to get throttled or blocked.
Where jmcomic is the wrong tool
This is a single-site client, not a crawler framework. If your actual task is crawling many unrelated sites with a shared scheduling and extraction model, jmcomic gives you nothing reusable: its Option, Client and Downloader abstractions are shaped around JMComic's endpoints and image pipeline. Choosing it for a general scraping job means fighting the design.
The second boundary is legality and content. The package targets an adult site, the PyPI keywords include NSFW, and the README's own note asks users to be considerate about server load. Whether you may download this material, and what you may do with it, depends on your jurisdiction and the site's terms, not on the MIT licence of the code. The licence covers the software, not the content it retrieves.
Third, documentation lag is acknowledged rather than solved. The README says the project is personal and that documentation and examples will sometimes be behind, and directs you to open an issue. That is honest, but it means a configuration key you remember from an older release may not match the current one. The option file syntax page is the reference to trust, and the release cadence is frequent enough (v2.7.5, v2.7.6 and v2.7.7 across August and September 2026) that drift between docs and code is plausible. The last push to the repository was on 2026-09-18.
How it compares to a general-purpose Python crawler
A framework like Scrapy takes the opposite approach. You define spiders, item pipelines and middlewares, and the framework owns scheduling, retries and concurrency in a way that generalises across sites. jmcomic inverts that: the domain logic is already written, and you configure it. There is no spider class to write and no item schema to define, because the entities (album, chapter, image) are built in.
The practical difference shows up when requirements change. With a general framework, adding a new target site is normal work. With jmcomic, a new target site is out of scope entirely, but adding a post-download step is cheap: the plugin list already includes PDF merging, long-image stitching, zip/7z packaging and favourites export, and the callback hooks let you insert your own logic before or after album, chapter and image downloads. The async API is also a real difference from the synchronous default, and the README points to a dedicated async usage tutorial rather than documenting it inline.
If you want the downloader to be a component inside a larger pipeline you control, jmcomic's extension points are the right seam. If you want the pipeline itself, pick something else.
Licence, maintenance and the cost of upgrading
The project is MIT licensed, and both pyproject.toml and setup.py declare it, with the classifier License :: OSI Approved :: MIT License. MIT is permissive: you can use, modify and redistribute the code with the licence and copyright notice retained. That says nothing about the content you download, and nothing here is legal advice.
Runtime dependencies are modest and named: commonx, curl-cffi, pillow, pycryptodome and pyyaml. The plugin extras are separate, listed under an optional dependency group called plugins: img2pdf, pikepdf, psutil, py7zr, pyzipper, rich and browser_cookie3. Installing the base package does not pull those in, which is why the README tells you to install rich yourself for the progress bar. If you enable a plugin that needs one of them, you own that install.
Upgrade cost is dominated by the option file, not the API. The download entry points are stable enough that the README's two-line example has not grown, but the configuration surface is wide and the README admits docs can lag. Keep your option.yml under version control, read the option file syntax page before and after upgrading, and pin a version if you depend on plugin behaviour. Note the classifier Development Status :: 4 - Beta, which sits oddly against a project with a changelog and frequent releases, but it is what the packaging metadata says.
There is no rollback documentation in the README, so plan upgrades by pinning rather than by expecting a documented downgrade path.
Editorial conclusion
Adopt jmcomic if you want a scripted, configurable downloader for JMComic albums and are comfortable editing option.yml to control domains, client type, image conversion and plugin behaviour. Do not adopt it if you need a general-purpose crawler framework, or if you expect the maintainer to treat documentation lag as a bug: the README itself says docs and examples are sometimes out of date. Verify first that the current release still talks to a working domain from your network, that you are on Python 3.10 or newer since CI only covers 3.10 and above, and that you have read the option file syntax page before writing your own config.
Frequently asked questions
How do I install jmcomic with pip?
Run pip install jmcomic -U. The README says the same command is used for updates, and recommends Python 3.14 while noting that CI only covers Python 3.10 and above.
Can I use jmcomic without writing Python code?
Yes. The package installs a jmcomic console script, so jmcomic 123 downloads album 123, and jmcomic 123 p456 adds a specific chapter. A separate jmv command shows album details without downloading anything.
Does jmcomic support async downloads?
The README shows an async API alongside the synchronous one, using jmcomic.download_album_async inside asyncio.run, and points to a dedicated async usage tutorial in the documentation.
How do I configure jmcomic with an option file?
Write a YAML file such as option.yml, load it with jmcomic.create_option_by_file and pass the result to download_album. The CLI accepts the same file through the --option flag or the JM_OPTION_PATH environment variable.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/hect0x7-jmcomic-crawler-python)