因为在研究爬虫,所以也了解了下域名解析。要提高爬虫的效率,就需要提高域名解析的效率。我将爬虫记录下的域名作为待解析的域名来测试各域名解析方法的效率。我尝试以下四种方法:1. 单线程依次解析各域名,2. 多线程同时解析各域名,3. 线程池解析各域名,4. 使用adns库解析各域名。其中,第四种方法最高效也最安全,推荐大家使用。完整的代码请见:https://github.com/sunada/dnsResolve

1. 单线程依次解析域名

这种方法最直观。使用一个循环,依次使用socket.getaddrinfo('host',None)来进行解析。这种方法很低效:解析100个域名花费了392s,解析500个域名花费了1695s。这是由于getaddrinfo方法解析单个域名就比较费时间,使用单线程阻碍的方法来解析500个域名,自然会耗时较长。

import time
import socket def ReadHost(file):
  hosts=[]
  ...
  return hosts def SynResolve(fr):
  hosts=ReadHost(fr)
  IPs={}
  for host in hosts:
  try:
   results=socket.getaddrinfo(host,None)
  for result in results:
  print host, result[4][0]
    IPs[result[4][0]]=host
  except Exception,e:
   print e
  file.close() if __name__=='__main__':
  start=time.time()
  print 'starting at: ',start
  SynResolve('host')
  print 'ending at: ',time.time()-start

2. 多线程解析域名

这种方法也好理解。每解析一个域名时,就建立一个新的线程,用这个线程去解析此域名。这种方法较为高效,但在线程数量太大时错误率较高。解析500个域名需要创建500个线程,试验结果表示:执行程序时给出了“thread.error: can't start new thread的提示。可能受此影响,运行脚本时提示个别域名无法解析。对这些域名单独使用socket.getaddrinfo进行解析时,都可解析成功;如果只需解析100个线程,则不会提示thread.error的提示,仅有一个域名提示无法解析成功。使用此方法,解析100个域名大约耗时1分钟左右。因为我运行脚本的机器所在的网速不太稳定,所以也许这种方法所需要的时间更短。

代码主要分为两个部分:一部分为一个继承自threading.Thread的子类,并通过run()函数这一成员函数来实现每个线程所要完成的工作;另一部分为一个函数,负责将需要完成的任务分配给一个新创建的线程。由于需要将解析得到的域名和对应的IP保存下载,所以需要各线程共同修改IPhost这一字典。代码中使用了一个锁(mutex),只有得到锁的线程才能向IPhost写入,否则只能等待。这样可保证IPhost中IP与域名信息正确的对应关系。否则在线程的来回快速切换中,可能造成这种对应关系记录的不准确。

import time
import socket def ReadHost(file):
  hosts=[]
  ...
  return hosts class ThreadClass(threading.Thread):
def __init__(self,host):
self.host=host
threading.Thread.__init__(self) def run(self):
global IPhost
try:
res=socket.getaddrinfo(self.host,None)
if mutex.acquire(1):
  for re in res:
  IPhost[re[4][0]]=self.host
   mutex.release()
except Exception, e:
print self.host, e def MulThreadResolve(fr):
start=time.ctime()
print 'starting MulThreadResolve at: ',start
hosts=ReadHost(fr)
threads=[]
for host in hosts:
t=ThreadClass(host)
threads.append(t) cntHost=len(hosts)
for i in range(cntHost):
threads[i].start() for i in range(cntHost):
threads[i].join() print 'ending MulThreadResolve at :', time.ctime() if __name__='__main__':
IPhost={}
mutex=threading.Lock()
MulThreadResolve('host1')
print IPhost

3. 利用线程池进行域名解析

通过方法2,我们知道在一个进程中创建过多的线程来执行任务,是危险的。自然的,我们就会想到利用有限个线程来进行域名解析。比如,用100个线程去解析500域名。当一个线程解析完成后,无需关闭,继续从队列中取出一个域名进行解析。如此反复,直到队列中为空,所有域名都得到解析为止。使用线程池的另一个好处是省略了新建线程和关闭线程的时间;如果线程执行的任务耗时较短,那么通过线程池节省下来的这笔时间将会是可观的。可以预计,此法将比方法2耗时更多。

利用线程池进行域名解析的代码较方法2要复杂一些,但也不难理解。代码仍旧主要分为两个部分:一部分为一个继承自threading.Thread的子类,并通过run()函数这一成员函数来实现每个线程所要完成的工作。run()函数中,当一个线程空闲时,就去队列中取出一个域名;直到队列为空,函数的任务也就完成了。另一部分为一个类,负责将任务分配给一个新创建的线程,并检查交由run()完成的任务是否都已完成。由于需要进行的管理行为较方法2更多,所以将这些管理行为整合在一起,弄成了一个类。因为一个线程需要进行多次域名解析工作,所以需要将这些待解析的域名进行排队。队伍的容量是有限的,只有当队未满时才能将域名加入队列等待线程将其取走并进行解析。由于代码较长,我就把它放在这里了。

