[PYTHON] 파이썬 요청은 로컬 URL에서 파일을 가져옵니다.
PYTHON파이썬 요청은 로컬 URL에서 파일을 가져옵니다.
내 응용 프로그램의 한 가지 방법으로 파이썬의 요청 라이브러리를 사용하고 있습니다. 메소드의 본문은 다음과 같습니다.
def handle_remote_file(url, **kwargs):
response = requests.get(url, ...)
buff = StringIO.StringIO()
buff.write(response.content)
...
return True
그 메서드에 대한 몇 가지 단위 테스트를 작성하고 싶습니다, 그러나 내가하고 싶은 일은 다음과 같은 가짜 로컬 URL을 전달하는 것입니다.
class RemoteTest(TestCase):
def setUp(self):
self.url = 'file:///tmp/dummy.txt'
def test_handle_remote_file(self):
self.assertTrue(handle_remote_file(self.url))
로컬 URL로 requests.get을 호출하면 아래에있는 KeyError 예외가 발생합니다.
requests.get('file:///tmp/dummy.txt')
/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/requests/packages/urllib3/poolmanager.pyc in connection_from_host(self, host, port, scheme)
76
77 # Make a fresh ConnectionPool of the desired type
78 pool_cls = pool_classes_by_scheme[scheme]
79 pool = pool_cls(host, port, **self.connection_pool_kw)
80
KeyError: 'file'
질문은 요청에 로컬 URL을 전달할 수있는 방법입니다.
추신 : 나는 위의 예를 구성했다. 많은 오류가있을 수 있습니다.
해결법
-
==============================
1.@ WooParadog는 요청 라이브러리가 로컬 파일을 처리하는 방법을 알지 못한다고 설명했습니다. 현재 버전에서는 전송 어댑터를 정의 할 수 있습니다.
@ WooParadog는 요청 라이브러리가 로컬 파일을 처리하는 방법을 알지 못한다고 설명했습니다. 현재 버전에서는 전송 어댑터를 정의 할 수 있습니다.
따라서 로컬 파일을 처리 할 수있는 자체 어댑터를 정의 할 수 있습니다 (예 :
from requests_testadapter import Resp class LocalFileAdapter(requests.adapters.HTTPAdapter): def build_response_from_file(self, request): file_path = request.url[7:] with open(file_path, 'rb') as file: buff = bytearray(os.path.getsize(file_path)) file.readinto(buff) resp = Resp(buff) r = self.build_response(request, resp) return r def send(self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None): return self.build_response_from_file(request) requests_session = requests.session() requests_session.mount('file://', LocalFileAdapter()) requests_session.get('file://<some_local_path>')
위 예제에서 requests-testadapter 모듈을 사용하고 있습니다.
-
==============================
2.다음은 b1r3k의 것보다 더 특징적인 전송 어댑터이며 Request 자체를 넘어서는 추가 종속성이 없습니다. 나는 그것을 철저히 시험하지는 않았지만, 내가 시도한 것은 버그가없는 것 같다.
다음은 b1r3k의 것보다 더 특징적인 전송 어댑터이며 Request 자체를 넘어서는 추가 종속성이 없습니다. 나는 그것을 철저히 시험하지는 않았지만, 내가 시도한 것은 버그가없는 것 같다.
import requests import os, sys if sys.version_info.major < 3: from urllib import url2pathname else: from urllib.request import url2pathname class LocalFileAdapter(requests.adapters.BaseAdapter): """Protocol Adapter to allow Requests to GET file:// URLs @todo: Properly handle non-empty hostname portions. """ @staticmethod def _chkpath(method, path): """Return an HTTP status for the given filesystem path.""" if method.lower() in ('put', 'delete'): return 501, "Not Implemented" # TODO elif method.lower() not in ('get', 'head'): return 405, "Method Not Allowed" elif os.path.isdir(path): return 400, "Path Not A File" elif not os.path.isfile(path): return 404, "File Not Found" elif not os.access(path, os.R_OK): return 403, "Access Denied" else: return 200, "OK" def send(self, req, **kwargs): # pylint: disable=unused-argument """Return the file specified by the given request @type req: C{PreparedRequest} @todo: Should I bother filling `response.headers` and processing If-Modified-Since and friends using `os.stat`? """ path = os.path.normcase(os.path.normpath(url2pathname(req.path_url))) response = requests.Response() response.status_code, response.reason = self._chkpath(req.method, path) if response.status_code == 200 and req.method.lower() != 'head': try: response.raw = open(path, 'rb') except (OSError, IOError) as err: response.status_code = 500 response.reason = str(err) if isinstance(req.url, bytes): response.url = req.url.decode('utf-8') else: response.url = req.url response.request = req response.connection = self return response def close(self): pass
(이름에도 불구하고, Google을 확인하기 전에 완전히 작성되었으므로 b1r3k와는 아무런 관련이 없습니다.) 다른 답변과 마찬가지로 다음을 수행하십시오.
requests_session = requests.session() requests_session.mount('file://', LocalFileAdapter()) r = requests_session.get('file:///path/to/your/file')
-
==============================
3.packages / urllib3 / poolmanager.py는 그것을 아주 잘 설명합니다. 요청은 로컬 URL을 지원하지 않습니다.
packages / urllib3 / poolmanager.py는 그것을 아주 잘 설명합니다. 요청은 로컬 URL을 지원하지 않습니다.
pool_classes_by_scheme = { 'http': HTTPConnectionPool, 'https': HTTPSConnectionPool, }
-
==============================
4.최근 프로젝트에서 같은 문제가 발생했습니다. 요청은 "파일"스키마를 지원하지 않으므로 코드를 패치하여 컨텐츠를 로컬로로드합니다. 먼저 requests.get을 대체 할 함수를 정의합니다.
최근 프로젝트에서 같은 문제가 발생했습니다. 요청은 "파일"스키마를 지원하지 않으므로 코드를 패치하여 컨텐츠를 로컬로로드합니다. 먼저 requests.get을 대체 할 함수를 정의합니다.
def local_get(self, url): "Fetch a stream from local files." p_url = six.moves.urllib.parse.urlparse(url) if p_url.scheme != 'file': raise ValueError("Expected file scheme") filename = six.moves.urllib.request.url2pathname(p_url.path) return open(filename, 'rb')
그런 다음, 테스트 설정이나 테스트 함수 꾸미기에서 mock.patch를 사용하여 요청에서 get 함수를 패치합니다.
@mock.patch('requests.get', local_get) def test_handle_remote_file(self): ...
이 기법은 다소 취약합니다. 기본 코드가 requests.request를 호출하거나 Session을 생성하고 호출하면 도움이되지 않습니다. 파일 : URL을 지원하기 위해 낮은 수준의 요청을 패치하는 방법이있을 수 있지만, 초기 조사에서 명백한 후크 포인트가없는 것 같아서이 간단한 접근 방식을 사용했습니다.
from https://stackoverflow.com/questions/10123929/python-requests-fetch-a-file-from-a-local-url by cc-by-sa and MIT license
'PYTHON' 카테고리의 다른 글
[PYTHON] 파이썬에서 코드 블록을 주석 처리하는 방법 [duplicate] (0) | 2018.11.07 |
---|---|
[PYTHON] Excel Python API (0) | 2018.11.07 |
[PYTHON] C / C ++ 프로그램에서 호출 된 여러 운영 체제 스레드에 대한 독립적 인 임베디드 Python 인터프리터 여러 개 (0) | 2018.11.07 |
[PYTHON] Python에서 피클 파일을로드하는 데 걸리는 시간을 줄이는 방법 (0) | 2018.11.07 |
[PYTHON] 임베디드 파이썬 중지 (0) | 2018.11.07 |