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

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

新規登録して質問してみよう
ただいま回答率
85.50%
スクレイピング

スクレイピングとは、公開されているWebサイトからページ内の情報を抽出する技術です。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

2回答

7565閲覧

python3で非同期スクレイピングがしたいけど非同期がよくわからない

kurosuke___

総合スコア217

スクレイピング

スクレイピングとは、公開されているWebサイトからページ内の情報を抽出する技術です。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

1クリップ

投稿2017/05/06 18:36

概要

  • スクレイピングはBeautifulSoup4
  • async, await がよく分かってない
  • どうやらurllib.requestのurlopenは同期処理?なのでaiohttpを使うのかな?

やりたいこと

たとえば、ユニークなドメインのURLが10個あって、すべてのURLからbodyタグ内を引っ張ってきたいとしたとき。

一つのURLに対してのリクエストは一回だけなので、10個のURLを1個ずつ処理するより並列でそれぞれ処理(HTTPリクエスト?)したほうが、取得する順番はどうでもいいですし、処理にかかる時間を相当短縮できるのでは?と思ったわけです。
(全然並列処理について分かってないのでトンチンカンなこと言ってたら叱ってください)

ここ2日ほどGoogle先生やQiitaで調べまくってみましたが、色々な書き方や事例がありすぎていまいちよく分かってません・・・
(単に頭が弱いというのが一番かもしれないですが)

拾ってきたコードをデバッグして処理を追ってみたりしましたが、あまり効果はなかったようです。

というわけで、**複数のURLを1つずつではなく、いっぺんに処理がしたい。**というのが私の願望でございます。

教えてください

  • 超個人的にはPython3.5からのasync/awaitを使用していきたい(使い方分かってないけど...)です

  • async/awaitの使い方を含めて、上記のような非同期スクレイピングをするにはどういったコードを書くのが良いでしょうか?

  • とにかく**複数のURLを1つずつではなく、いっぺんに処理がしたい。**ので、なんでも構いません、なにか方法を教えてください。

よろしくお願いします。

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

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

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

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

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

guest

回答2

0

ベストアンサー

目的は10並列程度の並列処理のようなので非同期処理を手段にする必要性はあまりないと私は思います。非同期処理を使用すればシングルスレッドで効率的な処理が実現できるという側面もありますが、取っ付きやすさの面からスレッドで処理の多重度を上げる方法を提案します。スレッドでの実現方法も色々とありますがconcurrent.futures.ThreadPoolExecutorが一押しです。以下がrequestsモジュールを使用して複数回ググるサンプルです。

from concurrent.futures import ThreadPoolExecutor import requests urls = [ 'https://google.com/?q=python', 'https://google.com/?q=teratail' ] with ThreadPoolExecutor() as pool: for res in pool.map(requests.get, urls): print(res.status_code, 'url=', res.url)

投稿2017/05/06 19:06

YouheiSakurai

総合スコア6142

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

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

kurosuke___

2017/05/07 04:42

回答ありがとうございます! なるほど、これはいいものですね。 ただ、submitとmapの違いがわかりません。 どういったように使い分けるのでしょうか?
YouheiSakurai

2017/05/07 06:47

submitは一個ずつタスクを登録する、結果の取得は自分で面倒をみるという感じです。一方、mapは一括でタスクを登録して終わったものから結果を取得する感じです。
kurosuke___

2017/05/07 12:37

なるほど、mapのほうがよしなにしてくれていい感じですね。 メリット・デメリット有るかと思いますが、現状「とっつきやすさ」が貢献して、とりあえずやりたいことができそうなので、こちらを使ってみることにします。 ありがとうございました!
guest

0

ドンピシャの記事ありましたよ↓

Python3.5のasync/awaitを使ってスクレイピング - Qiita

既にある回答のとおりスレッドプールを使う手もあるのですが,async/awaitを使えば1スレッドだけで完結するのでCPUには優しいです。HTTPリクエストに関してはボトルネックのほとんどが待ち時間なので,1スレッドのほうが適役です。


【蛇足】

上記の記事で

デコレータと yield from でやってたやつになんかそれっぽい構文が出来たよっていう感じにしか見えない。

という言及がありますが,これはPythonだけに限らず,例えばJavaScriptに関しても同じようなことがいえますね。もとはジェネレータを目的外使用することで無理やり実現していたけど,やっぱり何か違うので専用構文を用意しよう,という流れです。

JavaScriptは如何にしてAsync/Awaitを獲得したのか Qiita版 - Qiita

PHPに関してはまだ残念ながらジェネレータでしかそれっぽいことはできません。

mpyw/co: Asynchronous cURL executor simply based on resource and Generator.

PHPの派生のHack/HHVMはasync/awaitを言語レベルで持っています。

Async: Introduction

以上,蛇足でした…

投稿2017/05/07 07:15

編集2017/05/07 07:22
mpyw

総合スコア5223

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

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

mpyw

2017/05/07 07:35 編集

async/awaitに関しては蛇足で挙げたJavaScriptに関する記事が参考になると思います。Pythonにおいては,async関数の返り値はPromiseではなく単なるCoroutineオブジェクト(「並行処理目的のGenerator」と同義)であり,thenメソッドなどは持っていませんが,await対象に取れるという点では同じです。
kurosuke___

2017/05/07 12:33

回答ありがとうございます! ご提示いただいた記事はすでに読ませていただいておりましたが、今の私ではやはり難しい内容でした・・・ YouheiSakuraiさんにご提案いただいたThreadPoolExcecutorは割りととっつきやすいので、まずはそちらをすんなりかけるように理解できてから、async/awaitに挑戦したいと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問