whois/parser.py
changeset 40 9573d5bc9ad5
parent 39 68375a768598
child 41 8772587c32a5
equal deleted inserted replaced
39:68375a768598 40:9573d5bc9ad5
    70     # child classes will override this
    70     # child classes will override this
    71     _regex = {
    71     _regex = {
    72         'domain_name':      'Domain Name:\s?(.+)',
    72         'domain_name':      'Domain Name:\s?(.+)',
    73         'registrar':        'Registrar:\s?(.+)',
    73         'registrar':        'Registrar:\s?(.+)',
    74         'whois_server':     'Whois Server:\s?(.+)',
    74         'whois_server':     'Whois Server:\s?(.+)',
    75         'referral_url':     'Referral URL:\s?(.+)', # http url of whois_server
    75         'referral_url':     'Referral URL:\s?(.+)',  # http url of whois_server
    76         'updated_date':     'Updated Date:\s?(.+)',
    76         'updated_date':     'Updated Date:\s?(.+)',
    77         'creation_date':    'Creation Date:\s?(.+)',
    77         'creation_date':    'Creation Date:\s?(.+)',
    78         'expiration_date':  'Expir\w+ Date:\s?(.+)',
    78         'expiration_date':  'Expir\w+ Date:\s?(.+)',
    79         'name_servers':     'Name Server:\s?(.+)', # list of name servers
    79         'name_servers':     'Name Server:\s?(.+)',  # list of name servers
    80         'status':           'Status:\s?(.+)', # list of statuses
    80         'status':           'Status:\s?(.+)',  # list of statuses
    81         'emails':           '[\w.-]+@[\w.-]+\.[\w]{2,4}', # list of email addresses
    81         'emails':           '[\w.-]+@[\w.-]+\.[\w]{2,4}',  # list of email s
    82         'dnssec':           'dnssec:\s*([\S]+)',
    82         'dnssec':           'dnssec:\s*([\S]+)',
    83     }
    83     }
    84 
    84 
    85     def __init__(self, domain, text, regex=None):
    85     def __init__(self, domain, text, regex=None):
    86         self.domain = domain
    86         self.domain = domain
    87         self.text = text
    87         self.text = text
    88         if regex is not None:
    88         if regex is not None:
    89             self._regex = regex
    89             self._regex = regex
    90 
       
    91 
    90 
    92     def __getattr__(self, attr):
    91     def __getattr__(self, attr):
    93         """The first time an attribute is called it will be calculated here.
    92         """The first time an attribute is called it will be calculated here.
    94         The attribute is then set to be accessed directly by subsequent calls.
    93         The attribute is then set to be accessed directly by subsequent calls.
    95         """
    94         """
   114             raise AttributeError('Unknown attribute: %s' % attr)
   113             raise AttributeError('Unknown attribute: %s' % attr)
   115 
   114 
   116     def __str__(self):
   115     def __str__(self):
   117         """Print all whois properties of domain
   116         """Print all whois properties of domain
   118         """
   117         """
   119         return '\n'.join('%s: %s' % (attr, str(getattr(self, attr))) for attr in self.attrs())
   118         return '\n'.join('%s: %s' % (attr, str(getattr(self, attr)))
   120 
   119                          for attr in self.attrs())
   121 
   120 
   122     def __getstate__(self):
   121     def __getstate__(self):
   123         """To support pickling
   122         """To support pickling
   124         """
   123         """
   125         return self.__dict__
   124         return self.__dict__
   126 
   125 
   127     def __setstate__(self, state):
   126     def __setstate__(self, state):
   128         self.__dict__ = state
   127         self.__dict__ = state
   129 
   128 
   130 
       
   131     def attrs(self):
   129     def attrs(self):
   132         """Return list of attributes that can be extracted for this domain
   130         """Return list of attributes that can be extracted for this domain
   133         """
   131         """
   134         return sorted(self._regex.keys())
   132         return sorted(self._regex.keys())
   135 
   133 
   136 
       
   137     @staticmethod
   134     @staticmethod
   138     def load(domain, text):
   135     def load(domain, text):
   139         """Given whois output in ``text``, return an instance of ``WhoisEntry`` that represents its parsed contents.
   136         """Given whois output in ``text``, return an instance of ``WhoisEntry``
       
   137         that represents its parsed contents.
   140         """
   138         """
   141         if text.strip() == 'No whois server is known for this kind of object.':
   139         if text.strip() == 'No whois server is known for this kind of object.':
   142             raise PywhoisError(text)
   140             raise PywhoisError(text)
   143 
   141 
   144         if domain.endswith('.com'):
   142         if domain.endswith('.com'):
   146         elif domain.endswith('.net'):
   144         elif domain.endswith('.net'):
   147             return WhoisNet(domain, text)
   145             return WhoisNet(domain, text)
   148         elif domain.endswith('.org'):
   146         elif domain.endswith('.org'):
   149             return WhoisOrg(domain, text)
   147             return WhoisOrg(domain, text)
   150         elif domain.endswith('.name'):
   148         elif domain.endswith('.name'):
   151         	return WhoisName(domain, text)
   149             return WhoisName(domain, text)
   152         elif domain.endswith('.me'):
   150         elif domain.endswith('.me'):
   153         	return WhoisMe(domain, text)
   151             return WhoisMe(domain, text)
   154         elif domain.endswith('.au'):
   152         elif domain.endswith('.au'):
   155             return WhoisAU(domain, text)
   153             return WhoisAU(domain, text)
   156         elif domain.endswith('.ru'):
   154         elif domain.endswith('.ru'):
   157             return WhoisRu(domain, text)
   155             return WhoisRu(domain, text)
   158         elif domain.endswith('.us'):
   156         elif domain.endswith('.us'):
   159         	return WhoisUs(domain, text)
   157             return WhoisUs(domain, text)
   160         elif domain.endswith('.uk'):
   158         elif domain.endswith('.uk'):
   161         	return WhoisUk(domain, text)
   159             return WhoisUk(domain, text)
   162         elif domain.endswith('.fr'):
   160         elif domain.endswith('.fr'):
   163             return WhoisFr(domain, text)
   161             return WhoisFr(domain, text)
   164         elif domain.endswith('.fi'):
   162         elif domain.endswith('.fi'):
   165         	return WhoisFi(domain, text)
   163             return WhoisFi(domain, text)
   166         elif domain.endswith('.jp'):
   164         elif domain.endswith('.jp'):
   167             return WhoisJp(domain, text)
   165             return WhoisJp(domain, text)
   168         elif domain.endswith('.pl'):
   166         elif domain.endswith('.pl'):
   169             return WhoisPl(domain, text)
   167             return WhoisPl(domain, text)
   170         elif domain.endswith('.br'):
   168         elif domain.endswith('.br'):
   181             return WhoisRf(domain, text)
   179             return WhoisRf(domain, text)
   182         else:
   180         else:
   183             return WhoisEntry(domain, text)
   181             return WhoisEntry(domain, text)
   184 
   182 
   185 
   183 
   186 
       
   187 class WhoisCom(WhoisEntry):
   184 class WhoisCom(WhoisEntry):
   188     """Whois parser for .com domains
   185     """Whois parser for .com domains
   189     """
   186     """
   190     def __init__(self, domain, text):
   187     def __init__(self, domain, text):
   191         if 'No match for "' in text:
   188         if 'No match for "' in text:
   192             raise PywhoisError(text)
   189             raise PywhoisError(text)
   193         else:
   190         else:
   194             WhoisEntry.__init__(self, domain, text) 
   191             WhoisEntry.__init__(self, domain, text)
   195 
   192 
   196 
   193 
   197 class WhoisNet(WhoisEntry):
   194 class WhoisNet(WhoisEntry):
   198     """Whois parser for .net domains
   195     """Whois parser for .net domains
   199     """
   196     """
   200     def __init__(self, domain, text):
   197     def __init__(self, domain, text):
   201         if 'No match for "' in text:
   198         if 'No match for "' in text:
   202             raise PywhoisError(text)
   199             raise PywhoisError(text)
   203         else:
   200         else:
   204             WhoisEntry.__init__(self, domain, text) 
   201             WhoisEntry.__init__(self, domain, text)
   205 
   202 
   206 
   203 
   207 class WhoisOrg(WhoisEntry):
   204 class WhoisOrg(WhoisEntry):
   208     """Whois parser for .org domains
   205     """Whois parser for .org domains
   209     """
   206     """
   210     def __init__(self, domain, text):
   207     def __init__(self, domain, text):
   211         if text.strip() == 'NOT FOUND':
   208         if text.strip() == 'NOT FOUND':
   212             raise PywhoisError(text)
   209             raise PywhoisError(text)
   213         else:
   210         else:
   214             WhoisEntry.__init__(self, domain, text) 
   211             WhoisEntry.__init__(self, domain, text)
   215 
   212 
   216 
   213 
   217 class WhoisRu(WhoisEntry):
   214 class WhoisRu(WhoisEntry):
   218     """Whois parser for .ru domains
   215     """Whois parser for .ru domains
   219     """
   216     """
   236 
   233 
   237 class WhoisName(WhoisEntry):
   234 class WhoisName(WhoisEntry):
   238     """Whois parser for .name domains
   235     """Whois parser for .name domains
   239     """
   236     """
   240     regex = {
   237     regex = {
   241     	'domain_name_id':  'Domain Name ID:\s*(.+)',
   238         'domain_name_id':  'Domain Name ID:\s*(.+)',
   242         'domain_name':     'Domain Name:\s*(.+)',
   239         'domain_name':     'Domain Name:\s*(.+)',
   243         'registrar_id':    'Sponsoring Registrar ID:\s*(.+)',
   240         'registrar_id':    'Sponsoring Registrar ID:\s*(.+)',
   244         'registrar':       'Sponsoring Registrar:\s*(.+)',
   241         'registrar':       'Sponsoring Registrar:\s*(.+)',
   245         'registrant_id':   'Registrant ID:\s*(.+)',
   242         'registrant_id':   'Registrant ID:\s*(.+)',
   246         'admin_id':        'Admin ID:\s*(.+)',
   243         'admin_id':        'Admin ID:\s*(.+)',
   250         'expiration_date': 'Expires On:\s*(.+)',
   247         'expiration_date': 'Expires On:\s*(.+)',
   251         'updated_date':    'Updated On:\s*(.+)',
   248         'updated_date':    'Updated On:\s*(.+)',
   252         'name_server_ids': 'Name Server ID:\s*(.+)',  # list of name server ids
   249         'name_server_ids': 'Name Server ID:\s*(.+)',  # list of name server ids
   253         'name_servers':    'Name Server:\s*(.+)',  # list of name servers
   250         'name_servers':    'Name Server:\s*(.+)',  # list of name servers
   254         'status':          'Domain Status:\s*(.+)',  # list of statuses
   251         'status':          'Domain Status:\s*(.+)',  # list of statuses
   255 	}
   252     }
       
   253 
   256     def __init__(self, domain, text):
   254     def __init__(self, domain, text):
   257         if 'No match.' in text:
   255         if 'No match.' in text:
   258             raise PywhoisError(text)
   256             raise PywhoisError(text)
   259         else:
   257         else:
   260             WhoisEntry.__init__(self, domain, text, self.regex) 
   258             WhoisEntry.__init__(self, domain, text, self.regex)
   261     
   259 
   262         
   260 
   263 class WhoisUs(WhoisEntry):
   261 class WhoisUs(WhoisEntry):
   264     """Whois parser for .us domains
   262     """Whois parser for .us domains
   265     """
   263     """
   266     regex = {
   264     regex = {
   267         'domain_name':                    'Domain Name:\s*(.+)',
   265         'domain_name':                    'Domain Name:\s*(.+)',
   268     	'domain__id':                     'Domain ID:\s*(.+)',
   266         'domain__id':                     'Domain ID:\s*(.+)',
   269         'registrar':                      'Sponsoring Registrar:\s*(.+)',
   267         'registrar':                      'Sponsoring Registrar:\s*(.+)',
   270         'registrar_id':                   'Sponsoring Registrar IANA ID:\s*(.+)',
   268         'registrar_id':                   'Sponsoring Registrar IANA ID:\s*(.+)',
   271         'registrar_url':                  'Registrar URL \(registration services\):\s*(.+)',        
   269         'registrar_url':                  'Registrar URL \(registration services\):\s*(.+)',
   272         'status':                         'Domain Status:\s*(.+)',  # list of statuses
   270         'status':                         'Domain Status:\s*(.+)',  # list of statuses
   273         'registrant_id':                  'Registrant ID:\s*(.+)',
   271         'registrant_id':                  'Registrant ID:\s*(.+)',
   274         'registrant_name':                'Registrant Name:\s*(.+)',
   272         'registrant_name':                'Registrant Name:\s*(.+)',
   275         'registrant_address1':            'Registrant Address1:\s*(.+)',
   273         'registrant_address1':            'Registrant Address1:\s*(.+)',
   276         'registrant_address2':            'Registrant Address2:\s*(.+)',
   274         'registrant_address2':            'Registrant Address2:\s*(.+)',
   326         'created_by_registrar':           'Created by Registrar:\s*(.+)',
   324         'created_by_registrar':           'Created by Registrar:\s*(.+)',
   327         'last_updated_by_registrar':      'Last Updated by Registrar:\s*(.+)',
   325         'last_updated_by_registrar':      'Last Updated by Registrar:\s*(.+)',
   328         'creation_date':                  'Domain Registration Date:\s*(.+)',
   326         'creation_date':                  'Domain Registration Date:\s*(.+)',
   329         'expiration_date':                'Domain Expiration Date:\s*(.+)',
   327         'expiration_date':                'Domain Expiration Date:\s*(.+)',
   330         'updated_date':                   'Domain Last Updated Date:\s*(.+)',
   328         'updated_date':                   'Domain Last Updated Date:\s*(.+)',
   331 	}
   329     }
       
   330 
   332     def __init__(self, domain, text):
   331     def __init__(self, domain, text):
   333         if 'Not found:' in text:
   332         if 'Not found:' in text:
   334             raise PywhoisError(text)
   333             raise PywhoisError(text)
   335         else:
   334         else:
   336             WhoisEntry.__init__(self, domain, text, self.regex)
   335             WhoisEntry.__init__(self, domain, text, self.regex)
   337        
   336 
   338 
   337 
   339 class WhoisPl(WhoisEntry):
   338 class WhoisPl(WhoisEntry):
   340    """Whois parser for .pl domains
   339     """Whois parser for .pl domains
   341    """
   340     """
   342    regex = {
   341     regex = {
   343        'domain_name':                    'DOMAIN NAME:\s*(.+)\n',
   342         'domain_name':                    'DOMAIN NAME:\s*(.+)\n',
   344        'registrar':                      'REGISTRAR:\n\s*(.+)',
   343         'registrar':                      'REGISTRAR:\n\s*(.+)',
   345        'registrar_url':                  'URL:\s*(.+)',        # not available
   344         'registrar_url':                  'URL:\s*(.+)',        # not available
   346        'status':                         'Registration status:\n\s*(.+)',  # not available
   345         'status':                         'Registration status:\n\s*(.+)',  # not available
   347        'registrant_name':                'Registrant:\n\s*(.+)',   # not available
   346         'registrant_name':                'Registrant:\n\s*(.+)',   # not available
   348        'creation_date':                  'created:\s*(.+)\n',
   347         'creation_date':                  'created:\s*(.+)\n',
   349        'expiration_date':                'renewal date:\s*(.+)',
   348         'expiration_date':                'renewal date:\s*(.+)',
   350        'updated_date':                   'last modified:\s*(.+)\n',
   349         'updated_date':                   'last modified:\s*(.+)\n',
   351    }
   350     }
   352    def __init__(self, domain, text):
   351 
   353        if 'Not found:' in text:
   352     def __init__(self, domain, text):
   354            raise PywhoisError(text)
   353         if 'Not found:' in text:
   355        else:
   354             raise PywhoisError(text)
   356            WhoisEntry.__init__(self, domain, text, self.regex)
   355         else:
   357  
   356             WhoisEntry.__init__(self, domain, text, self.regex)
   358     
   357 
       
   358 
   359 class WhoisMe(WhoisEntry):
   359 class WhoisMe(WhoisEntry):
   360     """Whois parser for .me domains
   360     """Whois parser for .me domains
   361     """
   361     """
   362     regex = {
   362     regex = {
   363     	'domain_id':                   'Domain ID:(.+)',
   363         'domain_id':                   'Domain ID:(.+)',
   364         'domain_name':                 'Domain Name:(.+)',
   364         'domain_name':                 'Domain Name:(.+)',
   365         'creation_date':               'Domain Create Date:(.+)',
   365         'creation_date':               'Domain Create Date:(.+)',
   366         'updated_date':                'Domain Last Updated Date:(.+)',
   366         'updated_date':                'Domain Last Updated Date:(.+)',
   367         'expiration_date':             'Domain Expiration Date:(.+)',
   367         'expiration_date':             'Domain Expiration Date:(.+)',
   368         'transfer_date':               'Last Transferred Date:(.+)',
   368         'transfer_date':               'Last Transferred Date:(.+)',
   419         'tech_phone_ext':              'Tech Phone Ext\.:(.+)',
   419         'tech_phone_ext':              'Tech Phone Ext\.:(.+)',
   420         'tech_fax':                    'Tech FAX:(.+)',
   420         'tech_fax':                    'Tech FAX:(.+)',
   421         'tech_fax_ext':                'Tech FAX Ext\.:(.+)',
   421         'tech_fax_ext':                'Tech FAX Ext\.:(.+)',
   422         'tech_email':                  'Tech E-mail:(.+)',
   422         'tech_email':                  'Tech E-mail:(.+)',
   423         'name_servers':                'Nameservers:(.+)',  # list of name servers
   423         'name_servers':                'Nameservers:(.+)',  # list of name servers
   424 	}
   424     }
       
   425 
   425     def __init__(self, domain, text):
   426     def __init__(self, domain, text):
   426         if 'NOT FOUND' in text:
   427         if 'NOT FOUND' in text:
   427             raise PywhoisError(text)
   428             raise PywhoisError(text)
   428         else:
   429         else:
   429             WhoisEntry.__init__(self, domain, text, self.regex) 
   430             WhoisEntry.__init__(self, domain, text, self.regex)
   430 
   431 
   431 
   432 
   432 class WhoisUk(WhoisEntry):
   433 class WhoisUk(WhoisEntry):
   433     """Whois parser for .uk domains
   434     """Whois parser for .uk domains
   434     """
   435     """
   440         'registrant_name':                'Registrant:\n\s*(.+)',
   441         'registrant_name':                'Registrant:\n\s*(.+)',
   441         'creation_date':                  'Registered on:\s*(.+)',
   442         'creation_date':                  'Registered on:\s*(.+)',
   442         'expiration_date':                'Expiry date:\s*(.+)',
   443         'expiration_date':                'Expiry date:\s*(.+)',
   443         'updated_date':                   'Last updated:\s*(.+)',
   444         'updated_date':                   'Last updated:\s*(.+)',
   444         'name_servers':                   'Name servers:\s*(.+)',
   445         'name_servers':                   'Name servers:\s*(.+)',
   445 	}
   446     }
       
   447 
   446     def __init__(self, domain, text):
   448     def __init__(self, domain, text):
   447         if 'Not found:' in text:
   449         if 'Not found:' in text:
   448             raise PywhoisError(text)
   450             raise PywhoisError(text)
   449         else:
   451         else:
   450             WhoisEntry.__init__(self, domain, text, self.regex)
   452             WhoisEntry.__init__(self, domain, text, self.regex)
   484         'updated_date':                   'modified:\s*([\S]+)',
   486         'updated_date':                   'modified:\s*([\S]+)',
   485         'expiration_date':                'expires:\s*([\S]+)',
   487         'expiration_date':                'expires:\s*([\S]+)',
   486         'name_servers':                   'nserver:\s*([\S]+) \[\S+\]',  # list of name servers
   488         'name_servers':                   'nserver:\s*([\S]+) \[\S+\]',  # list of name servers
   487         'name_server_statuses':           'nserver:\s*([\S]+) \[(\S+)\]',  # list of name servers and statuses
   489         'name_server_statuses':           'nserver:\s*([\S]+) \[(\S+)\]',  # list of name servers and statuses
   488         'dnssec':                         'dnssec:\s*([\S]+)',
   490         'dnssec':                         'dnssec:\s*([\S]+)',
   489 	}
   491     }
       
   492 
   490     def __init__(self, domain, text):
   493     def __init__(self, domain, text):
   491         if 'Domain not ' in text:
   494         if 'Domain not ' in text:
   492             raise PywhoisError(text)
   495             raise PywhoisError(text)
   493         else:
   496         else:
   494             WhoisEntry.__init__(self, domain, text, self.regex)
   497             WhoisEntry.__init__(self, domain, text, self.regex)
   512         else:
   515         else:
   513             WhoisEntry.__init__(self, domain, text, self.regex)
   516             WhoisEntry.__init__(self, domain, text, self.regex)
   514 
   517 
   515 
   518 
   516 class WhoisAU(WhoisEntry):
   519 class WhoisAU(WhoisEntry):
   517    """Whois parser for .au domains
   520     """Whois parser for .au domains
   518    """
   521     """
   519    regex = {
   522     regex = {
   520        'domain_name':                    'Domain Name:\s*(.+)\n',
   523         'domain_name':                    'Domain Name:\s*(.+)\n',
   521        'last_modified':			      'Last Modified:\s*(.+)\n',
   524         'last_modified':			      'Last Modified:\s*(.+)\n',
   522        'registrar':                      'Registrar Name:\s*(.+)\n',
   525         'registrar':                      'Registrar Name:\s*(.+)\n',
   523        'status':                         'Status:\s*(.+)',  
   526         'status':                         'Status:\s*(.+)',
   524        'registrant_name':                'Registrant:\s*(.+)',
   527         'registrant_name':                'Registrant:\s*(.+)',
   525        'name_servers':                   'Name Server:\s*(.+)',
   528         'name_servers':                   'Name Server:\s*(.+)',
   526    }
   529     }
   527    def __init__(self, domain, text):
   530 
   528        if text.strip() == 'No Data Found':
   531     def __init__(self, domain, text):
   529            raise PywhoisError(text)
   532         if text.strip() == 'No Data Found':
   530        else:
   533             raise PywhoisError(text)
   531            WhoisEntry.__init__(self, domain, text, self.regex)
   534         else:
       
   535             WhoisEntry.__init__(self, domain, text, self.regex)
   532 
   536 
   533 
   537 
   534 class WhoisEu(WhoisEntry):
   538 class WhoisEu(WhoisEntry):
   535     """Whois parser for .eu domains
   539     """Whois parser for .eu domains
   536     """
   540     """
   551         else:
   555         else:
   552             WhoisEntry.__init__(self, domain, text, self.regex)
   556             WhoisEntry.__init__(self, domain, text, self.regex)
   553 
   557 
   554 
   558 
   555 class WhoisBr(WhoisEntry):
   559 class WhoisBr(WhoisEntry):
   556    """Whois parser for .br domains
   560     """Whois parser for .br domains
   557    """
   561     """
   558    regex = {
   562     regex = {
   559        'domain':                        'domain:\s*(.+)\n',
   563         'domain':                        'domain:\s*(.+)\n',
   560        'owner':                         'owner:\s*([\S ]+)',
   564         'owner':                         'owner:\s*([\S ]+)',
   561        'ownerid':                       'ownerid:\s*(.+)', 
   565         'ownerid':                       'ownerid:\s*(.+)',
   562        'country':                       'country:\s*(.+)',
   566         'country':                       'country:\s*(.+)',
   563        'owner_c':                       'owner-c:\s*(.+)',
   567         'owner_c':                       'owner-c:\s*(.+)',
   564        'admin_c':                       'admin-c:\s*(.+)',
   568         'admin_c':                       'admin-c:\s*(.+)',
   565        'tech_c':                        'tech-c:\s*(.+)',
   569         'tech_c':                        'tech-c:\s*(.+)',
   566        'billing_c':                     'billing-c:\s*(.+)',
   570         'billing_c':                     'billing-c:\s*(.+)',
   567        'nserver':                       'nserver:\s*(.+)',
   571         'nserver':                       'nserver:\s*(.+)',
   568        'nsstat':                        'nsstat:\s*(.+)',
   572         'nsstat':                        'nsstat:\s*(.+)',
   569        'nslastaa':                      'nslastaa:\s*(.+)',
   573         'nslastaa':                      'nslastaa:\s*(.+)',
   570        'saci':                          'saci:\s*(.+)',
   574         'saci':                          'saci:\s*(.+)',
   571        'created':                       'created:\s*(.+)',
   575         'created':                       'created:\s*(.+)',
   572        'expires':                       'expires:\s*(.+)',
   576         'expires':                       'expires:\s*(.+)',
   573        'changed':                       'changed:\s*(.+)',
   577         'changed':                       'changed:\s*(.+)',
   574        'status':                        'status:\s*(.+)',
   578         'status':                        'status:\s*(.+)',
   575        'nic_hdl_br':                    'nic-hdl-br:\s*(.+)',
   579         'nic_hdl_br':                    'nic-hdl-br:\s*(.+)',
   576        'person':                        'person:\s*([\S ]+)',
   580         'person':                        'person:\s*([\S ]+)',
   577        'email':                         'e-mail:\s*(.+)',
   581         'email':                         'e-mail:\s*(.+)',
   578    }
   582     }
   579 
   583 
   580    def __init__(self, domain, text):
   584     def __init__(self, domain, text):
   581 
   585 
   582        if 'Not found:' in text:
   586         if 'Not found:' in text:
   583            raise PywhoisError(text)
   587             raise PywhoisError(text)
   584        else:
   588         else:
   585            WhoisEntry.__init__(self, domain, text, self.regex)
   589             WhoisEntry.__init__(self, domain, text, self.regex)
   586 
   590 
   587 
   591 
   588 class WhoisKr(WhoisEntry):
   592 class WhoisKr(WhoisEntry):
   589     """Whois parser for .kr domains
   593     """Whois parser for .kr domains
   590     """
   594     """
   615     """
   619     """
   616     regex = {
   620     regex = {
   617         'domain_name': 'domain name:\s*(.+)',
   621         'domain_name': 'domain name:\s*(.+)',
   618         'creation_date': 'creation date \(dd\/mm\/yyyy\):\s*(.+)',
   622         'creation_date': 'creation date \(dd\/mm\/yyyy\):\s*(.+)',
   619         'expiration_date': 'expiration date \(dd\/mm\/yyyy\):\s*(.+)',
   623         'expiration_date': 'expiration date \(dd\/mm\/yyyy\):\s*(.+)',
   620         'name_servers': '\tNS\t(.+).', # list of name servers
   624         'name_servers': '\tNS\t(.+).',  # list of name servers
   621         'status': 'status:\s*(.+)', # list of statuses
   625         'status': 'status:\s*(.+)',  # list of statuses
   622         'emails': '[\w.-]+@[\w.-]+\.[\w]{2,4}', # list of email addresses
   626         'emails': '[\w.-]+@[\w.-]+\.[\w]{2,4}',  # list of email addresses
   623     }
   627     }
   624 
   628 
   625     def __init__(self, domain, text):
   629     def __init__(self, domain, text):
   626         if text.strip() == 'No entries found':
   630         if text.strip() == 'No entries found':
   627             raise PywhoisError(text)
   631             raise PywhoisError(text)
   628         else:
   632         else:
   629             WhoisEntry.__init__(self, domain, text, self.regex)
   633             WhoisEntry.__init__(self, domain, text, self.regex)
       
   634 
   630 
   635 
   631 class WhoisBg(WhoisEntry):
   636 class WhoisBg(WhoisEntry):
   632     """Whois parser for .bg domains"""
   637     """Whois parser for .bg domains"""
   633 
   638 
   634     regex = {
   639     regex = {
   639         if text.strip() == 'No entries found':
   644         if text.strip() == 'No entries found':
   640             raise PywhoisError(text)
   645             raise PywhoisError(text)
   641         else:
   646         else:
   642             WhoisEntry.__init__(self, domain, text, self.regex)
   647             WhoisEntry.__init__(self, domain, text, self.regex)
   643 
   648 
       
   649 
   644 class WhoisRf(WhoisEntry):
   650 class WhoisRf(WhoisEntry):
   645     """Whois parser for .bg domains"""
   651     """Whois parser for .bg domains"""
   646 
   652 
   647     regex = {
   653     regex = {
   648         'expiration_date': 'free-date:\s*(.+)',
   654         'expiration_date': 'free-date:\s*(.+)',