faster-than-requests: a single file HTTP client with a scraper bolted on
Faster requests on Python 3
At a glance
- What is it?
- faster-than-requests is an MIT licensed Python HTTP client in one file with no dependencies, aimed at the small scripts where the requests library is more machinery than the job needs. It also ships seven scraper functions and WebSocket support, which is the part that makes it more than a drop-in for requests.
- Who is it for?
- faster-than-requests fits a script that makes a handful of HTTP calls, wants no dependency to install, and does not need the session, proxy and retry machinery that comes with requests. It is a poor fit for anything that depends on the wider requests ecosystem, on connection pooling behaviour you can reason about, or on a maintained stream of upstream fixes, since the last tagged release is 1.0.0 from 2020 while the repository has seen commits as recently as 2026-10-06.
- 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 17 days ago.
- What is it written in?
- Mainly Nim, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
One import line, and a much larger API than requests
The pitch is a single line of code, and it is designed to be a drop-in for the most common import in Python:
import faster_than_requests as requests
requests.get("http://httpbin.org/get")After that alias, the naming convention is the giveaway about what this project actually is. The function list in the readme runs to a few dozen names, and they are grouped by what they return rather than by what they do. There are the conventional verbs, get, post, put, patch, delete and head, plus download, download2 and download3, and then a family whose names describe the return type: get2str, get2dict, get2json, post2str, post2dict, post2json and post2list.
Then there are the utility functions, tuples2json, set_headers, multipartdata2str, datauri, urlparse, urlencode, urldecode, encodequery, encodexml, debugs and minifyhtml, plus a websocket_send and a websocket_ping, and a documented way to turn on debug mode.
What is missing from that list is as informative as what is in it. There is no session object, no proxy handling, no retry decorator, no authentication helper, no streaming response and no async client in the documented surface. That is not an oversight, it is the design: the comparison table lists the dependencies of the other libraries as seven or more for requests, against zero for this one, and the whole argument is that a small script should not carry a dependency tree.
The comparison table also puts the library at one file and 999 lines of code, measured with the CLOC tool, with a single developer behind it against hundreds for the established libraries.
The benchmark table and exactly what it measured
The readme leads with a comparison table, and the notes under it are specific enough to be useful.
The speed column is the real time taken to complete 10000 HTTP local requests, so this is a loopback benchmark rather than a test against a remote server, which means it measures client overhead and connection handling rather than network latency. The figures are 152.39 for PyWGET, 15.58 for requests, 5.50 for requests with a cached object, 4.00 for urllib, 3.55 for urllib3, 0.75 for PyCurl, 0.68 for PyCurl without SSL, and 0.40 for faster-than-requests.
The conditions are stated as well: the benchmarks were run on Docker using the Dockerfile in the repository, on an x86_64 64-bit AMD machine with an SSD running Arch Linux, and the statistics are as of the year 2020.
That date matters. These are the author's own numbers, produced on his own machine, with his own harness, and the table has not been refreshed in the years since, even though the repository has seen commits more recently. The comparison is not a neutral benchmark, and a reader should treat it as a claim rather than as evidence. What the table does show clearly is the shape of the trade: a single file with no dependencies and no pooling is faster in a tight local loop than a general purpose library that does connection management.
The columns on websockets and on a built-in multi-threaded web scraper are also worth reading, because they are the two capabilities that the established libraries in the table do not have, and they are the two reasons to look at this project at all.
Seven scraper functions, which is the unusual part
The scraper family is what separates this from a plain HTTP client, and it is the reason the project is interesting beyond the benchmark.
There are seven numbered scraper functions, and the naming shows the progression. The scraper function takes a list of URLs and a threads flag, and it is the multi-threaded web scraper that the comparison table highlights, with a one-line example linked in the repository. The scraper2 through scraper4 functions occupy the middle of the range, and the readme's table of contents lists them without a detailed description in the visible text, which suggests the documentation for them is in the reference section rather than in the summary.
The last three are specific and self-explanatory. scraper5 takes a list of URLs and a path to a SQLite file, and it is a URL to SQLite scraper, which means you can point it at a list of pages and end up with a database rather than a pile of output. scraper6 takes a list of URLs and a regular expression, and it is the regex powered scraper. scraper7 takes a URL and a selector, and it is the CSS selector scraper.
The example set in the repository makes the same progression visible in file names: a multithread web scraper, a multitag scraper in two variants, a regex scraper, a SQLite web scraper, a CSS selector scraper, an image scraper, a download with retry example, a post file example, a multipart post example, and a websocket send and ping example. There is also a directory of numbered bug reports, which suggests the author treats the issues as a test corpus.
For a one-off data collection job, a scraper that takes a URL and a CSS selector and returns the matches is genuinely shorter than assembling the same thing with a requests session and a parsing library.
WebSockets and the zero dependency claim
The websocket support is listed as one of the two capabilities the other libraries in the comparison table lack, and it is implemented with the same request and response functions.
requests.websocket_send("ws://echo.websocket.org", "data here")The send function takes binary or text, the readme says, and the ping function is the keepalive counterpart. A websocket client inside a package with zero dependencies means the handshake, the framing and the masking are implemented in the same file as the HTTP code, which is the only way to keep the dependency count at zero.
That is the trade-off of this project in one place. You get a small surface, no installation friction, and a fast enough client for scripts, in exchange for implementing the protocol yourself. The comparison table lists the cost of the alternative: requests pulls in more than twenty files and more than 2500 lines with at least seven dependencies, and urllib3 is over forty files and more than 5200 lines.
Whether that trade is right depends entirely on the job. A service that talks to a remote API, handles authentication, retries on failure and manages connection pools wants the mature library. A script that fetches a few pages, parses them and exits wants the single file, and a container image that ships a hundred of those scripts wants zero dependencies more than it wants anything else.
Packaging, the examples directory and the CI setup
The repository layout shows a project that treats distribution as a first class concern, which is unusual for something whose headline is that it has no dependencies.
There is a dist directory, a docker directory used for the benchmarks, an upload2pypi.sh script and a package4pypi.sh script, so the release to PyPI is scripted rather than manual. The package is published on PyPI and the readme links the install section, along with a Windows section, a FAQ, a get help page pointing at the issue tracker, the GitHub Actions workflow for Python, and an examples directory.
That examples directory is worth more attention than it usually gets. It holds more than twenty files, and the names map onto the features: example, example2, example3 and example4, a head request example, an image scraper, a multitag web scraper in two versions, a multithread web scraper, a post with a file, a multipart post, a regex scraper, a SQLite web scraper, a CSS selector web scraper, websocket send and websocket ping, and a download with retry.
The download with retry example is interesting, because retry is not in the function list at all. That suggests the retry behaviour is something you write in your own loop rather than something the library provides, which is the sort of detail that decides whether the library fits your problem.
The repository also has a code of conduct, a contributing guide, a tests directory, a docs directory, an img directory and a licence file, and the primary language listed for the project is Nim rather than Python, which points to a compiled component somewhere in the tree rather than to a pure Python implementation of the whole package.
A 1.0.0 from 2020 and commits in 2026
The release history is the weak point, and it is better to say so plainly than to work around it.
There are three tagged releases: 0.9.2 on 2019-12-01, 0.9.6 on 2019-12-24 and 1.0.0 on 2020-07-21. The last push to the repository was on 2026-10-06 and the project is not archived, so commits have continued in the years since the 1.0 tag, but the version on PyPI is the one from 2020 unless the author has published something outside the tag list.
The readme also carries a maintenance badge that claims maintenance from 2022, which is another sign that the visible project metadata has not been kept in step with the commit history.
What this means in practice is that the benchmark table, the documentation and the release you install are all from 2020, and the commits since then are not visible in a version number. If you install from PyPI, you get the 2020 code. If you install from the repository, you get something newer that no tag marks, and you have to read the changelog yourself to see what changed.
The licence is MIT, and the homepage is a personal gist rather than a project site, which is another sign of a project that grew out of an experiment with a following rather than out of an organisation's roadmap. The pragmatic advice is to read the function list carefully against what your code needs, since the library is small enough that you can read its source, and to test it against the endpoints you actually use before you depend on it.
Editorial conclusion
faster-than-requests fits a script that makes a handful of HTTP calls, wants no dependency to install, and does not need the session, proxy and retry machinery that comes with requests. It is a poor fit for anything that depends on the wider requests ecosystem, on connection pooling behaviour you can reason about, or on a maintained stream of upstream fixes, since the last tagged release is 1.0.0 from 2020 while the repository has seen commits as recently as 2026-10-06. Before you depend on it, read the function list for the features you actually use, and run the same requests against your real endpoints to see whether the response objects behave the way your code expects.
Frequently asked questions
How do I install faster-than-requests?
The package is published on PyPI and the readme links its own installation section, along with the project page and a Windows specific section. The repository also contains upload and packaging scripts for PyPI, so the published artefact comes from the same tree.
Is faster-than-requests a drop-in replacement for requests?
It is designed to be used as one, since the documented usage is to import faster_than_requests as requests and then call get, post and the rest. The import alias matters, because the library also exposes functions that requests does not, including the numbered scraper functions and the websocket helpers.
What do the speed numbers in the comparison table mean?
The speed column is the real time taken to complete 10000 HTTP local requests, with the benchmarks run on Docker from the repository's own Dockerfile, on an x86_64 64-bit AMD machine with an SSD running Arch Linux. The table states that the statistics are as of the year 2020.
Does faster-than-requests support WebSockets?
Yes, and it is one of the two capabilities the comparison table marks as absent from the other libraries. The package exposes websocket_send for binary or text payloads and websocket_ping, and it does so without any third party dependency.
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/juancarlospaco-faster-than-requests)Was this useful?