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

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

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

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

cURL

cURLはHTTP, FTPやTelnetなど複数のプロトコルを用いてデータを転送するライブラリとコマンドラインツールを提供します。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

Q&A

解決済

1回答

1748閲覧

【PHP】【PHPQUERY】複数のURLを実行する方法【curl】【スクレイピング】

shimane

総合スコア98

スクレイピング

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

cURL

cURLはHTTP, FTPやTelnetなど複数のプロトコルを用いてデータを転送するライブラリとコマンドラインツールを提供します。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

0グッド

0クリップ

投稿2017/08/23 12:21

現在、PHPの勉強をしているものです。

スクレイピングについての勉強をしていまして
ネットで調べたり、書籍で調べたりして一般的なスクレイピングが出来るようになれました。

そこで今回、1歩進んで「複数のURL」を配列に入れて
スクレイピングを実行するという方法について調べてみたのですが、
何度やっても上手くいかず、質問をさせて頂きました。


【実行した事】
file_get_contentsよりも「cURL」の方が処理が速いとネットで見かけまして
cURLを使っています。

PHP

1 2try { 3 $db = new \PDO(DSN, DB_USERNAME, DB_PASSWORD); 4 $db->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION); 5 echo "データベースへの接続が出来ました<br />"; 6}catch (\PDOException $e) { 7 8 echo $e->getMessage(); 9 exit; 10} 11 12require_once(__DIR__ . '/phpQuery-onefile.php'); 13 14$html = "対象のURL"; 15 16//cURLセッションを初期化する 17$ch = curl_init(); 18 19//URLとオプションを指定する 20curl_setopt($ch, CURLOPT_URL, $html); 21curl_setopt($ch, CURLOPT_HEADER, false ); 22curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 23curl_setopt($ch, CURLOPT_TIMEOUT, 30); 24 25//URLの情報を取得する 26$html = curl_exec($ch); 27 28$doc = phpQuery::newDocument(mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8')); 29 30//ループ回数の指定 31$i = 0; 32foreach ($doc[".kiji-body"] as $entry){ 33 34//10回でループの終了 35if ($i >= 10 ) { 36 break; 37}else { 38 $i++; 39} 40 41// タイトル 42$title = pq($entry)->find('.title')->text(); 43 44if(!isset($title)) { 45 break; 46} 47 48// コメント数取得 49$comment = pq($entry)->find('.comment')->text(); 50 51// 最新コメントの日付取得 52$youbipattern = '/\(日\)|\(月\)|\(火\)|\(水\)|\(木\)|\(金\)|\(土\)/'; 53$youbispeace = ""; 54$date1 = preg_replace($youbipattern, $youbispeace, $comment); 55 56// URLを取得 57$url = pq($entry)->find('a')->attr("href"); 58 59$title = h($title); 60$comment = h($comment); 61$date1 = h($date1); 62$url = h($url); 63 64$sql = "insert into bbs (title, url, comment, date) values (:title,:url,:comment,:date) 65ON DUPLICATE KEY UPDATE 66comment = $comment 67"; 68$stmt = $db->prepare($sql); 69$stmt->execute([ 70 ':title' => $title, 71 ':url' => $url, 72 ':comment' => $comment, 73 ':date' => $date1 74]); 75 76 77} 78 79//セッションを終了する 80curl_close($ch); 81 82 83

上のコードで1つのURLに対してのスクレイピングを実行する事が出来ました。

そこで次に2段階で
1回スクレイピングで取得したURLを配列に入れて
その後に配列に入っているURLのスクレイピングを実行しようとしてみます。

PHP

1 2 3try { 4 $db = new \PDO(DSN, DB_USERNAME, DB_PASSWORD); 5 $db->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION); 6 echo "データベースへの接続が出来ました<br />"; 7}catch (\PDOException $e) { 8 9 echo $e->getMessage(); 10 exit; 11} 12 13require_once(__DIR__ . '/phpQuery-onefile.php'); 14 15 16//別のスクレイピングで取得したURLを配列に追加していきます。 17//この配列に入っているURLを使ってスクレイピングを実行したいと思っています。 18$html[] = $url2; 19 20//cURLセッションを初期化する 21$ch = curl_init(); 22 23//URLとオプションを指定する 24curl_setopt($ch, CURLOPT_URL, $html); 25curl_setopt($ch, CURLOPT_HEADER, false ); 26curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 27curl_setopt($ch, CURLOPT_TIMEOUT, 30); 28 29//URLの情報を取得する 30$html = curl_exec($ch); 31 32$doc = phpQuery::newDocument(mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8')); 33 34//ループ回数の指定 35$i = 0; 36foreach ($doc[".kiji-body"] as $entry){ 37 38//10回でループの終了 39if ($i >= 10 ) { 40 break; 41}else { 42 $i++; 43} 44 45// タイトル 46$title = pq($entry)->find('.title')->text(); 47 48if(!isset($title)) { 49 break; 50} 51 52// コメント数取得 53$comment = pq($entry)->find('.comment')->text(); 54 55// 最新コメントの日付取得 56$youbipattern = '/\(日\)|\(月\)|\(火\)|\(水\)|\(木\)|\(金\)|\(土\)/'; 57$youbispeace = ""; 58$date1 = preg_replace($youbipattern, $youbispeace, $comment); 59 60// URLを取得 61$url = pq($entry)->find('a')->attr("href"); 62 63$title = h($title); 64$comment = h($comment); 65$date1 = h($date1); 66$url = h($url); 67 68$sql = "insert into bbs (title, url, comment, date) values (:title,:url,:comment,:date) 69ON DUPLICATE KEY UPDATE 70comment = $comment 71"; 72$stmt = $db->prepare($sql); 73$stmt->execute([ 74 ':title' => $title, 75 ':url' => $url, 76 ':comment' => $comment, 77 ':date' => $date1 78]); 79 80 81} 82 83//セッションを終了する 84curl_close($ch); 85

【発生したエラー】

こちらの行にエラー発生:
curl_setopt($ch, CURLOPT_URL, $html2);

エラー文言
Notice: Array to string conversion
日本語訳:配列から文字列への変換

【対処してみた方法】
配列を文字列に変換してみたらいいのでは?と考え

ネットで調べてみた結果「implode($html2)」を試してみる事にしたのですが
curl_setopt($ch, CURLOPT_URL, implode($html2));

実行した所、「URLが存在しません」として取得できず
mysqlにも登録する事が出来ませんでした。

【色々試してみた所】

curl_setopt($ch, CURLOPT_URL, $html2[0]);

としてみると「1つのURL」だけは取得が成功してmysqlへの登録も出来ました。

1つのURLの取得は出来たのですが
配列の中に入っている複数のURLを実行する事が何度試してみても上手くいきません。

解決方法をご存知の方、何かお気付きになられた方は
お力をお貸し頂けると嬉しいです。
お願いします。

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

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

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

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

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

guest

回答1

0

ベストアンサー

ループの前にurl配列を作成し、foreachでループします。
以下の例ですと$valueにurlが入ってくるので、あとはループ内で1件の処理と同様の記述で行けるのではないかと思います。

PHP

1$html[] = 'url1'; 2$html[] = 'url2'; 3$html[] = 'url3'; 4 5foreach($html as $value) { 6 //cURLセッションを初期化する 7 $ch = curl_init(); 8 9 //URLとオプションを指定する 10 curl_setopt($ch, CURLOPT_URL, $value); 11 curl_setopt($ch, CURLOPT_HEADER, false ); 12 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 13 curl_setopt($ch, CURLOPT_TIMEOUT, 30); 14 15 //URLの情報を取得する 16 $html = curl_exec($ch); 17}

投稿2017/08/23 12:36

mayoi_maimai

総合スコア1583

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

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

shimane

2017/08/23 14:59

素晴らしいです、実現することが出来ました!悩みに悩んでいた事なので本当に助かりました。大感謝です!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問