Skip to main content

asyncio-compatible Python module for performing WHOIS queries for any domain.

Project description

https://badge.fury.io/py/asyncwhois.svg https://travis-ci.com/pogzyb/asyncwhois.svg?branch=master https://codecov.io/gh/pogzyb/asyncwhois/branch/master/graph/badge.svg

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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

asyncwhois-0.3.0.tar.gz (32.9 kB view hashes)

Uploaded Source

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page