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

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

ただいまの
回答率

90.35%

  • PHP

    22383questions

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

  • スクレイピング

    416questions

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

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

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 417

shimane

score 82

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

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

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

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


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

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

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

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

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

作成したコードです。

try {
  $db = new \PDO(DSN, DB_USERNAME, DB_PASSWORD);
  $db->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
  echo "データベースへの接続が出来ました";
}catch (\PDOException $e) {

  echo $e->getMessage();
  exit;
}

require_once(__DIR__ . '/phpQuery-onefile.php');

// WEB用のスクレピングのURL
$html = "取得したいサイトのURL";

//cURLセッションを初期化する
$ch = curl_init();

//URLとオプションを指定する
curl_setopt($ch, CURLOPT_URL, $html);
curl_setopt($ch, CURLOPT_HEADER, false );
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);

//URLの情報を取得する
$html =  curl_exec($ch);

$doc = phpQuery::newDocument(mb_convert_encoding($html, 'HTML-ENTITIES', 'Shift_JIS'));

// var_dump($doc);

$i = 0;
foreach ($doc[".MENU"] as $entry){

//ループ回数が5回を超えたらforeachを抜けます。
if ($i >= 5 ) {
  break;
}else {
  $i++;
}

//URLを取得
$url1 = pq($entry)->find('p > a:eq(0)')->attr("href");

//URLを取得
$url2 = pq($entry)->find('p > a:eq(2)')->attr("href");

//URLを取得
$url3 = pq($entry)->find('p > a:eq(4)')->attr("href");

//次のスクレピングを行う為に、配列に追加してみました。
$html2 = [
  $url1,
  $url2,
  $url3,
];

}

//配列の中にあるURLの数だけスクレピングを行いたいのでこのように設置しています。
foreach($html2 as $html3) {

  //cURLセッションを初期化する
  $ch = curl_init();

  //URLとオプションを指定する
  curl_setopt($ch, CURLOPT_URL, $html3);
  curl_setopt($ch, CURLOPT_HEADER, false );
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  curl_setopt($ch, CURLOPT_TIMEOUT, 30);

  //URLの情報を取得する
 $html3 =  curl_exec($ch);

  $doc = phpQuery::newDocument(mb_convert_encoding($html3, 'HTML-ENTITIES', 'Shift_JIS'));

  $j = 0;
  foreach ($doc[".container"] as $entry2){

//ループ回数が5回を超えたらforeachを抜けます。
    if ($j >= 5 ) {
      break;
    }else {
      $j++;
    }

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

echo "<br />";
var_dump($title);

// URL
$url99 = pq($entry2)->find('.menuurl > a:eq(1)')->attr("href");

echo "<br />";
var_dump($url99);

//mysqlに取得したタイトルとURLを書き込みで保存します。
$sql = "insert into bbs (title, url,
created) values (:title,:url,now())
ON DUPLICATE KEY UPDATE
created = now()
";
$stmt = $db->prepare($sql);
$stmt->execute([
  ':title' => $title,
  ':url' => $url99
]);

}
}
//セッションを終了する
curl_close($ch);

プログラムの組み方に間違いがあり上手くいっていません。:
このように空白の行(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にて保存を行った際にも「空白の行」が間に挿入されてしまいます。

イメージ説明

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

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

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

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • mts10806

    2017/09/11 17:23 編集

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

    キャンセル

  • shimane

    2017/09/11 17:25

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

    キャンセル

  • mts10806

    2017/09/11 17:27

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

    キャンセル

  • shimane

    2017/09/11 17:42

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

    キャンセル

回答 1

checkベストアンサー

+3

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

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/09/12 09:32

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

    キャンセル

  • 2017/09/12 13:15

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

    キャンセル

  • 2017/09/12 13:48

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

    キャンセル

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

  • ただいまの回答率 90.35%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る

  • PHP

    22383questions

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

  • スクレイピング

    416questions

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

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