現在、PHPでサイトからデータを抽出してSQLに読み込む練習をしています。

20件ほどいろいろなサイトの抽出を自分で試した結果、取得できるものと取得できないものが出てきました。
そのうちのいくつかのサイトはどこがおかしかったのか原因自体がわからないので、どなたか抽出の模範回答をお願いします。

データベース名:headline、テーブル名:datalist、フィールド名はblogtitle、url、sourcetitleの3つです。
http://blog.livedoor.com/category/111/ranking.html
抽出したいのはブログ名とURLです。

上のURL先のソースを読み取り、ランキング先の20個のブログタイトルとURLを、SQLに入力するようなものを考えています。
対応する「sourcetitle」フィールドには、上のURLのタイトル…つまりhttp://blog.livedoor.com/category/111/ranking.htmlのタイトルである、「今日のできごと : 日記 : ランキング - ライブドアブログ」という文字が入力されます。

練習中ですので、なるべくわかりやすく書いていただけると大変助かります。
どうかよろしくお願いします。

回答の条件
  • 1人5回まで
  • 登録:
  • 終了:2011/02/21 22:35:05
※ 有料アンケート・ポイント付き質問機能は2023年2月28日に終了しました。

回答3件)

id:asuka645 No.1

回答回数856ベストアンサー獲得回数97

ポイント35pt

以下のような感じでどうでしょう。


ご質問にあるランキングのURLは配列 $items[N]['url'] に、タイトルは $items[N]['sourcetitle'] に格納するようにしてあります。Nは1~20の整数です。


SQLへの展開をどのような形で行っているのか分からなかったので、ここでは省略しています。

<?php
$url = 'http://blog.livedoor.com/category/111/ranking.html';  //ターゲット
$source_encoding   = 'EUC-JP';  //ターゲットのエンコード
$internal_encoding = 'UTF-8';   //本スクリプトのエンコード
mb_internal_encoding($internal_encoding);

//抽出パターン
$pat = "/<span class=\"number[^\"]*\">[0-9]+<\/span>.*<a href=\"([^\"]+)\">(.+)<\/a>/iu";

$cnt = 1;
$items = array();
$fp = fopen($url, 'r');
//1行ずつ読み込んで抽出,配列$itemsへ格納
while (! feof($fp)) {
    $str = fgets($fp);
    $str = mb_convert_encoding($str, $internal_encoding, $source_encoding);
    if (preg_match($pat, $str, $ary) > 0) {
        $items[$cnt]['url'] = $ary[1];
        $items[$cnt]['sourcetitle'] = $ary[2];
        $cnt++;
    }
}
fclose($fp);

//表示
var_dump($items);
?>
id:holoholobird

指定したURLのソースを読み取り、

データベース名:headline、テーブル名:datalist、フィールド名が順にblogtitle、url、sourcetitleとなるmySQLのデータベースに登録したいのです。

たとえばhttp://blog.livedoor.com/category/111/ranking.htmlだと

Olz Weblog:http://blog.livedoor.jp/olzjp/:今日のできごと : 日記 : ランキング - ライブドアブログ

人名力:http://blog.livedoor.jp/namepower/:今日のできごと : 日記 : ランキング - ライブドアブログ

嵌る日常:http://shinji.livedoor.biz/:今日のできごと : 日記 : ランキング - ライブドアブログ

みたいに自動でSQLに登録されるPHPを作成したいのですが、書き方が悪かったのでしょうか。


恥ずかしながら

>SQLへの展開をどのような形で行っているのか

という文章の意味が理解できませんでしたので、どういう意味か教えていただけると助かります。

2011/02/15 04:16:47
id:windofjuly No.2

回答回数2625ベストアンサー獲得回数1149

ポイント35pt

>取得できるものと取得できないものが出てきました

正規表現のパターンが今ひとつなのかもしれません

データベース関連はひとまず横において、下のような具合にして「取得成功/失敗の違いを洗い出す」ことをまずは行ってみてください

