Self-hosted service
qd-today/qd avatar
qd-today/qd

qd-today/qd: a HAR-driven scheduler for HTTP check-in tasks

QD [v20240210] —— HTTP请求定时任务自动执行框架 base on HAR Editor and Tornado Server

5,585 stars655 forksPythonMIT

At a glance

What is it?
QD is a Tornado-based framework that turns a browser session recorded as a HAR file into a scheduled HTTP request. It fits people who need recurring check-ins against sites that have no API, and it expects you to trust the recorded session with real cookies.
Who is it for?
Adopt qd-today/qd if you already capture sessions in Chrome DevTools and want those requests replayed on a cron without writing a client per site. Do not adopt it if you need documented rollback, a multi-browser capture path, or a scheduler that never stores plaintext session cookies.
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 89 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 October 2, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The check-in problem QD was built to absorb

A large class of sites hands out a daily reward for visiting a page while logged in. They have no public API for it, the request carries a session cookie, and the endpoint changes when the site ships a new front end. Writing a script per site means re-reading DevTools every time something shifts. QD takes the position that the browser already knows how to make the request, so it should be the source of truth.

The audience is narrow and specific. The README states the project only guarantees support for Chrome, and asks for a pull request if someone tests another browser. That sentence tells you the intended workflow: open Chrome, record the traffic, export it as HAR, import it into QD. Anyone who lives in Firefox or Safari is working outside the supported path. The project is not a general scraping framework and does not try to parse HTML for you; it replays requests.

HAR in, Tornado scheduler out

The repository description calls QD an "HTTP请求定时任务自动执行框架 base on HAR Editor and Tornado Server". The mechanism follows from that: a HAR export is the task definition, and Tornado is the HTTP server that serves the admin UI and runs the scheduler.

The process layout is visible in the top-level files. run.py, web.py, worker.py and qd.py sit alongside libs/, config/, db/ and web/, which suggests a split between the web front end, the task worker, and shared library code. croniter appears in requirements.txt, which is the dependency that evaluates cron expressions, and the docker-compose.yml exposes CHECK_TASK_LOOP, TASK_MAX_RETRY_COUNT and NEW_TASK_DELAY, so task scheduling and retry behaviour are tunable rather than fixed. Redis is a declared dependency: the compose file defines a redis service and passes REDISCLOUD_URL=redis://redis:6379 to the app, with REDIS_DB_INDEX available to pick a database number. MySQL is reachable through aiomysql and pymysql, and sqlite3 is the commented-out default for DB_TYPE, so the storage layer can be either a single file or an external server.

The consequence of replaying recorded requests is that QD is sensitive to whatever the recording captured. Headers, cookies and body all come from the HAR. If the site rotates a token that was baked into the recording, the task fails until you record again. QD does not repair that for you.

Installing QD with Docker and running a first task

The README points at the usage guide at https://qd-today.github.io/qd/zh_CN/, and the repository ships a docker-compose.yml. The compose file pulls qdtoday/qd:latest, maps host port 8923 to container port 80, and mounts ./config into /usr/src/app/config so settings survive a container rebuild. Two commented alternatives are listed: qdtoday/qd:lite-latest for a trimmed image and qdtoday/qd:dev for the development build.

Start it with:

bash
docker compose up -d

After that the admin interface answers on http://localhost:8923. The compose file sets DOMAIN to an empty value, so the app does not assume a hostname; if you put QD behind a reverse proxy, that is the variable to revisit.

The environment block also carries two secrets that ship with placeholder values, COOKIE_SECRET=binux and AES_KEY=binux. Both are commented as defaults and both should be replaced before the instance is reachable from anywhere. PBKDF2_ITERATIONS=400 is set alongside them.

Storage defaults matter here. DB_TYPE is present but commented out, and the only other database option shown is JAWSDB_MARIA_URL with a mysql:// URL shape. If you leave DB_TYPE unset, check the guide for which backend the app falls back to before you accumulate tasks.

For a first task, the workflow is: log into the target site in Chrome, open DevTools, perform the check-in action once, export the session as HAR, then import that HAR into QD and attach a cron schedule. The README does not document the import dialog itself, so the field-by-field behaviour comes from the usage guide rather than the repository.

What breaks, and when QD is the wrong tool

The failure mode is baked into the design. A HAR is a point-in-time recording, and any request that depends on a value generated at page load will go stale. The task then fails, and the failure is a failed HTTP request, not a parse error you can debug from the response body.

