asyncio-compatible Python module for performing WHOIS queries for any domain.
Project description
asyncwhois
asyncio-compatible Python module for performing WHOIS queries for any domain.
Installation
pip install asyncwhois
Quickstart
# Connects to the appropriate WhoIs server, submits a query, and parses the output.
result = asyncwhois.lookup('google.com')
# [for asyncio] result = await asyncwhois.aio_lookup('google.com')
result.query_output # raw output from the whois server
result.parser_output # dictionary of key/values extracted from query_output
# Equivalent to running "whois <domain>" from the shell. Uses the "subprocess" package.
result = asyncwhois.whois_cmd_shell('google.com')
# [for asyncio] result = await asyncwhois.aio_whois_cmd_shell('google.com')
result.query_output # raw output from the whois server
result.parser_output # dictionary of key/values extracted from query_output
Examples
standard
from pprint import pprint
import asyncwhois
result = asyncwhois.lookup('bitcoin.org')
pprint(result.parser_output)
>>> {created: datetime.datetime(2008, 8, 18, 13, 19, 55),
dnssec: 'unsigned',
domain_name: 'bitcoin.org',
expires: datetime.datetime(2029, 8, 18, 13, 19, 55),
name_servers: ['dns1.registrar-servers.com', 'dns2.registrar-servers.com'],
registrant_address: 'P.O. Box 0823-03411',
registrant_city: 'Panama',
registrant_country: 'PA',
registrant_name: 'WhoisGuard Protected',
registrant_organization: 'WhoisGuard, Inc.',
registrant_state: 'Panama',
registrant_zipcode: '',
registrar: 'NAMECHEAP INC',
status: ['clientTransferProhibited '
'https://icann.org/epp#clientTransferProhibited'],
updated: datetime.datetime(2019, 11, 24, 13, 58, 35, 940000)}
bulk standard
import asyncwhois
def main():
urls = [
'www.google.co.uk',
'en.wikipedia.org/wiki/Pi',
'https://twitch.tv',
'https://www.bing.com/search?q=llama',
'agar.io',
'172.217.3.110'
]
for url in urls:
asyncwhois.lookup(url)
if __name__ == '__main__':
main()
bulk asyncio
import asyncio
import asyncwhois
async def main():
urls = [
'www.google.co.uk',
'en.wikipedia.org/wiki/Pi',
'https://twitch.tv',
'https://www.bing.com/search?q=llama',
'agar.io',
'172.217.3.110'
]
tasks = []
for url in urls:
awaitable = asyncwhois.aio_lookup(url)
tasks.append(awaitable)
await asyncio.gather(*tasks)
if __name__ == '__main__':
asyncio.run(main())
Contributions
Unfortunately, “the format of responses [from a Whois server] follow a semi-free text format”. This means that situations will arise where this module does not support parsing the output of a specific server, and you may find yourself needing more control over how parsing happens. Fortunately, you can create customized parsers to suit your needs.
Example: This is a snippet of the output from running the “whois google.be” command.
Domain: google.be
Status: NOT AVAILABLE
Registered: Tue Dec 12 2000
Registrant:
Not shown, please visit www.dnsbelgium.be for webbased whois.
Registrar Technical Contacts:
Organisation: MarkMonitor Inc.
Language: en
Phone: +1.2083895740
Fax: +1.2083895771
Registrar:
Name: MarkMonitor Inc.
Website: http://www.markmonitor.com
Nameservers:
ns2.google.com
ns1.google.com
ns4.google.com
ns3.google.com
Keys:
Flags:
clientTransferProhibited
...
In this case, the “name servers” are listed on separate lines. The default BaseParser regexes won’t find all of these server names. In order to accommodate this extra step, the “parse” method was overwritten within the parser subclass as seen below:
class RegexBE(BaseParser):
_be_expressions = { # the base class (BaseParser) will handle these regexes
BaseKeys.CREATED: r'Registered: *(.+)',
BaseKeys.REGISTRAR: r'Registrar:\n.+Name: *(.+)',
BaseKeys.REGISTRANT_NAME: r'Registrant:\n *(.+)'
}
def __init__(self):
super().__init__()
self.update_reg_expressions(self._be_expressions)
def parse(self, blob: str) -> Dict[str, Any]: # custom parsing is needed to extract all the name servers
parsed_output = super().parse(blob) # run normal parsing for other keys
ns_match = re.search(r"Name servers: *(.+)Keys: ", blob, re.DOTALL) # custom parsing for name servers
if ns_match:
parsed_output[BaseKeys.NAME_SERVERS] = [m.strip() for m in ns_match.group(1).split('\n') if m.strip()]
return parsed_output
...
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.