WHOIS lookup and parsing library with CLI support
Project description
pywhois2
pywhois2 is a Python WHOIS library and CLI.
It queries WHOIS servers directly and parses the response with ttp-based text templates.
This project is aimed at TLDs whose WHOIS formats differ enough that template-driven parsing is easier to maintain than a single generic parser.
Features
- Direct WHOIS queries for domains, hosts, and IP addresses
- Template-based parsing under
pywhois2/templates/ - Support for localized WHOIS output, including
.jpand related second-level domains - JSON-friendly CLI output
- Packaged for modern Python and automated GitHub Actions releases
Current state
The project is usable, but still evolving.
- Some TLDs still rely on generic fallback templates
- Historical or unassigned TLDs are intentionally left without active WHOIS definitions
- WHOIS output formats can change without notice, so templates may need periodic updates
Installation
Install from PyPI:
pip install pywhois2
Install from a local checkout:
git clone https://github.com/blacknon/pywhois2
cd pywhois2
pip install .
Command line usage
Query a domain and print compact JSON:
pywhois2 mynavi.jp
Pretty-print the result:
pywhois2 --pretty mynavi.co.jp
Show the installed version:
pywhois2 --version
If the registry returns a clear no-match response, pywhois2 returns JSON instead of raising an exception:
$ pywhois2 osrebibou123456789.com
{"domain_name":"osrebibou123456789.com","status_text":"No match for \"OSREBIBOU123456789.COM\".","available":true,"parser_note":"Generic no-match response"}
Detailed example:
$ pywhois2 --pretty mynavi.jp
{
"contact_zip_code": "100-0003",
"contact_email": "nic@mynavi.jp",
"contact_name": "Mynavi Corporation",
"contact_name_local": "株式会社マイナビ",
"updated": "2026/03/10 15:02:12 +0900",
"status": {
"ok": true,
"hold": false,
"to_be_suspended": false,
"suspended": false
},
"expiration": "2027/02/28 00:00:00 +0900",
"creation": "2007/02/10 00:00:00 +0900",
"registrant_name": "Mynavi Corporation",
"registrant_name_local": "株式会社マイナビ",
"domain_name": "mynavi.jp",
"name_servers": [
"ns-884.awsdns-46.net",
"ns-1231.awsdns-25.org",
"ns-226.awsdns-28.com",
"ns-1786.awsdns-31.co.uk"
],
"status_text": "Active",
"contact_address": "1-1-1, Hitotsubashi, Chiyoda-ku, Tokyo 100-0003",
"contact_fax": "03-6267-4013",
"contact_phone": "03-6267-4129",
"contact_address_local": "東京都千代田区一ツ橋1-1-1 パレスサイドビル6F"
}
Another example, from the current parser output for mynavi.co.jp:
{
"updated": "2026/01/01 01:04:06 +0900",
"connected": "2011/12/01 00:00:00 +0900",
"creation": "2011/12/01 00:00:00 +0900",
"status": {
"ok": true,
"registered": false,
"connected": true,
"user_reserved": false,
"advance_registered": false,
"renamed": false,
"to_be_deleted": false,
"deleted": false,
"negotiated": false
},
"tech_name": "AT106JP",
"registrant_name": "MI13396JP",
"registrant_organization_type": "Corporation",
"registrant_organization_type_local": "株式会社",
"registrant_organization": "Mynavi Support Corporation",
"registrant_organization_local": "株式会社マイナビサポート",
"registrant_organization_local2": "かぶしきがいしゃまいなびさぽーと",
"domain_name": "mynavi.co.jp",
"name_servers": [
"ns-687.awsdns-21.net",
"ns-1295.awsdns-33.org",
"ns-463.awsdns-57.com",
"ns-1892.awsdns-44.co.uk"
],
"status_text": "Connected (2026/12/31)",
"created": "2011/12/01 00:00:00 +0900"
}
Current parser output for google.co.kr:
{
"registrar_name": "Whois Corp.(http://whois.co.kr)",
"publish_status": "Y",
"expiration": "2026/07/28 00:00:00 +0900",
"updated": "2010/10/04 00:00:00 +0900",
"creation": "1999/07/28 00:00:00 +0900",
"admin_phone": "82.25319000",
"admin_email": "dns-admin@google.com",
"admin_name": "Domain Administrator",
"registrant_zip_code": "135984",
"registrant_address": "22nd Floor Gangnam Finance Center 737, Yeoksam-dong Kangnam-ku Seoul",
"registrant_name": "Google Korea, LLC",
"domain_name": "google.co.kr",
"registrar_name_local": "(주)후이즈(http://whois.co.kr)",
"admin_name_local": "Domain Administrator",
"registrant_address_local": "서울시 강남구 역삼동 737 강남파이낸스센터 22층",
"registrant_name_local": "구글코리아유한회사",
"dnssec": "unsigned",
"name_servers": [
"ns1.google.com",
"ns2.google.com",
"ns3.google.com",
"ns4.google.com"
],
"created": "1999/07/28 00:00:00 +0900"
}
Library usage
import json
import datetime
from pywhois2 import Whois
def json_serial(obj):
if isinstance(obj, (datetime.datetime, datetime.date)):
return obj.strftime("%Y/%m/%d %H:%M:%S %z")
raise TypeError("Type %s not serializable" % type(obj))
whois = Whois("mynavi.co.jp")
result = whois.get()
print(json.dumps(result, default=json_serial, ensure_ascii=False, indent=2))
Template-based parsing
Parsing is driven by template files in pywhois2/templates.
That makes it easier to add support for new WHOIS formats or refine existing parsers incrementally.
For compatibility with older template output, some parsers expose both creation and created when the upstream template historically used created.
If you want to inspect template coverage:
python3 scripts/audit_templates.py
The current inventory is tracked in TEMPLATE_COVERAGE.md.
You can also experiment with a raw WHOIS response and a template directly with ttp:
$ ttp -d ./tests/fixtures/jp_whois.txt -t ./pywhois2/templates/jp.tpl -o raw
[{'contact_zip_code': '101-0065', 'contact_email': 'email@jprs.co.jp', 'contact_name': 'Japan Registry Services Co.,Ltd.', 'updated': datetime.datetime(2026, 3, 1, 1, 5, 3, tzinfo=datetime.timezone(datetime.timedelta(seconds=32400))), 'expiration': datetime.datetime(2027, 2, 28, 0, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=32400))), 'creation': datetime.datetime(2001, 2, 2, 0, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=32400))), 'registrant_name': 'Japan Registry Services Co.,Ltd.', 'domain_name': 'jprs.jp', 'name_servers': ['ns1.jprs.jp', 'ns2.jprs.jp', 'ns3.jprs.jp', 'ns4.jprs.jp'], 'dns_keys': ['7240 8 2'], 'status_text': 'Active', 'status': {'ok': True, 'hold': False, 'to_be_suspended': False, 'suspended': False}, 'contact_address': 'Tokyo, Chiyoda-ku, Chiyoda First Bldg. East, 3-8-1 Nishi-Kanda, Japan', 'contact_fax': '03-5215-8452', 'contact_phone': '03-5215-8451'}]
And for the organizational .jp templates:
$ ttp -d ./tests/fixtures/co_jp_whois.txt -t ./pywhois2/templates/xx.jp.tpl -o raw
[{'updated': datetime.datetime(2026, 2, 1, 1, 2, 4, tzinfo=datetime.timezone(datetime.timedelta(seconds=32400))), 'connected': datetime.datetime(2001, 1, 24, 0, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=32400))), 'creation': datetime.datetime(2001, 1, 22, 0, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=32400))), 'status_text': 'Connected (2027/01/31)', 'status': {'ok': True, 'registered': False, 'connected': True, 'user_reserved': False, 'advance_registered': False, 'renamed': False, 'to_be_deleted': False, 'deleted': False, 'negotiated': False}, 'signing_key': '63574 8 2', 'tech_name': 'KI59866JP', 'registrant_name': 'SO42861JP', 'registrant_organization_type': 'Company', 'registrant_organization': 'Japan Registry Services Co.,Ltd.', 'domain_name': 'jprs.co.jp', 'name_servers': ['ns1.jprs.co.jp', 'ns2.jprs.co.jp', 'ns3.jprs.co.jp', 'ns4.jprs.co.jp'], 'lock_status': ['AgentChangeLocked']}]
Development
Run the test suite locally:
python3 -m unittest discover -s tests -v
Run the same command set used by CI:
sh .github/scripts/run_ci.sh
Build the Docker test image:
docker build -t pywhois2-test .
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pywhois2-0.2.0.tar.gz.
File metadata
- Download URL: pywhois2-0.2.0.tar.gz
- Upload date:
- Size: 85.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
eeb132e7fde036bd4b3f3077e7e233a2bf9fb6a4dc78f34b2ca4fd1197410e43
|
|
| MD5 |
ac3077b7762bf71fe11fb5cccf18633d
|
|
| BLAKE2b-256 |
d2f95b77e761ab3ad43b3c8bd92f632df429e022b86a2031d2a1295aa037123c
|
Provenance
The following attestation bundles were made for pywhois2-0.2.0.tar.gz:
Publisher:
publish.yml on blacknon/pywhois2
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pywhois2-0.2.0.tar.gz -
Subject digest:
eeb132e7fde036bd4b3f3077e7e233a2bf9fb6a4dc78f34b2ca4fd1197410e43 - Sigstore transparency entry: 1340593740
- Sigstore integration time:
-
Permalink:
blacknon/pywhois2@6312bd73f044de3171ca3d2824f9cbba730e9324 -
Branch / Tag:
refs/heads/master - Owner: https://github.com/blacknon
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@6312bd73f044de3171ca3d2824f9cbba730e9324 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file pywhois2-0.2.0-py3-none-any.whl.
File metadata
- Download URL: pywhois2-0.2.0-py3-none-any.whl
- Upload date:
- Size: 251.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6ffaef5741b545fc7b3f9e1a01dc7c03b8f9da4bb7bf1457349f83a3d4eab89a
|
|
| MD5 |
9936edd02f1a502613d472f407ecad73
|
|
| BLAKE2b-256 |
24c31bdbf1b4a12a87747107644e34dde6d99e292b7fc3b5760022fb93d28bf2
|
Provenance
The following attestation bundles were made for pywhois2-0.2.0-py3-none-any.whl:
Publisher:
publish.yml on blacknon/pywhois2
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pywhois2-0.2.0-py3-none-any.whl -
Subject digest:
6ffaef5741b545fc7b3f9e1a01dc7c03b8f9da4bb7bf1457349f83a3d4eab89a - Sigstore transparency entry: 1340593743
- Sigstore integration time:
-
Permalink:
blacknon/pywhois2@6312bd73f044de3171ca3d2824f9cbba730e9324 -
Branch / Tag:
refs/heads/master - Owner: https://github.com/blacknon
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@6312bd73f044de3171ca3d2824f9cbba730e9324 -
Trigger Event:
workflow_dispatch
-
Statement type: