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

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

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

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

PHP

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

Q&A

解決済

1回答

2160閲覧

【PHP】【スクレイピング】取得した時に「空白の行」が自動追加されてしまう問題の解決方法【PHPQUERY】

shimane

総合スコア98

スクレイピング

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

PHP

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

0グッド

0クリップ

投稿2017/09/11 06:36

編集2017/09/11 08:27

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

勉強目的でスクレイピングを行うサイトを作成しています。

単純なサイトの記事タイトル・記事URLを取得して
mysqlにてデータベースに保存するという事は作成する事が出来ました。

次に、2段階のスクレイピングとして
トップページにてURLを取得して、
次にそのURLにアクセスして記事タイトルや投稿日時を取得して
mysqlにてデータベースに保存するという事もできるようになりました。


そこで今回、
スクレイピングによってトップページにあるリンクを複数取得して
次に1個1個のURLにアクセスしてそこで記事タイトルや画像のURLを取得するといったサイトを作成しています。

途中までは今までの勉強と似ている内容でしたので順調にいっていたのですが
エラーが発生していました。

【問題が発生して上手く行かない時の内容】

記事のタイトルや投稿日時等の情報を取得した時に
自動的に「空白の行」が追加されてしまいます。

最初はvar_dump()にて表示されていて
echoでは表示されていなかったので、試しにmysqlにて保存してみると
mysqlにも空白の行が追加されてしまっていました。
これだとデータベースでの操作で思ったような挙動が出来ないので
スクレイピングを行った時に自動的に空白の行が追加されないようにしたいです。

作成したコードです。

PHP

1try { 2 $db = new \PDO(DSN, DB_USERNAME, DB_PASSWORD); 3 $db->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION); 4 echo "データベースへの接続が出来ました"; 5}catch (\PDOException $e) { 6 7 echo $e->getMessage(); 8 exit; 9} 10 11require_once(__DIR__ . '/phpQuery-onefile.php'); 12 13// WEB用のスクレピングのURL 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', 'Shift_JIS')); 29 30// var_dump($doc); 31 32$i = 0; 33foreach ($doc[".MENU"] as $entry){ 34 35//ループ回数が5回を超えたらforeachを抜けます。 36if ($i >= 5 ) { 37 break; 38}else { 39 $i++; 40} 41 42//URLを取得 43$url1 = pq($entry)->find('p > a:eq(0)')->attr("href"); 44 45//URLを取得 46$url2 = pq($entry)->find('p > a:eq(2)')->attr("href"); 47 48//URLを取得 49$url3 = pq($entry)->find('p > a:eq(4)')->attr("href"); 50 51//次のスクレピングを行う為に、配列に追加してみました。 52$html2 = [ 53 $url1, 54 $url2, 55 $url3, 56]; 57 58} 59 60//配列の中にあるURLの数だけスクレピングを行いたいのでこのように設置しています。 61foreach($html2 as $html3) { 62 63 //cURLセッションを初期化する 64 $ch = curl_init(); 65 66 //URLとオプションを指定する 67 curl_setopt($ch, CURLOPT_URL, $html3); 68 curl_setopt($ch, CURLOPT_HEADER, false ); 69 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 70 curl_setopt($ch, CURLOPT_TIMEOUT, 30); 71 72 //URLの情報を取得する 73 $html3 = curl_exec($ch); 74 75 $doc = phpQuery::newDocument(mb_convert_encoding($html3, 'HTML-ENTITIES', 'Shift_JIS')); 76 77 $j = 0; 78 foreach ($doc[".container"] as $entry2){ 79 80//ループ回数が5回を超えたらforeachを抜けます。 81 if ($j >= 5 ) { 82 break; 83 }else { 84 $j++; 85 } 86 87// タイトル取得 88$title = pq($entry2)->find('.title:eq(0)')->text(); 89 90echo "<br />"; 91var_dump($title); 92 93// URL 94$url99 = pq($entry2)->find('.menuurl > a:eq(1)')->attr("href"); 95 96echo "<br />"; 97var_dump($url99); 98 99//mysqlに取得したタイトルとURLを書き込みで保存します。 100$sql = "insert into bbs (title, url, 101created) values (:title,:url,now()) 102ON DUPLICATE KEY UPDATE 103created = now() 104"; 105$stmt = $db->prepare($sql); 106$stmt->execute([ 107 ':title' => $title, 108 ':url' => $url99 109]); 110 111} 112} 113//セッションを終了する 114curl_close($ch); 115

