Package: asyncwhois
asyncwhoisasyncwhois| Python utility for WHOIS and RDAP queries.Quickstartimportasynciofrompprintimportpprintimportasyncwhois# pick a domaindomain='bitcoin.org'# domain could also be a URL; asyncwhois uses tldextract to parse the URLdomain='https://www.google.com?q=asyncwhois'# basic examplequery_string,parsed_dict=asyncwhois.whois(domain)# query_string  # The semi-free text output from the whois server# parsed_dict   # A dictionary of key:values extracted from `query_string`# asyncio exampleloop=asyncio.get_event_loop()query_string,parsed_dict=loop.run_until_complete(asyncwhois.aio_whois(domain))pprint(parsed_dict)"""{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)}..."""# support for IPv4, IPv6, and ASNs tooipv4="8.8.8.8"query_string,parsed_dict=asyncwhois.whois(ipv4)pprint(parsed_dict)"""{abuse_address: None,abuse_email: 'network-abuse@google.com',abuse_handle: 'ABUSE5250-ARIN',abuse_name: 'Abuse',abuse_phone: '+1-650-253-0000',abuse_rdap_ref: 'https://rdap.arin.net/registry/entity/ABUSE5250-ARIN',cidr: '8.8.8.0/24',net_handle: 'NET-8-8-8-0-2',net_name: 'GOGL',net_range: '8.8.8.0 - 8.8.8.255',net_type: 'Direct Allocation',org_address: '1600 Amphitheatre Parkway',org_city: 'Mountain View',org_country: 'US',org_id: 'GOGL',..."""RDAPThewhodapproject is used behind the scenes to perform RDAP queries.domain="https://google.com"query_string,parsed_dict=asyncwhois.rdap(domain)# OR with asyncioquery_string,parsed_dict=loop.run_until_complete(asyncwhois.aio_rdap(domain))# Reusable client (caches the RDAP bootstrap server list, so it is faster for doing multiple calls)client=asyncwhois.DomainClient()fordomainin["google.com","tesla.coffee","bitcoin.org"]:query_string,parsed_dict=client.rdap(domain)# query_string, parsed_dict = await client.aio_rdap(domain)# Using a proxy or need to configure something HTTP related? Try reconfiguring the client:whodap_client=whodap.DNSClient.new_client(httpx_client=httpx.Client(proxies="https://proxy:8080"))# whodap_client = await whodap.DNSClient.new_aio_client(httpx_client=httpx.AsyncClient(proxies="https://proxy:8080"))client=asyncwhois.DomainClient(whodap_client=whodap_client)Using ProxiesSOCKS4 and SOCKS5 proxies are supported for WHOIS and RDAP queries.importwhodaptor_host="localhost"tor_port=9050# WHOISquery_string,parsed_dict=asyncwhois.whois("8.8.8.8",proxy_url=f"socks5://{tor_host}:{tor_port}")# RDAPimporthttpxfromhttpx_socksimportSyncProxyTransport,AsyncProxyTransport# EXTERNAL DEPENDENCY for SOCKS Proxiestransport=SyncProxyTransport.from_url(f"socks5://{tor_host}:{tor_port}")httpx_client=httpx.Client(transport=transport)whodap_client=whodap.IPv6Client.new_client(httpx_client=httpx_client)query_string,parsed_dict=asyncwhois.rdap('2001:4860:4860::8888',whodap_client=whodap_client)transport=AsyncProxyTransport.from_url(f"socks5://{tor_user}:{tor_pw}@{tor_host}:{tor_port}")asyncwithhttpx.AsyncClient(transport=transport)ashttpx_client:whodap_client=awaitwhodap.DNSClient.new_aio_client(httpx_client=httpx_client)query_string,parsed_dict=awaitasyncwhois.aio_rdap('bitcoin.org',whodap_client=whodap_client)Exported FunctionsFunction/ObjectDescriptionDomainClientReusable client for  WHOIS or RDAP domain queriesNumberClientReusable client for WHOIS or RDAP ipv4/ipv6 queriesASNClientReusable client for RDAP asn querieswhoisWHOIS entrypoint for domain, ipv4, or ipv6 queriesrdapRDAP entrypoint for domain, ipv4, ipv6, or asn queriesaio_whoisasync counterpart towhoisaio_rdapasync counterpart tordapwhois_ipv4[DEPRECATED] WHOIS lookup for ipv4 addresseswhois_ipv6[DEPRECATED] WHOIS lookup for ipv6 addressesrdap_domain[DEPRECATED] RDAP lookup for domain namesrdap_ipv4[DEPRECATED] RDAP lookup for ipv4 addressesrdap_ipv6[DEPRECATED] RDAP lookup for ipv6 addressesrdap_asn[DEPRECATED] RDAP lookup for Autonomous System Numbersaio_whois_domain[DEPRECATED] async counterpart towhois_domainaio_whois_ipv4[DEPRECATED] async counterpart towhois_ipv4aio_whois_ipv6[DEPRECATED] async counterpart towhois_ipv6aio_rdap_domain[DEPRECATED] async counterpart tordap_domainaio_rdap_ipv4[DEPRECATED] async counterpart tordap_ipv4aio_rdap_ipv6[DEPRECATED]  async counterpart tordap_ipv6aio_rdap_asn[DEPRECATED] async counterpart tordap_asnContributionsParsed output not what you expected? Unfortunately, "the format of responses [from a WHOIS server] follow a semi-free text format". Therefore,
situations will arise where this module does not support parsing the output from 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.beStatus:NOTAVAILABLERegistered:TueDec122000Registrant:Notshown,pleasevisitwww.dnsbelgium.beforwebbasedwhois.RegistrarTechnicalContacts:Organisation:MarkMonitorInc.Language:enPhone:+1.2083895740Fax:+1.2083895771Registrar:Name:MarkMonitorInc.Website:http://www.markmonitor.comNameservers:ns2.google.comns1.google.comns4.google.comns3.google.comKeys: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:classRegexBE(BaseParser):_be_expressions={# the base class (BaseParser) will handle these regexesBaseKeys.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)defparse(self,blob:str)->Dict[str,Any]:# run base class parsing for other keysparsed_output=super().parse(blob)# custom parsing is needed to extract all the name serversns_match=re.search(r"Name servers: *(.+)Keys: ",blob,re.DOTALL)ifns_match:parsed_output[BaseKeys.NAME_SERVERS]=[m.strip()forminns_match.group(1).split('\n')ifm.strip()]returnparsed_output