【问题标题】:Multi-request pycurl running forever ( Infinite loop)多请求 pycurl 永远运行(无限循环)
【发布时间】:2011-11-29 21:19:38
【问题描述】:

我想使用 Pycurl 执行多请求。代码是: m.add_handle(句柄) requests.append((句柄,响应))

    # Perform multi-request.
    SELECT_TIMEOUT = 1.0
    num_handles = len(requests)
    while num_handles:
        ret = m.select(SELECT_TIMEOUT)
        if ret == -1: continue
        while 1:
            ret, num_handles = m.perform()
            print "In while loop of multicurl"
            if ret != pycurl.E_CALL_MULTI_PERFORM: break

问题是,这个循环需要永远运行。它没有终止。 谁能告诉我,它的作用是什么以及可能出现的问题是什么?

【问题讨论】:

    标签: python web-crawler pycurl


    【解决方案1】:

    你看过 PyCurl 官方代码了吗?下面的代码实现了多种东西,我尝试执行它,我能够在 300 秒内并行抓取大约 10,000 个 url。我认为这正是您想要实现的目标?请纠正我,如果我错了。

    #! /usr/bin/env python
    # -*- coding: iso-8859-1 -*-
    # vi:ts=4:et
    # $Id: retriever-multi.py,v 1.29 2005/07/28 11:04:13 mfx Exp $
    
    #
    # Usage: python retriever-multi.py <file with URLs to fetch> [<# of
    #          concurrent connections>]
    #
    
    import sys
    import pycurl
    
    # We should ignore SIGPIPE when using pycurl.NOSIGNAL - see
    # the libcurl tutorial for more info.
    try:
        import signal
        from signal import SIGPIPE, SIG_IGN
        signal.signal(signal.SIGPIPE, signal.SIG_IGN)
    except ImportError:
        pass
    
    
    # Get args
    num_conn = 10
    try:
        if sys.argv[1] == "-":
            urls = sys.stdin.readlines()
        else:
            urls = open(sys.argv[1]).readlines()
        if len(sys.argv) >= 3:
            num_conn = int(sys.argv[2])
    except:
        print "Usage: %s <file with URLs to fetch> [<# of concurrent connections>]" % sys.argv[0]
        raise SystemExit
    
    
    # Make a queue with (url, filename) tuples
    queue = []
    for url in urls:
        url = url.strip()
        if not url or url[0] == "#":
            continue
        filename = "doc_%03d.dat" % (len(queue) + 1)
        queue.append((url, filename))
    
    
    # Check args
    assert queue, "no URLs given"
    num_urls = len(queue)
    num_conn = min(num_conn, num_urls)
    assert 1 <= num_conn <= 10000, "invalid number of concurrent connections"
    print "PycURL %s (compiled against 0x%x)" % (pycurl.version, pycurl.COMPILE_LIBCURL_VERSION_NUM)
    print "----- Getting", num_urls, "URLs using", num_conn, "connections -----"
    
    
    # Pre-allocate a list of curl objects
    m = pycurl.CurlMulti()
    m.handles = []
    for i in range(num_conn):
        c = pycurl.Curl()
        c.fp = None
        c.setopt(pycurl.FOLLOWLOCATION, 1)
        c.setopt(pycurl.MAXREDIRS, 5)
        c.setopt(pycurl.CONNECTTIMEOUT, 30)
        c.setopt(pycurl.TIMEOUT, 300)
        c.setopt(pycurl.NOSIGNAL, 1)
        m.handles.append(c)
    
    
    # Main loop
    freelist = m.handles[:]
    num_processed = 0
    while num_processed < num_urls:
        # If there is an url to process and a free curl object, add to multi stack
        while queue and freelist:
            url, filename = queue.pop(0)
            c = freelist.pop()
            c.fp = open(filename, "wb")
            c.setopt(pycurl.URL, url)
            c.setopt(pycurl.WRITEDATA, c.fp)
            m.add_handle(c)
            # store some info
            c.filename = filename
            c.url = url
        # Run the internal curl state machine for the multi stack
        while 1:
            ret, num_handles = m.perform()
            if ret != pycurl.E_CALL_MULTI_PERFORM:
                break
        # Check for curl objects which have terminated, and add them to the freelist
        while 1:
            num_q, ok_list, err_list = m.info_read()
            for c in ok_list:
                c.fp.close()
                c.fp = None
                m.remove_handle(c)
                print "Success:", c.filename, c.url, c.getinfo(pycurl.EFFECTIVE_URL)
                freelist.append(c)
            for c, errno, errmsg in err_list:
                c.fp.close()
                c.fp = None
                m.remove_handle(c)
                print "Failed: ", c.filename, c.url, errno, errmsg
                freelist.append(c)
            num_processed = num_processed + len(ok_list) + len(err_list)
            if num_q == 0:
                break
        # Currently no more I/O is pending, could do something in the meantime
        # (display a progress bar, etc.).
        # We just call select() to sleep until some more data is available.
        m.select(1.0)
    
    
    # Cleanup
    for c in m.handles:
        if c.fp is not None:
            c.fp.close()
            c.fp = None
        c.close()
    m.close()
    

    【讨论】:

      【解决方案2】:

      我认为这是因为您只跳出第一个 while 循环

      # Perform multi-request.
      SELECT_TIMEOUT = 1.0
      num_handles = len(requests)
      while num_handles:                           #  while nr.1
          ret = m.select(SELECT_TIMEOUT)
          if ret == -1: continue
          while 1:                                 #  while nr.2
              ret, num_handles = m.perform()
              print "In while loop of multicurl"
              if ret != pycurl.E_CALL_MULTI_PERFORM: break
          '**'
      

      所以如果你使用'break'会发生什么,你将跳出当前的while循环(当你使用break时你处于第二个while循环中。) 程序的下一步将在此处输入写为 '**' 的行,因为它是它跳回的最后一行。 (到 while num_handles 的第一行) 然后再走 3 行,它会运行到 'while 1:' 等等......这就是你获得 inf 循环的方式。

      所以要解决这个问题:

      # Perform multi-request.
      SELECT_TIMEOUT = 1.0
      num_handles    = len(requests)
      while num_handles:                           #  while nr.1
          ret = m.select(SELECT_TIMEOUT)
          if ret == -1: continue
          while 1:                                 #  while nr.2
              ret, num_handles = m.perform()
              print "In while loop of multicurl"
              if ret != pycurl.E_CALL_MULTI_PERFORM: 
                  break
          break
      

      所以这里发生的事情是,一旦它从嵌套的 while 循环中中断,它也会自动从第一个循环中中断。 (否则它永远不会到达这条线,因为while,以及之前使用的continue

      【讨论】:

        猜你喜欢
        • 2019-04-14
        • 1970-01-01
        • 2012-09-04
        • 1970-01-01
        • 1970-01-01
        • 2018-03-24
        • 2014-11-23
        • 2017-08-19
        • 2021-11-06
        相关资源
        最近更新 更多