プログラムの組み方に間違いがあり上手くいっていません。:
このように空白の行(string(0) "")が取得する度に入ってしまいます。
今回はタイトルとURLを取得しているので
2つの行のstring(0) ""が入ってしまっています。

string(0) "" string(0) "" string(161) "【ネット】新潟・米山隆一知事が石平氏投稿に「吐き気を催すほど醜悪」とツイート。「差別発言だ」との批判相次ぐ " string(54) "http://site-1.html" string(0) "" string(0) "" string(83) "【北朝鮮】アントニオ猪木議員、朝鮮労働党副委員長と会談 " string(54) "http://site-2.html" string(0) "" string(0) "" string(191) "【このハゲー!】豊田議員「辞めない」「必死で働き償う」" string(54) "http://site-3.html"

mysqlにて保存を行った際にも「空白の行」が間に挿入されてしまいます。

イメージ説明

これだとサイトに表示する際やデータベースの操作でも問題が起きてしまうので
なんとか「スクレイピングを実施した際に空白の行が入らない」ようにする為に
試行錯誤を何度も行ったのですが上手くいきません。

解決方法をご存知の方や
何かお気付きの点がありましたら教えて頂けると、とても嬉しいです。

お力をお貸し頂けたら嬉しいです。
どうかよろしくお願いします。

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

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

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

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

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

m.ts10806

2017/09/11 08:25 編集

細かいですが、今回は組み方の問題なのでおきている現象に対してエラーという表現は適当でないと思います。
shimane

2017/09/11 08:25

プログラムの勉強中のものですみません。失敗したらエラー(問題?)なのかと思っていました。今すぐに書き直してきますね、教えてくださってありがとうございます。 組み方の問題でうまくいきません という風に変更してみます。
m.ts10806

2017/09/11 08:27

主にエラーはプログラム側やサーバー側、DB側で処理中に処理を中断しなければならない現象(文法だったりメモリーだったり要因は色々)出力される内容です。今回はあくまで「組んだ結果、こういう現象が起きていて想定どおりに行かない」ので、エラーとは違う分類と解釈します。
shimane

2017/09/11 08:42

おおお、有難うございます。すっきりと理解できました。初心者にも分かりやすい説明のおかげで本当に助かりました!大感謝です。
guest

回答1

0

ベストアンサー

スクレイピングは、自身の管理下に無いデータを取り扱う物なので対象ページの状態によって想定したデータが取得できない、あるいは不正なタグ構造などでおかしなデータが取得される事がありえることを考慮してプログラムを作る必要があります。
ひとまず本コードにおいてデータベースに空のタイトルが保存されるのが問題なのであれば、保存する前にタイトルが空の時は処理を行わないようにすればよいかと思います。

// タイトル取得 $title = pq($entry2)->find('.title:eq(0)')->text(); if(empty(title)){ continue; }

投稿2017/09/11 16:04

aro10

総合スコア4106

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

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

shimane

2017/09/12 00:32

回答有難うございます。勉強中の身なので判断が付かないのですが、私が書いているコードには大きな間違い(空行のものが追加されてしまうような)が無くて、今回のようなものは取得先のサイト様に問題?があるという風に考えても大丈夫なのでしょうか? コードに問題が無いようでしたら、別の勉強を進めていこうと思います。
aro10

2017/09/12 04:15

改善点としては、findの引数のセレクタ等を改善すれば穴空きのデータが無くなるかと思いますが、今のところtitleが空のデータを無視で済むのであればこれでよいかと思います。 考え方として相手先のデータ取得の難度に合わせて、セレクタを調整するか取得後に判定によって振り分けるかを行うと良いかと思います。
shimane

2017/09/12 04:48

なるほど!とてもよく分かりました。今回は、教えて頂いた空白時のチェックでif判定を行っていって、他の勉強を進めていこうと思います。大感謝です!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問