2010-06-22 24 views
2

Je traitement une liste de milliers de noms de domaine à partir d'un DNSBL par creuser, en créant un fichier CSV d'URL et les adresses IP. C'est un processus très long qui peut prendre plusieurs heures. DNSBL de mon serveur met à jour toutes les quinze minutes. Est-il possible d'augmenter le débit de mon script Python pour suivre les mises à jour du serveur?débit croissant dans un script python

Modifier: le script, comme l'a demandé.

import re 
import subprocess as sp 

text = open("domainslist", 'r') 
text = text.read() 
text = re.split("\n+", text) 

file = open('final.csv', 'w') 

for element in text: 
     try: 
      ip = sp.Popen(["dig", "+short", url], stdout = sp.PIPE) 
      ip = re.split("\n+", ip.stdout.read()) 
      file.write(url + "," + ip[0] + "\n") 
     except: 
      pass 
+1

Affiche le script ou le pseudo-code du script. De cette façon, nous pouvons suggérer des améliorations. Une liste de milliers en 15 minutes devrait être facilement dans les limites de python. – Kieveli

+0

+1, s'il vous plaît nous montrer ce que vous avez. BTW, si j'ai bien compris, il est probable que c'est la résolution de noms, pas le script lui-même, qui prend si longtemps. Si c'est le cas, vous pouvez essayer une solution threadée. – rbp

+0

Publié, tel que demandé. – Tom

Répondre

2

Eh bien, c'est probablement la résolution de nom qui vous prend si longtemps. Si vous comptez cela (c'est-à-dire, si d'une manière ou d'une autre vous revenez très rapidement), Python devrait être capable de gérer facilement des milliers d'entrées.

Cela dit, vous devriez essayer une approche filetée. Cela résoudrait (théoriquement) plusieurs adresses en même temps, plutôt que séquentiellement. Vous pourriez tout aussi bien continuer à utiliser creuser pour cela, et il devrait être trivial de modifier mon code exemple ci-dessous, mais, pour rendre les choses intéressantes (et je l'espère plus pythonique), nous allons utiliser un module existant pour que: dnspython

alors, installez-le avec:

sudo pip install -f http://www.dnspython.org/kits/1.8.0/ dnspython 

Et essayez quelque chose comme ce qui suit:

import threading 
from dns import resolver 

class Resolver(threading.Thread): 
    def __init__(self, address, result_dict): 
     threading.Thread.__init__(self) 
     self.address = address 
     self.result_dict = result_dict 

    def run(self): 
     try: 
      result = resolver.query(self.address)[0].to_text() 
      self.result_dict[self.address] = result 
     except resolver.NXDOMAIN: 
      pass 


def main(): 
    infile = open("domainlist", "r") 
    intext = infile.readlines() 
    threads = [] 
    results = {} 
    for address in [address.strip() for address in intext if address.strip()]: 
     resolver_thread = Resolver(address, results) 
     threads.append(resolver_thread) 
     resolver_thread.start() 

    for thread in threads: 
     thread.join() 

    outfile = open('final.csv', 'w') 
    outfile.write("\n".join("%s,%s" % (address, ip) for address, ip in results.iteritems())) 
    outfile.close() 

if __name__ == '__main__': 
    main() 

Si cela se révèle commencer trop de threads en même temps, vous pourriez essayer de le faire par lots ou en utilisant une file d'attente (voir http://www.ibm.com/developerworks/aix/library/au-threadingpython/ pour un exemple)

+0

fonctionne très bien, mais je continue à obtenir ces erreurs: Fichier « /home/okim/dnspython/dns/resolver.py », ligne 541, dans _compute_timeout raise Délai d'attente Délai d'attente Des idées? – Tom

+0

Apparemment, votre serveur de noms ne peut pas résoudre certains noms dans le délai d'expiration par défaut (le serveur de noms faisant autorité ne répond peut-être pas). Si vous voulez les ignorer, changez simplement la ligne "except resolver.NXDOMAIN:" en "except (resolver.NXDOMAIN, resolver.Timeout):". Si vous voulez traiter ces exceptions différemment, ajoutez juste une nouvelle clause except, après celle de NXDOMAIN. Incidemment, NXDOMAIN capture les domaines inexistants. – rbp

+0

BTW, si vous trouvez que le problème est votre serveur de noms, vous pouvez en spécifier un nominalement avec "resolver.default_resolver.nameservers.insert (0, '8.8.8.8')". Mais je dis juste pour l'exhaustivité, il est plus probable que, parmi des milliers de noms de domaine, certains d'entre eux ne répondent tout simplement pas (d'autant plus que vous mentionnez qu'ils proviennent d'une liste noire). – rbp

2

La grande majorité du temps ici est passé dans les appels externes à , afin d'améliorer cette vitesse, vous devez multithread. Cela vous permettra d'exécuter plusieurs appels à en même temps. Voir par exemple: Python Subprocess.Popen from a thread. Ou, vous pouvez utiliser Twisted (http://twistedmatrix.com/trac/).

EDIT: Vous avez raison, une grande partie de ce n'était pas nécessaire.

+0

+1 pour avoir mentionné la nécessité de passer des appels à creuser. Vous devriez mettre ceci avant tout dans votre réponse. –

0

J'envisagerais d'utiliser une bibliothèque pure-Python pour faire les requêtes DNS, plutôt que de déléguer à , car l'appel d'un autre processus peut prendre beaucoup de temps. (Bien sûr, chercher quoi que ce soit sur internet est aussi relativement long, alors ce que gilesc a dit sur le multithreading s'applique toujours) Une recherche Google pour python dns vous donnera quelques options pour commencer.

+0

le temps de démarrage de nouveaux processus est négligeable par rapport au temps nécessaire pour exécuter une requête DNS –

+0

Oui, mais le délai réseau était déjà couvert par la réponse de gilesc. –

0

Afin de maintenir le rythme des mises à jour du serveur, il faut prendre moins de 15 minutes pour exécuter. Votre script prend-il 15 minutes pour s'exécuter? Si cela ne prend pas 15 minutes, vous avez terminé!

J'enquête sur la mise en cache et diffs de séries précédentes afin d'augmenter les performances.

+0

il a déjà été mentionné, il faut plusieurs heures –