<?php
// このソースコードはUTF-8で保存されているものとします
// file_get_contentsでhttpから始まるURLも利用可能かどうかはphp.iniの設定によります
// 参考URL // http://jp2.php.net/manual/ja/function.file-get-contents.php
//
// ********** URLからの読み取り **********
$url = 'http://blog.livedoor.com/category/111/ranking.html';
$chrCode = 'UTF-8';
$pattern1 = '!<title+?>(.+?)</title>!i'; // ソースタイトル
$pattern2 = '!<span.+?class="number.+?>(\d+).+?href="(.+?)".*?>(.+?)</!i'; // URLとブログタイトル
$strText = file_get_contents($url) or Die('読み込みに失敗しました'); // 読み取り
$strText = mb_convert_encoding( $strText, $chrCode, mb_detect_encoding( $strText ) ); // キャラクタコード変換
preg_match( $pattern1, $strText, $matchs1) or die('タイトルのパターンにマッチしませんでした'); // パターンマッチング
echo '<pre>'; print_r( $matchs1 ); echo '</pre>';// 抽出結果
preg_match_all( $pattern2, $strText, $matchs2, PREG_SET_ORDER) or die('URLとブログタイトルのパターンにマッチしませんでした'); // パターンマッチング
echo '<pre>'; print_r( $matchs2 ); echo '</pre>';// 抽出結果

$pattern2は下記のようにしてもかまいません

$pattern2 = '!<span class="number">(\d+).+?href="(.+?)">(.+?)</a>!i'; // URLとブログタイトル

パターンのデリミタに/ではなく!を使っているのは…URLに/が含まれるためです

テキストを"ではなく'で囲っているのは…HTMLタグ内部に"が含まれているためです

internal_encodingは不要です(phpは受け入れたデータをそのままの形で保持するからです)

fopenでファイルを開いてfgetsなどで取得する方法を用いる場合もありますが、ネイティブで動作するfile_get_contentsを用いるほうが簡単で早いです

 

上記で問題点が見当たらない場合はSQLの作成ミスの確認をしてみてください

(phpからMySQLへの接続方法はmysqliやPDO、pearなど複数存在します。下記はよく使われるmysqlモジュールを例にしています)

// mysql_query($sqlStr); //これをコメントにして
echo $sqlStr . "<br />\n"; // SQLをブラウザに返す

この先になりますと、あなたが作成したプログラムをコメントか返信欄に丸投げしてもらうほうが早いです

 

はてなからの通知メールで確認してもらうと>|php|と||<でソースコードが囲まれているのがわかると思いますが、

ダイアリーや返信欄でも使えます(質問文やコメント欄では無視されます)ので、まねをしていただければソースコードが見やすくて助かります

id:holoholobird

ご回答ありがとうございます。

すみません。私の質問分の書き方がおかしかったせいで、質問の内容がずれてしまいました。

お二人には上の回答分のポイントを差し上げますので、どうかコメントに書いたようなPHPのコードを教えてください。

回答数制限を5回にひきあげました。どうかご回答のほど、よろしくお願いします。

2011/02/15 16:56:16

質問者が未読の回答一覧

 回答者回答受取ベストアンサー回答時間
