1. はじめに
この時期かなり忙しくて、長い間ブログを書いていませんでした。今日は、curl_multi_* 関数セットの使用に関する私の経験と http リクエストの問題について話します。
ユーザー php が http リクエストを開始したとき。まず何を使用することを考えますか?そうです、リクエストに応じてcurlを作成します。 1 回の実行で複数の http リクエストを開始する必要がある場合はどうなるでしょうか。これは簡単で、URL ごとに URL リクエストを作成します。 1本目をプレイしてから2本目をプレイしてほしいとのリクエスト…これで終わりですか?他に何が言えますか?
公式サイトリンク: http://php.net/manual/zh/book.curl.php
2. 複数の単純なcurlリクエストのデメリット
クリをあげましょう。現在 3 つの http リクエストがあります。各リクエストには 2 秒かかります。単純なcurlリクエストに従う場合(図1-(1))。 6秒もかかったのは耐えられない。リクエストが多ければ多いほど、時間がかかります。
クエリ時間を短縮する方法はありますか? 3つのhttpリクエストを同時に実行できますか(図1-(1))。この問題を解決して時間を 2 秒に短縮する方法はたくさんあります。例: マルチプロセス、スレッド、イベント ループ、curl_multi_* など。最も簡単な方法は、curl_multi_* 関数を使用することです。実際、curl_multi_* の内部実装ではイベント ループが使用されます。
3. シンプルなcurl_multi_*アプリケーション
<code><span><?php</span><span>/** * * curl_multi_*简单运用 * *<span> @author</span>: rudy *<span> @date</span>: 2016/07/12 */</span><span>/** * 根据url,postData获取curl请求对象,这个比较简单,可以看官方文档 */</span><span><span>function</span><span>getCurlObject</span><span>(<span>$url</span>,<span>$postData</span>=array<span>()</span>,<span>$header</span>=array<span>()</span>)</span>{</span><span>$options</span> = <span>array</span>(); <span>$url</span> = trim(<span>$url</span>); <span>$options</span>[CURLOPT_URL] = <span>$url</span>; <span>$options</span>[CURLOPT_TIMEOUT] = <span>10</span>; <span>$options</span>[CURLOPT_USERAGENT] = <span>'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.89 Safari/537.36'</span>; <span>$options</span>[CURLOPT_RETURNTRANSFER] = <span>true</span>; <span>// $options[CURLOPT_PROXY] = '127.0.0.1:8888';</span><span>foreach</span>(<span>$header</span><span>as</span><span>$key</span>=><span>$value</span>){ <span>$options</span>[<span>$key</span>] =<span>$value</span>; } <span>if</span>(!<span>empty</span>(<span>$postData</span>) && is_array(<span>$postData</span>)){ <span>$options</span>[CURLOPT_POST] = <span>true</span>; <span>$options</span>[CURLOPT_POSTFIELDS] = http_build_query(<span>$postData</span>); } <span>if</span>(stripos(<span>$url</span>,<span>'https'</span>) === <span>0</span>){ <span>$options</span>[CURLOPT_SSL_VERIFYPEER] = <span>false</span>; } <span>$ch</span> = curl_init(); curl_setopt_array(<span>$ch</span>,<span>$options</span>); <span>return</span><span>$ch</span>; } <span>// 创建三个待请求的url对象</span><span>$chList</span> = <span>array</span>(); <span>$chList</span>[] = getCurlObject(<span>'https://www.baidu.com'</span>); <span>$chList</span>[] = getCurlObject(<span>'http://www.jd.com'</span>); <span>$chList</span>[] = getCurlObject(<span>'http://www.jianshu.com/'</span>); <span>// 创建多请求执行对象</span><span>$downloader</span> = curl_multi_init(); <span>// 将三个待请求对象放入下载器中</span><span>foreach</span> (<span>$chList</span><span>as</span><span>$ch</span>){ curl_multi_add_handle(<span>$downloader</span>,<span>$ch</span>); } <span>// 轮询</span><span>do</span> { <span>while</span> ((<span>$execrun</span> = curl_multi_exec(<span>$downloader</span>, <span>$running</span>)) == CURLM_CALL_MULTI_PERFORM) ; <span>if</span> (<span>$execrun</span> != CURLM_OK) { <span>break</span>; } <span>// 一旦有一个请求完成,找出来,处理,因为curl底层是select,所以最大受限于1024</span><span>while</span> (<span>$done</span> = curl_multi_info_read(<span>$downloader</span>)) { <span>// 从请求中获取信息、内容、错误</span><span>$info</span> = curl_getinfo(<span>$done</span>[<span>'handle'</span>]); <span>$output</span> = curl_multi_getcontent(<span>$done</span>[<span>'handle'</span>]); <span>$error</span> = curl_error(<span>$done</span>[<span>'handle'</span>]); <span>// 将请求结果保存,我这里是打印出来</span><span>print</span><span>$output</span>; <span>// print "一个请求下载完成!\n";</span><span>// 把请求已经完成了得 curl handle 删除</span> curl_multi_remove_handle(<span>$downloader</span>, <span>$done</span>[<span>'handle'</span>]); } <span>// 当没有数据的时候进行堵塞,把 CPU 使用权交出来,避免上面 do 死循环空跑数据导致 CPU 100%</span><span>if</span> (<span>$running</span>) { <span>$rel</span> = curl_multi_select(<span>$downloader</span>, <span>1</span>); <span>if</span>(<span>$rel</span> == -<span>1</span>){ usleep(<span>1000</span>); } } <span>if</span>( <span>$running</span> == <span>false</span>){ <span>break</span>; } } <span>while</span> (<span>true</span>); <span>// 下载完毕,关闭下载器</span> curl_multi_close(<span>$downloader</span>); <span>echo</span><span>"所有请求下载完成!"</span>;</span></code>
この例では、まずリクエストするURLリクエストオブジェクトを3つ以上作成します。 curl_multi_* 関数を使用してダウンローダーを作成します。リクエストをダウンローダーに書き込みます。最後の投票。現在 3 つのリクエストが完了するのを待っています。加工を行います。
4. 複雑なcurl_multi_*の使用法
これがcurl_multi_*の使用方法ですか?シンプルすぎる!上の例では。ダウンローダー $downloader 内のリクエストは最初から追加されます。ダウンローダーにリクエストを動的に追加できますか。完了したリクエストをダウンローダーから動的に取得します。考えてみてください。これは何ですか?これがクローラーの中核部分、つまりダイナミックダウンローダーではないでしょうか。動的に追加するにはどうすればよいですか?マルチプロセスを使用して IPC 経由で追加できます。コルーチンを介してキューに待機を追加できます。
').addClass('事前番号付け').hide(); $(this).addClass('has-numbering').parent().append($numbering); for (i = 1; i ').text(i)); }; $numbering.fadeIn(1700); }); });コルーチン+curl_multi_*を介してクローラーフレームワークを実装しました。
Tspider: https://github.com/hirudy/Tspider。
1 つのプロセスで 2000 ~ 5000/分のリクエストを処理できます。
上記は、PHP で設定されたcurl_multi関数の使用法を、関連する内容も含めて紹介しました。PHP チュートリアルに興味のある友人に役立つことを願っています。