为什么子进程模块不在for循环中执行多个命令?

时间:2016-04-04 12:21:52

标签: python for-loop subprocess

我有一个保存在文本文件中的IP地址列表,我想使用子流程模块和for循环检查它们的代码编号(404,200,504,...)。对于一个IP地址,我的代码工作正常,但是当我尝试列表包含多个IP时,它会给我一些错误。

这是我的文本文件:

77.87.19.114
143.21.15.91
17.63.33.21
24.44.12.181

我使用的代码:

from subprocess import check_output

def ipcheck200(ip_list_file):
   with open(ip_list_file) as f:
      content = f.readlines()
   for item in content:

    # url generator for each ip
       url = "http://" + item + "/"
    #print(content[0])

    # command generator for each ip
       command = "python -c " + '"'
       command += "import urllib ;"
       command += "a = urllib.urlopen('%s') ;print(a.getcode())" % url
       command += '"'
       proc = check_output(command)
       print(proc)

结果将是:

> Traceback (most recent call last):
  File "<pyshell#0>", line 1, in <module>
    ipcheck200('test.txt')
  File "C:\Users\XXXX\XXXX\XXXX\file.py", line 17, in ipcheck200
    proc = check_output(command)
  File "C:\Python27\lib\subprocess.py", line 573, in check_output
    raise CalledProcessError(retcode, cmd, output=output)
CalledProcessError: Command 'python -c "import urllib ;a = urllib.urlopen('http://77.87.19.114
/') ;print(a.getcode())"' returned non-zero exit status 1

1 个答案:

答案 0 :(得分:2)

当存在未处理的异常时,Python将以1退出。

您没有错误处理;如果IP地址不存在,包含额外的空格,或者即使机器拒绝连接或只是超时,urllib.urlopen()也会引发异常:

>>> urllib.urlopen('http://127.0.0.1:80')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/mjpieters/Development/Library/buildout.python/parts/opt/lib/python2.7/urllib.py", line 87, in urlopen
    return opener.open(url)
  File "/Users/mjpieters/Development/Library/buildout.python/parts/opt/lib/python2.7/urllib.py", line 213, in open
    return getattr(self, name)(url)
  File "/Users/mjpieters/Development/Library/buildout.python/parts/opt/lib/python2.7/urllib.py", line 350, in open_http
    h.endheaders(data)
  File "/Users/mjpieters/Development/Library/buildout.python/parts/opt/lib/python2.7/httplib.py", line 1053, in endheaders
    self._send_output(message_body)
  File "/Users/mjpieters/Development/Library/buildout.python/parts/opt/lib/python2.7/httplib.py", line 897, in _send_output
    self.send(msg)
  File "/Users/mjpieters/Development/Library/buildout.python/parts/opt/lib/python2.7/httplib.py", line 859, in send
    self.connect()
  File "/Users/mjpieters/Development/Library/buildout.python/parts/opt/lib/python2.7/httplib.py", line 836, in connect
    self.timeout, self.source_address)
  File "/Users/mjpieters/Development/Library/buildout.python/parts/opt/lib/python2.7/socket.py", line 575, in create_connection
    raise err
IOError: [Errno socket error] [Errno 61] Connection refused

您的代码从文件中获取行而不进行进一步处理;它至少会在每一行附加一个换行符,所以你想去掉这一行:

for item in content:
    item = item.strip()

您还在执行 sequence 中的所有子进程,因为check_output()等待进程先完成;这比尝试在同一进程中运行此代码要慢。不要在这里重新发明多处理轮,而是使用multiprocessing module代替:

from multiprocessing import Pool
import urllib

def check(ipaddress):
     try:
         response = urllib.urlopen('http://{}/'.format(url))
     except IOError:
         return 0  # connection unsuccessful (timeout, connection refused, etc)
     return response.getcode()

if __name__ == '__main__':
    p = Pool(10)
    with open(ip_list_file) as f:
        ipaddresses = [address.strip() for address in f if address.strip()]
    print(p.map(check, ipaddresses))

此示例将使用10个子进程并行测试IP地址。