使用Python脚本进行域名解析的更多相关文章

  1. freeswitch嵌入python脚本

    操作系统:debian8.5_x64 freeswitch 版本 : 1.6.8 python版本:2.7.9 开启python模块 安装python lib库 apt-get install pyt ...

  2. python脚本后台运行

    问题描述: 环境: CentOS6.4 一个用python写的监控脚本test1.py,用while True方式一直运行,在ssh远程(使用putty终端)时通过以下命令启动脚本: python t ...

  3. 某互联网后台自动化组合测试框架RF+Sikuli+Python脚本

    某互联网后台自动化组合测试框架RF+Sikuli+Python脚本 http://www.jianshu.com/p/b3e204c8651a 字数949 阅读323 评论1 喜欢0 一.**Robo ...

  4. 动态执行python脚本

    前言 存在许多独立的python脚本,这些脚本可能会增加,也可能会减少,现在需要按照某种顺序调度这些程序.在python的standard library中,有一个模块imp可以实现动态的调用ptho ...

  5. 一个获取指定目录下一定格式的文件名称和文件修改时间并保存为文件的python脚本

    摘自:http://blog.csdn.net/forandever/article/details/5711319 一个获取指定目录下一定格式的文件名称和文件修改时间并保存为文件的python脚本 ...

  6. SecureCRT中python脚本编写

    SecureCRT中python脚本编写学习指南 SecureCRT python 引言 在测试网络设备中,通常使用脚本对设备端进行配置和测试以及维护:对于PE设备的测试维护人员来说使用较多是Secu ...

  7. Python脚本配合Linux计划任务工作

    经常遇到直接运行Python脚本没有问题,但是一放入/etc/crontab之后就歇菜的情况,总结了一下,大致需要注意以下几点: 1. 脚本首行加入#!/usr/bin/env python 2. 脚 ...

  8. Labview调用Python脚本

    Labview程序框图如下: Python脚本如下: #!/usr/bin/env pythonimport sys #Command Line Arguements are stored in li ...

  9. 使用Runtime.getRuntime().exec()在java中调用python脚本

    举例有一个Python脚本叫test.py,现在想要在Java里调用这个脚本.假定这个test.py里面使用了拓展的包,使得pythoninterpreter之类内嵌的编译器无法使用,那么只能采用ja ...

随机推荐

  1. hdu 4927 java求组合数(大数)

    import java.util.Scanner; import java.math.BigInteger; public class Main { private static int [] a = ...

  2. delphi 中 $是什么意思 串口中使用

    delphi 中 $是什么意思? 比如:$41----$5A 意识是26个字母, 可以用$来表示? $在delphi 中还可以怎么用?1.表示16进制,$41就是65,第一个字母的ASCII值 pro ...

  3. Aptana 插件 for Eclipse 4.4

    http://download.aptana.com/studio3/plugin/install Aptana Update Site This site is designed to be use ...

  4. Linux系统上安装Python

    1.下载Python安装包,官网下:http://www.python.org/getit/ http://jingyan.baidu.com/article/eae07827f7f2d01fec54 ...

  5. 动手动脑之查看String.equals()方法的实现代码及解释

    动手动脑 请查看String.equals()方法的实现代码,注意学习其实现方法. 第一个是false,后三个是true. package stringtest; public class Strin ...

  6. Linux下U盘的挂载和文件的拷贝

    把文件通过U盘拷贝到linux系统下插好U盘后,查看磁盘情况fdisk -l正常情况下有 Disk /dev/sda:2045 MB,2045247488 bytes47 heads,46 secto ...

  7. Use weakref module in a cache or mapping

    The weakref module allows the Python programmer to create weak references to objects. In the followi ...

  8. WS之cxf与spring整合1

    1.在web.xml中加入CXFServlet: <!-- 下面表示所有来自/cxfservice/*的请求,都交给 CXFServlet来处理 .--> <servlet>  ...

  9. NServiceBus-网关和多站点分布

    多站点部署的企业的数量.净系统由于增加的挑战高可用性和用户要求更快的响应时间,服务器和数据访问更接近. RPC技术迅速陷入困境在这些环境中,使机器在同一个站点和远程站点看起来是一样的. 在这些情况下, ...

  10. Strassen算法

    如题,该算法是来自德国的牛逼的数学家strassen搞出来的,因为把n*n矩阵之间的乘法复杂度降低到n^(lg7)(lg的底是2),一开始想当然地认为朴素的做法是n^3,哪里还能有复杂度更低的做法,但 ...