1

Requests lib を使用してリモート Web サービスへの要求を開始する Python スクリプトを作成します。ここに私のコード(test.py)があります:

import logging.config
from requests import Request, Session

logging.config.fileConfig('../../resources/logging.conf')
logr = logging.getLogger('pyLog')
url = 'https://158.74.36.11:7443/hqu/hqapi1/user/get.hqu'
token01 = 'hqstatus_python'
token02 = 'ytJFRyV7g'
response_length = 351

def main():
    try:
        logr.info('start SO example')

        s = Session()
        prepped = Request('GET', url, auth=(token01, token02), params={'name': token01}).prepare()
        response = s.send(prepped, stream=True, verify=False)

        logr.info('status: ' + str(response.status_code))
        logr.info('elapsed: ' + str(response.elapsed))
        logr.info('headers: ' + str(response.headers))
        logr.info('content: ' + response.raw.read(response_length).decode())


    except Exception: 
        logr.exception("Exception")
    finally:
        logr.info('stop')


if __name__ == '__main__':
    main()

これを実行すると、次の成功した出力が得られます。

INFO test - start SO example
INFO test - status: 200
INFO test - elapsed: 0:00:00.532053
INFO test - headers: CaseInsensitiveDict({'server': 'Apache-Coyote/1.1', 'set-cookie': 'JSESSIONID=8F87A69FB2B92F3ADB7F8A73E587A10C; Path=/; Secure; HttpOnly', 'content-type': 'text/xml;charset=UTF-8', 'transfer-encoding': 'chunked', 'date': 'Wed, 18 Sep 2013 06:34:28 GMT'})
INFO test - content: <?xml version="1.0" encoding="utf-8"?>
<UserResponse><Status>Success</Status> .... </UserResponse>
INFO test - stop

ご覧のとおり、コンテンツを読み取れるようにするために応答オブジェクト (オプションの引数) に渡す必要がある、この奇妙な変数 'response_length' があります。この変数は、「コンテンツ」の長さと等しい数値に設定する必要があります。これは明らかに、response-content-length を事前に知る必要があることを意味しますが、これは不合理です。

その変数を渡さないか、コンテンツの長さよりも大きい値に設定すると、次のエラーが発生します。

Traceback (most recent call last):
  File "\Python33\lib\http\client.py", line 590, in _readall_chunked
    chunk_left = self._read_next_chunk_size()
  File "\Python33\lib\http\client.py", line 562, in _read_next_chunk_size
    return int(line, 16)
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xb4 in position 0: invalid start byte

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "test.py", line 22, in main
    logr.info('content: ' + response.raw.read().decode())
  File "\Python33\lib\site-packages\requests\packages\urllib3\response.py", line 167, in read
    data = self._fp.read()
  File "\Python33\lib\http\client.py", line 509, in read
    return self._readall_chunked()
  File "\Python33\lib\http\client.py", line 594, in _readall_chunked
    raise IncompleteRead(b''.join(value))
http.client.IncompleteRead: IncompleteRead(351 bytes read)

この「response_length」変数なしでこれを機能させるにはどうすればよいですか? また、「リクエスト」ライブラリよりも優れたオプションはありますか?

PS: このコードは独立したスクリプトであり、Django フレームワークでは実行されません。

4

2 に答える 2

4

内部の代わりにパブリック APIを使用し、コンテンツの長さとライブラリへの読み取りについて心配する必要はありません。

import requests

s = requests.Session()
s.verify = False
s.auth = (token01, token02)
resp = s.get(url, params={'name': token01}, stream=True)
content = resp.content

または、以降stream=Trueresp.rawファイル オブジェクトを使用できます。

for line in resp.iter_lines():
    # process a line

また

for chunk in resp.iter_content():
    # process a chunk

ファイルのようなオブジェクトが必要な場合は、resp.raw使用できます (stream=True上記のようにリクエストで設定されている場合) が、EOF まで読み取るために長さのない.read()呼び出しを使用するだけです。

ただし、ストリーミングが必要なリソース (大きなファイルのリクエスト、最初にヘッダーをテストする必要がある場合、またはストリーミング サービスとして明示的に文書化されている Web サービスを除く) をクエリしていない場合は、 を省略して、またはstream=Trueを使用します。バイトまたはユニコード応答データ用。resp.contentresp.text

ただし、最終的には、サーバーが不正な形式または不完全なチャンク応答を送信しているように見えます。チャンク転送エンコーディングには各チャンクの長さ情報が含まれており、サーバーはチャンクの長さについて嘘をついている、または特定のチャンクに対して送信するデータが少なすぎるように見えます。デコード エラーは、不完全なデータが送信された結果にすぎません。

于 2013-09-18T07:01:09.043 に答える