質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

解決済

2回答

684閲覧

コードレビューしてほしい: ストリーミング処理でGETしたい

yosukesan

総合スコア34

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

0グッド

1クリップ

投稿2023/01/08 19:03

編集2023/01/08 19:18

正規表現で抜き出した複数の URL へのストリーム処理で GET をしたいのですが、ネットワーク系の経験があまりなく、以下で良いのか判断できていません。

for loop 中の id(resp) が変っています。この場合、resp が新しく作成されたタイミングで自動的に timeout するのでしょうか?

shadow variable を許す言語なので resp が破棄されるのが関数を出るタイミングだったと記憶しています。そのため、以下の Keep-Alive のセクションを読む限り大量に timeout していない resp が残ったままになるのではないかと考えています。
https://requests.readthedocs.io/en/latest/user/advanced/#session-objects

for loop の中で get() の後に resp.close() した方が良いのでしょうか?しかし、そのようにするとストリーミング処理した意味がなくなってしまうのではないかと思うのですが...

最後に他にサーバー側に負荷を掛けずに、もっと効率的に処理する方法などありましたらご指摘ください。

ses = requests.Session() resp = ses.get(self.URLS['short_ratio'], stream=True, timeout=3) resp.encoding = resp.apparent_encoding url_chars = '[0-9a-zA-Z\/\-\_]*' urls_xls = [] urls_xls += re.findall('{0}\.xls?'.format(url_chars), resp.text) for p in re.findall('{0}\d\d-archives-\d\d\.html?'.format(url_chars): resp = ses.get('{0}{1}'.format(self.BASE_URL, p), stream=True, timeout=3) print(id(ses), id(resp)) print(resp.cookies) resp.encoding = resp.apparent_encoding urls_xls += re.findall('{0}\.xls?'.format(url_chars), resp.text) resp.close() ses.close()
$ pytest-3 -s pandas_datareader/tests/test_tse.py ============================= test session starts ============================== platform linux -- Python 3.9.2, pytest-6.0.2, py-1.10.0, pluggy-0.13.0 rootdir: ************************************, configfile: setup.cfg collected 1 item pandas_datareader/tests/test_tse.py 140171185815120 140171185185648 <RequestsCookieJar[]> 140171185815120 140171185566768 <RequestsCookieJar[]> 140171185815120 140171185366880 <RequestsCookieJar[]> 140171185815120 140171185567056 <RequestsCookieJar[]> 140171185815120 140171185368752 <RequestsCookieJar[]> 140171185815120 140171185568448 <RequestsCookieJar[]> 140171185815120 140171185366880 <RequestsCookieJar[]> 140171185815120 140171185568736 <RequestsCookieJar[]> 140171185815120 140171185368752 <RequestsCookieJar[]> 140171185815120 140171185568688 <RequestsCookieJar[]> 140171185815120 140171185366880 <RequestsCookieJar[]> 140171185815120 140171185568688 <RequestsCookieJar[]> . ============================== 1 passed in 3.33s ===============================

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

まず、前提として:

クライアント(手元のパソコン)がサーバー(相手のパソコン)にリクエスト(ses.get(url))を送ると、サーバーがクライアントにレスポンス(resp)を返します。
この際、クライアントからのリクエストに対してサーバーが一定時間応答しないと、タイムアウト(時間切れ)としてリクエストの送信をやめ、レスポンスを受け取ることを諦めます。

resp が新しく作成されたタイミングで自動的に timeout するのでしょうか?

この質問は、上記の前提を理解していないために生まれた疑問と推測します。resp が受け取れたのであれば、セッションはタイムアウトしてません。

resp.close() した方が良いのでしょうか?

ドキュメントにもありますが、明確な理由がない限り手動でレスポンスを閉じる必要はありません。閉じるならばセッションです。ですが、for 文の中でセッションを閉じては元も子もないので、提示されているコードの通り、全てのリクエストが終わった後で問題ありません。

複数の URL へのストリーム処理で GET をしたい

提示されているコードでは、stream=True オプションを利用している意味がありません。実際のコードでは、respiter_lines() で回していたりするのでしょうか?失礼ですが、「ストリーム処理」という単語の意味を勘違いされていませんか?ここでいうストリーム処理(stream=True)は、大きなサイズのコンテンツ(画像や動画といったバイナリ、または OS のイメージファイルなど)を細かく分けて断片的に少しづつレスポンスを受け取ることを指します。提示されているコードでは、テキストベースのレスポンスを直接 resp.text としているのであまり意味がないように感じました。

最後に他にサーバー側に負荷を掛けずに、もっと効率的に処理する方法などありましたらご指摘ください。

各リクエストの送信間隔を 1 秒程度開けることが推奨されています。time という標準ライブラリのモジュールを利用して、for 文の最後に time.sleep(1) を追加します。

python

1import time 2 3import requests 4 5urls = [ 6 "https://httpbin.org/get", 7 "https://httpbin.org/json", 8 "https://httpbin.org/robots.txt", 9] 10 11session = requests.Session() 12 13resp = session.get("https://httpbin.org/xml") 14print(id(session), id(resp)) 15 16for url in urls: 17 18 response = session.get(url, timeout=3.0) 19 print(id(session), id(response)) 20 time.sleep(1) 21 22session.close() 23

もう一つ、コンテキストマネージャーを利用すると、セッションを手動で閉じる必要がなく安心してリクエストを送信できます。

python

1import time 2 3import requests 4 5urls = [ 6 "https://httpbin.org/get", 7 "https://httpbin.org/json", 8 "https://httpbin.org/robots.txt", 9] 10 11with requests.Session() as session: 12 13 resp = session.get("https://httpbin.org/xml") 14 print(id(session), id(resp)) 15 16 for url in urls: 17 18 response = session.get(url, timeout=3.0) 19 print(id(session), id(response)) 20 time.sleep(1) 21

投稿2023/01/09 02:01

Demerara

総合スコア397

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yosukesan

2023/01/09 02:18 編集

ご回答ありがとうございました。 > 失礼ですが、「ストリーム処理」 ご指摘の通り、ストリーム処理を含めネットワーク関連は理解できていない部分が多いです。 > この質問は、上記の前提を理解していないために生まれた疑問と推測します。resp が受け取れたのであれば、セッションはタイムアウトしてません。 ちなみに、タイムアウトしたかどうか確認する方法はありますか? > 提示されているコードでは、stream=True オプションを利用している意味がありません。実際のコードでは、resp を iter_lines() で回していたりするのでしょうか?失礼ですが、「ストリーム処理」という単語の意味を勘違いされていませんか?ここでいうストリーム処理(stream=True)は、大きなサイズのコンテンツ(画像や動画といったバイナリ、または OS のイメージファイルなど)を細かく分けて断片的に少しづつレスポンスを受け取ることを指します。提示されているコードでは、テキストベースのレスポンスを直接 resp.text としているのであまり意味がないように感じました。 ご指摘の通り勘違いしておりました。 > ドキュメントにもありますが、明確な理由がない限り手動でレスポンスを閉じる必要はありません。閉じるならばセッションです。ですが、for 文の中でセッションを閉じては元も子もないので、提示されているコードの通り、全てのリクエストが終わった後で問題ありません。 わかりました。
yosukesan

2023/01/09 03:24

追加回答ありがとうございました。
guest

0

ChatGPT

1あなたのコードでは、Session オブジェクトを使用しています。Session オブジェクトは、特に指定されない限り、自動的に HTTP Keep-Alive ヘッダーを送信します。これにより、Web サーバーとの接続を維持し、再接続を行わずに複数の HTTP 要求を送信することができます。つまり、Session オブジェクトを使用することで、再接続を行わずに複数の HTTP 要求を送信できるため、負荷をかけずに効率的に処理することができます。 2 3さらに、Session オブジェクトは、内部でプールされた HTTP コネクションを管理します。そのため、同じ Session オブジェクトを使用して複数の HTTP 要求を送信する場合、同じ HTTP コネクションを使用することができます。これにより、再接続を行わずに複数の HTTP 要求を送信できるため、さらに効率的に処理することができます。 4 5ですので、for ループ内での resp.close() は必要ありません。また、resp オブジェクトは、Session オブジェクトを使用して送信された HTTP 要求に対する応答を表すものですので、それぞれの Session.get() 呼び出しで新しい resp オブジェクトが生成されます。 6 7さらに、ストリームを使用することで、応答ボディをサーバーから受信しながら、それを読み込むことができます。これにより、必要に応じて逐次的に応答ボディを処理しながら、メモリを効率的に使用することができます。 8 9最後に、複数の URL への HTTP 要求を効率的に送

投稿2023/01/08 21:43

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問