Retries are bounded. TASK_MAX_RETRY_COUNT is set to 8 in the compose file, and TASK_WHILE_LOOP_TIMEOUT to 900, with TASK_REQUEST_LIMIT at 1500. Those are the ceilings on how hard QD will try before it gives up on a run. If your target site rate-limits or bans on repeated attempts, that retry budget is a risk rather than a safety net.

QD also stores live session material. AES_KEY and COOKIE_SECRET protect it, but the material is there, and the compose file's default values are public. That makes QD a poor fit for anything with financial authority or a shared team account where an audit trail is required. It is equally wrong for sites you do not own or have permission to automate; the project provides the mechanism and says nothing about the terms of the sites you point it at.

Finally, browser support is a stated limit, not a bug. The README says maintenance effort is limited and only Chrome is guaranteed. If your capture workflow runs anywhere else, you are on your own.

How QD differs from a plain cron plus curl

The obvious alternative is a crontab entry that calls curl with a cookie header. That approach is lighter and has no web UI, no Redis, and no database. The difference is where the task definition lives. With cron and curl, you hand-write the header set and you maintain it when the site changes. With QD, the header set comes out of a browser session, so the first version of a task costs one recording rather than a reading of the network tab.

The second alternative is a general-purpose automation runner such as a headless browser driven by a script. That handles dynamic pages and JavaScript-rendered tokens, which QD does not, because QD replays HTTP requests rather than rendering pages. The trade is resource cost: a headless browser per task is far heavier than an HTTP replay, and QD's worker model with a queue is built around the lighter case.

A third option is a hosted monitoring service that hits a URL on a schedule. Those generally cannot carry your authenticated session, which is the entire problem QD exists to solve.

Maintenance, releases and the MIT licence

The last push to the repository was on 2026-07-06. The most recent release is 20250803, published on 2025-08-03, with 20250129 and 20250128 before it. That is a slow release cadence: roughly two release points in the period covered by the changelog excerpt. The repository is not archived.

Upgrades run through the image tag. The compose file pins qdtoday/qd:latest, so a pull and recreate moves you to whatever the current build is. The repository also ships update.sh and a Dockerfile that symlinks it to /bin/update, so an in-container update path exists. The README does not document rollback, and the compose file does not pin a digest, so an upgrade that breaks a task leaves you reconstructing the previous image tag yourself.

On licensing: QD is MIT licensed, and the LICENSE file is in the repository root. MIT permits commercial use and modification, and requires the copyright notice and permission notice to be preserved. The Dockerfile clones the source from a Gitee mirror during the build, which is worth knowing if your build pipeline has no route to that host. This is a description of the licence text, not legal advice; read the LICENSE file and your own obligations.

Editorial conclusion

Adopt qd-today/qd if you already capture sessions in Chrome DevTools and want those requests replayed on a cron without writing a client per site. Do not adopt it if you need documented rollback, a multi-browser capture path, or a scheduler that never stores plaintext session cookies. Before deploying, verify the COOKIE_SECRET and AES_KEY values in docker-compose.yml, confirm whether the default sqlite3 DB_TYPE suits your task volume, and check that the last release, 20250803, covers the features you need.

Frequently asked questions

What is qd-today/qd and what does it do?

It is an HTTP request scheduling framework built on a HAR Editor and a Tornado server, written in Python. You import a browser session recorded as a HAR file, attach a cron schedule, and QD replays those requests automatically.

How do I install qd-today/qd with Docker?

The repository includes a docker-compose.yml that pulls qdtoday/qd:latest, maps host port 8923 to container port 80, and mounts ./config into /usr/src/app/config. Running docker compose up -d starts it, after which the interface is available on port 8923.

Which browsers does qd-today/qd support for recording tasks?

The README states that only Chrome is guaranteed, citing limited maintenance capacity, and invites a pull request if someone tests another browser. Other browsers are outside the supported path.

Does qd-today/qd need Redis or a database?

The docker-compose.yml defines a redis service and passes REDISCLOUD_URL=redis://redis:6379 to the app. For storage, DB_TYPE is shown commented out with sqlite3 as the value, and JAWSDB_MARIA_URL is the MySQL option, so both a local file and an external database are possible.

Official sources

  1. License: MIT
  2. Project website
  3. qd-today/qd on GitHub
  4. README
  5. Releases
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.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/qd-today-qd.svg)](https://hysenlabs.com/projects/qd-today-qd)