【问题标题】:closing files properly opened with urllib2.urlopen()关闭使用 urllib2.urlopen() 正确打开的文件
【发布时间】:2010-10-07 10:31:44
【问题描述】:

我在 python 脚本中有以下代码

  try:
    # send the query request
    sf = urllib2.urlopen(search_query)
    search_soup = BeautifulSoup.BeautifulStoneSoup(sf.read())
    sf.close()
  except Exception, err:
    print("Couldn't get programme information.")
    print(str(err))
    return

我很担心,因为如果我在 sf.read() 上遇到错误,则不会调用 sf.clsoe()。 我尝试将sf.close() 放在finally 块中,但如果urlopen() 出现异常,则没有要关闭的文件,我在finally 块中遇到异常!

然后我尝试了

  try:
    with urllib2.urlopen(search_query) as sf:
      search_soup = BeautifulSoup.BeautifulStoneSoup(sf.read())
  except Exception, err:
    print("Couldn't get programme information.")
    print(str(err))
    return

但这在with... 行上引发了无效的语法错误。 我怎么能最好地处理这个,我觉得很愚蠢!

正如评论者所指出的,我使用的是 Pys60,它是 python 2.5.4

【问题讨论】:

  • "with" 语句仅在 Python 2.6 中可用,如果您将 from __future__ import with_statement 放在文件顶部,则在 2.5 中可用。我不太记得 PyS60 实现了什么 Python 版本,但它可能是 2.5?
  • 它是 2.5.4。导入是一个好点:)

标签: python exception-handling urllib2 pys60


【解决方案1】:

我会使用 contextlib.closing(与旧 Python 版本的 from __future__ import with_statement 结合使用):

from contextlib import closing

with closing(urllib2.urlopen('http://blah')) as sf:
    search_soup = BeautifulSoup.BeautifulStoneSoup(sf.read())

或者,如果你想避免使用 with 语句:

try:
    sf = None
    sf = urllib2.urlopen('http://blah')
    search_soup = BeautifulSoup.BeautifulStoneSoup(sf.read())
finally:
    if sf:
        sf.close()

虽然没有那么优雅。

【讨论】:

    【解决方案2】:
    finally:
        if sf: sf.close()
    

    【讨论】:

      【解决方案3】:

      为什么不尝试关闭sf,如果不存在则通过?

      import urllib2
      try:
          search_query = 'http://blah'
          sf = urllib2.urlopen(search_query)
          search_soup = BeautifulSoup.BeautifulStoneSoup(sf.read())
      except urllib2.URLError, err:
          print(err.reason)
      finally:
          try:
              sf.close()
          except NameError: 
              pass
      

      【讨论】:

      • 知道我遗漏了一些明显的嵌套尝试!您的解决方案非常优雅,谢谢!
      【解决方案4】:

      鉴于您尝试使用“with”,您应该使用 Python 2.5,然后这也适用:http://docs.python.org/tutorial/errors.html#defining-clean-up-actions

      【讨论】:

        【解决方案5】:

        如果 urlopen() 有异常,捕获它并调用异常的 close() 函数,如下所示:

        try:
            req = urllib2.urlopen(url)
            req.close()
            print 'request {0} ok'.format(url)
        except urllib2.HTTPError, e:
            e.close()
            print 'request {0} failed, http code: {1}'.format(url, e.code)
        except urllib2.URLError, e:
            print 'request {0} error, error reason: {1}'.format(url, e.reason)
        

        异常也是一个完整的响应对象,你可以看到这个问题信息:http://bugs.jython.org/issue1544

        【讨论】:

          【解决方案6】:

          看起来问题比我想象的更深 - this forum thread 表示 urllib2 直到 python 2.6 之后才实现 with,并且可能直到 3.1 才实现

          【讨论】:

          • 这是真的。我使用的是 Python 2.7(2013 年发表评论),但它似乎不起作用,所以我正在用 Python2 重写最初为 Python3 编写的东西,我不得不重写我所有的 with urllib.urlopen(source) as f: 语句。
          【解决方案7】:

          您可以创建自己的通用 URL 打开器:

          from contextlib import contextmanager
          
          @contextmanager
          def urlopener(inURL):
              """Open a URL and yield the fileHandle then close the connection when leaving the 'with' clause."""
              fileHandle = urllib2.urlopen(inURL)
              try:     yield fileHandle
              finally: fileHandle.close()
          

          然后您可以使用原始问题中的语法:

          with urlopener(theURL) as sf:
              search_soup = BeautifulSoup.BeautifulSoup(sf.read())
          

          此解决方案为您提供了清晰的关注点分离。您将获得一个干净的通用 urlopener 语法,该语法可以处理正确关闭资源的复杂性,而不管您的 with 子句下发生的错误。

          【讨论】:

            【解决方案8】:

            为什么不直接使用多个 try/except 块?

            try:
                # send the query request
                sf = urllib2.urlopen(search_query)
            except urllib2.URLError as url_error:
                sys.stderr.write("Error requesting url: %s\n" % (search_query,))
                raise
            
            try:
                search_soup = BeautifulSoup.BeautifulStoneSoup(sf.read())
            except Exception, err: # Maybe catch more specific Exceptions here
                sys.stderr.write("Couldn't get programme information from url: %s\n" % (search_query,))
                raise # or return as in your original code
            finally:
                sf.close()
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2020-02-15
              • 2018-01-27
              • 1970-01-01
              • 2015-06-25
              • 2015-02-05
              • 1970-01-01
              相关资源
              最近更新 更多