закрытие файлов, правильно открытых с помощью urllib2.urlopen () - PullRequest
7 голосов
/ 07 октября 2010

У меня следующий код в скрипте 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

Ответы [ 8 ]

17 голосов
/ 13 февраля 2013

Я бы использовал contextlib.closing (в сочетании с из __future__ import with_statement для старых версий Python):

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()

Не совсем элегантно.

8 голосов
/ 07 октября 2010
finally:
    if sf: sf.close()
6 голосов
/ 07 октября 2010

Почему бы просто не попробовать закрыть 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
1 голос
/ 19 мая 2017

Если 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

1 голос
/ 07 октября 2010

Учитывая, что вы пытаетесь использовать 'with', вы должны быть на Python 2.5, и это также относится: http://docs.python.org/tutorial/errors.html#defining-clean-up-actions

0 голосов
/ 24 марта 2015

Почему бы просто не использовать несколько блоков try / кроме?

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()
0 голосов
/ 25 августа 2013

Вы можете создать свой собственный открыватель 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.

0 голосов
/ 07 октября 2010

Похоже, проблема глубже, чем я думал - эта ветка форума указывает, что urllib2 не реализует with до Python 2.6 и, возможно, не до 3.1

...