1 hanako393 1142 981 87 2011-02-15 05:13:14
  • id:taknt
    >>SQLへの展開をどのような形で行っているのか

    >という文章の意味が理解できませんでしたので、どういう意味か教えていただけると助かります。


    多分、どういうSQLを作って実行しましたか?
    ということになると思いますよ。
  • id:windofjuly
    うぃんど 2011/02/15 12:25:30
    >どういうSQLを作って実行しましたか?
    >ということになると思います
     
    SQLが原因である可能性もありますけれど、その可能性は高いほうではないでしょう
    なぜなら「取得できるものと取得できないものが出てきました」という状況だからです
  • id:holoholobird
    お二人とも回答ありがとうございます。
    なるほどです。というより私の書き方が誤解を招く書き方になっていますね。申し訳ありません。

    >20件ほどいろいろなサイトの抽出を自分で試した結果、取得できるものと取得できないものが出てきました。
    というのは、回答1でいう「ターゲット」をいろいろなサイトに変えて、それぞれのリンクの一覧を抽出しようと試みたのです。
    そのサイトに見合うように正規表現を書き換えて、

    http://www.sumnet.ne.jp/domp/hplink/dir_5.htm
    http://blog.livedoor.com/category/111/ranking.html
    http://www.pressnet.or.jp/link/02_list01.htm

    こんな感じの「リンクがいろいろ掲載されているページ」のURLとサイトタイトル一覧をまとめて取得するようなPHPを作成しようと練習しました。
    windofjulyさんに前に教えてもらったPHPをいろいろ工夫して、PHPと連携させたりSQLを入れたりして試したりしていたのです。

    そうして20ターゲットほど、抽出をいろいろ試してみたのですが、ターゲット「http://blog.livedoor.com/category/111/ranking.html」
    の取得ができませんでした。

    おかしいと思ったところを書き換えていくうちにコードがぐちゃぐちゃになってしまったので、
    上のターゲットをSQLに格納するようなPHPの模範回答を見せてもらいたいと考えました。
  • id:holoholobird
    2行目が入ったせいで誤解されたような気がしたので、質問文を書き換えます。
    わかりにくい文章で済みません。どうかご回答のほど、よろしくお願いします。

    ------------

    現在、PHPでサイトからデータを抽出してSQLに格納する練習をしています。

    格納先のデータベースは、
    データベース名:headline、テーブル名:datalist、フィールド名:blogtitle、url、sourcetitle (フィールドは左の3つ)です。

    http://blog.livedoor.com/category/111/ranking.html
    抽出したいのはブログ名とURLです。

    PHPを実行すると、

    Olz Weblog:http://blog.livedoor.jp/olzjp/:今日のできごと : 日記 : ランキング - ライブドアブログ
    人名力:http://blog.livedoor.jp/namepower/:今日のできごと : 日記 : ランキング - ライブドアブログ
    嵌る日常:http://shinji.livedoor.biz/:今日のできごと : 日記 : ランキング - ライブドアブログ

    というようにデータベースに登録されます。

    上のURL先のソースを読み取り、ランキング先の20個のブログタイトルとURLを、SQLに入力するようなものを考えています。
    対応する「sourcetitle」フィールドには、上のURLのタイトル…つまり
    http://blog.livedoor.com/category/111/ranking.htmlのタイトルである、「今日のできごと : 日記 : ランキング - ライブドアブログ」という文字が入力されます。
    他のサイト…たとえばターゲットを「http://www.sumnet.ne.jp/domp/hplink/dir_5.htm」にして正規表現をサイトにあうように対応させて実行すると、抽出したデータの「sourcetitle」には「HTML/CSS - ホームページ作成無料リンク集」が入力されます。
  • id:sayo213sayo
    コメント荒らし キタ━━(━(━(-( ( (゚∀゚) ) )-)━)━) ━━ !!!!!
     
    暇を持て余し、コメント投稿者に対して因縁を付けているのか!?
  • id:windofjuly
    うぃんど 2011/02/15 20:01:55
    【1】まずは訂正ですみませんが下記のように変更してください(変更せずとも偶然動きますが直しておいてください)
    $pattern1 = '!<title>(.+?)</!i'; // ソースタイトル

    【2】回答2のコードに続いて下記のようにすればデータベースへの書き込みまで終了します
    //
    // ********** SQL文作成 **********
    $sqlStr = 'INSERT INTO datalist(blogtitle、url、sourcetitle) VALUES ';
    foreach ($matchs2 as $m) {
    $sqlStr .= '(' . join( ',', array( "'$m[2]'", "'$m[3]'", "'$matchs1[0]'") ) . '),';
    }
    $sqlStr = substr ( $sqlStr ,0 , strlen( $sqlStr ) -1 );
    // echo $sqlStr; // SQL文を見たい場合はコメントを外す
    //
    // ********** MySQLへの書き込み **********
    $con = mysql_connect(接続パラメータ) or Die('MySQL接続に失敗しました');
    mysql_select_db('headline') or Die('データベースオープンに失敗しました');
    mysql_query($sqlstr) or Die('データベース書き込みに失敗しました');
    echo 'データベースへの書き込み終了'; // 正常終了すれば出てくるはずです
     
    最低レベルのものとしては以上です
    (回答2にてMySQLへの接続方法は複数あると書いておいたのですが、回答2を読んでいただけて無いようなので、勝手に選びました)
     
    【3】デバッグについて
    今回の場合であれば下記のような具合に確認していくことになります
    (1)URLからのデータ取得に成功しているかどうか?
    (2)パターンマッチングで必要な部分だけを抜き出させているか?
    (3)SQL文の生成は成功しているか?
    こちらも回答2を実行していただいていれば実感できたと思うのですが、残念です
  • id:sayo213sayo
    コメント荒らし再び キタ━━(━(━(-( ( (゚∀゚) ) )-)━)━) ━━ !!!!!
     
    質問者のスキルを無視して難しい指事を連発!
    自分はいったい何様のつもり!?
  • id:holoholobird
    windofjulyさん
    いつもご回答ありがとうございます。

    すみません。大学からだったため、とりあえず質問文の訂正のみ行いました。

    データの取得に関して、回答2を組み込んだPHPを使えばより効率よく学習できそうです。ありがとうございます。
    回答1のコードも合わせて、とりあえず質問内容である該当URLのデータベースへの取得は無事にできました。

    SQLの接続に関しては、手元の参考書に「mysql_connect」を使って接続するように指示されていたのですが、これのことでしょうか。
    接続方法が複数ある、という点についてもう少し教えていただければ助かります。

    どうかご回答のほど、よろしくお願いします。
  • id:windofjuly
    うぃんど 2011/02/16 07:36:39
    phpでは下記のようにデータベース毎に専用のモジュールが用意されています
    http://www.php.net/manual/ja/refs.database.php
     
    その中でMySQL用には下記のようなものが用意されています
    http://www.php.net/manual/ja/book.mysql.php…(1)
    http://www.php.net/manual/ja/book.mysqli.php
    比較的最近追加されたものとして下記もありますが実績や関連情報の充実はまだこれからです
    http://www.php.net/manual/ja/book.mysqlnd.php
    http://www.php.net/manual/ja/book.mysqlnd-qc.php
     
    MySQL専用などに比べればパフォーマンスは落ちますが、
    データベースを抽象化して隠蔽するためのモジュールとして下記などがあります
    http://www.php.net/manual/ja/book.uodbc.php
    http://www.php.net/manual/ja/book.pdo.php
     
    phpで書かれた抽象化モジュールもあります
    http://pear.php.net/manual/ja/package.database.php…(2)
     
    主に使われているのは(1)あるいは(2)になります
    mysql_connectは(1)での接続方法であり利用範囲も広く、
    最初に覚えておくと他の接続方法への転向も難しくはないです
     
    回答1(非常に古い時代のコードです)を併用しなければデータの取得が出来なかったという事であれば、
    php.iniの設定の見直しなども必要になると思いますが、短い時間で解決するのは難しいので今後の課題として置いておくとしますが、
    キャラクタコード関連の見直しが必要という点だけは覚えておいてください
  • id:holoholobird
    ご説明ありがとうございます。
    mySQLの接続については、mysql_connectから少しずつ覚えるものを増やしていきたいと思います。
    大変参考になりました。また機会があればよろしくお願いします。
  • id:sayo217sayo
    コメント荒らし再び キタ━━(━(━(-( ( (゚∀゚) ) )-)━)━) ━━ !!!!!
     
    さりげなく他の回答者を罵倒
    人間性を疑うな

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

回答リクエストを送信したユーザーはいません