PHPについて質問です。


現在WEB上からデータを取って来て、データをまとめるというマーケティングの作業をやっています。

しかし、これがとても膨大な作業で、どうにかして半分でもいいので自動化できたらと考えています。

現在自分がデータを取ってきているのはオークションサイト(ヤフオク)でページ(HTML)にはある一定の規則性があります。

自分がやりたい事は

まず ① 指定したURL にアクセスして

②そのページのHTMLを取得 取得したデータを変数に保存 

③法則性のあるhtmlの中から必要なデータを正規表現で抜き出す。
抜き出したデータは変数に保存する。

④保存した変数をデータベースに保存する。

という作業を行えば実現出来るのではないかと考えています。

問題点ですが

①と②の段階がいまいちよくわかりません。

どのような方法を取ればPHPでは実現できますでしょうか?

お手数をおかけしますがご回答お待ちしております。

回答の条件
  • 1人2回まで
  • 登録:2009/09/21 04:05:10
  • 終了:2009/09/23 18:25:38

ベストアンサー

id:makeworld No.2

makeworld回答回数75ベストアンサー獲得回数232009/09/21 05:58:22

ポイント100pt

HTMLの取得は、fopen()でURLを開いて読み込めます。(fopen()に失敗する場合は、php.iniのallow_url_fopenをOnに設定してください)

文字列の抽出は、preg_match()などで可能です。

下記の例は、文字コードをEUC-JPで保存して実行してください。(「円」の部分で日本語を使用しています)

残り時間の「日」は、EUC-JPで表示されます。

<?php
$URL = 'http://page12.auctions.yahoo.co.jp/jp/auction/p170009654';

$html = '';
$fp = fopen($URL, 'r') or die("fopen");
while (!feof($fp)) {
  $html .= fread($fp, 1024);
}
fclose($fp);

preg_match('|<strong property="auction:Price">(.*?) 円</strong>|', $html, $matches);
$price = strtr($matches[1], array("," => ""));
preg_match('|<td><strong>(.*?)</strong>|', $html, $matches);
$remain = $matches[1];
preg_match('|<strong property="auction:Bids">(.*?)</strong>|', $html, $matches);
$count = $matches[1];

print "$price\n";
print "$remain\n";
print "$count\n";
?>
id:aiomock

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

2009/09/21 06:01:39

その他の回答(5件)

id:kn1967 No.1

kn1967回答回数2915ベストアンサー獲得回数3012009/09/21 05:00:37

ポイント19pt

不正アクセスを防ぐため、わざと面倒な手順を踏むように設計されていますので、

コピペで済むような簡単なコードでは対処できません。


それでも業務上必要だという事であれば、

yahoo側が用意しているアクセス手段を用いる方法を学んでください。

Yahoo!デベロッパーネットワーク - オークション

Yahoo! JAPAN - サービス利用規約


例えば、

出品リストの取得は下記に説明があるのですが、

必要なパラメータを送るだけでデータを手に入れる事が出来ます。

Yahoo!デベロッパーネットワーク - オークション - 出品リスト

具体的なサンプルコードと動作デモは下記にあります。

Yahoo!デベロッパーネットワーク - サンプルコード集 - オークションサンプルコード - 出品リストを表示する

※サンプルを見ればコピペで済むようなものではないことは直ぐ判る事と思います。


他にもサンプルコードや動作デモは下記に色々ありますので、

まずはサンプルからチャレンジしてください。

Yahoo!デベロッパーネットワーク - サンプルコード集


サンプルコードがある程度理解できたら、

サンプルコードを改造して3と4の機能を追加してください。 


※今件、私の回答は多分ここまでとなると思いますが、あしからずご了承ください。

id:aiomock

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

2009/09/21 05:59:32
id:makeworld No.2

makeworld回答回数75ベストアンサー獲得回数232009/09/21 05:58:22ここでベストアンサー

ポイント100pt

HTMLの取得は、fopen()でURLを開いて読み込めます。(fopen()に失敗する場合は、php.iniのallow_url_fopenをOnに設定してください)

文字列の抽出は、preg_match()などで可能です。

下記の例は、文字コードをEUC-JPで保存して実行してください。(「円」の部分で日本語を使用しています)

残り時間の「日」は、EUC-JPで表示されます。

<?php
$URL = 'http://page12.auctions.yahoo.co.jp/jp/auction/p170009654';

$html = '';
$fp = fopen($URL, 'r') or die("fopen");
while (!feof($fp)) {
  $html .= fread($fp, 1024);
}
fclose($fp);

preg_match('|<strong property="auction:Price">(.*?) 円</strong>|', $html, $matches);
$price = strtr($matches[1], array("," => ""));
preg_match('|<td><strong>(.*?)</strong>|', $html, $matches);
$remain = $matches[1];
preg_match('|<strong property="auction:Bids">(.*?)</strong>|', $html, $matches);
$count = $matches[1];

print "$price\n";
print "$remain\n";
print "$count\n";
?>
id:aiomock

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

2009/09/21 06:01:39
id:ymlab No.3

ymlab回答回数507ベストアンサー獲得回数342009/09/21 12:21:46

ポイント18pt

id:makeworld さんと同じように、fopenで取得可能ですが

あらかじめ、ソースコードを取得する目的だとはっきりしているのであれば、

http://rokuha48.blog63.fc2.com/blog-entry-52.html

のサイトのように、file()を使えば、結構簡単に取得できますよ。

一気に

$a=file("URL");

で、$aにソースが入りますので、1と2の手順を完了できます。

後は、$aに対して、3,4の処理を加えればよいのです。

id:aiomock

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

2009/09/21 12:58:09
id:TakiTake No.4

TakiTake回答回数1ベストアンサー獲得回数02009/09/21 13:20:20

ポイント18pt

HTML取ってくるだけなら

file_get_contents('URL');

で取得できますし


API使うなら

<?php
$appid       = '自分のYahoo API ID';
$auctionID   = 'オークションID';
$request_url = 'http://auctions.yahooapis.jp/AuctionWebService/V2/php/auctionItem';
$parameter   = sprintf('?appid=%s&auctionID=%s', $appid, $auctionID);

// 結果がPHP serializeされて返ってくる
$response     = file_get_contents($request_url . $parameter);

// unserializeして連想配列に戻す
$auction_item = unserialize($response);

// 必要な値を取得
$price    = $auction_item['ResultSet']['Result']['Price'];
$end_time = strtotime($auction_item['ResultSet']['Result']['EndTime']);
$bids     = $auction_item['ResultSet']['Result']['Bids'];
?>
<p><?php echo $price ?></p>
<p><?php echo round(($end_time - time()) / 86400) ?></p>
<p><?php echo $bids ?></p>

こんな感じでどうでしょう?

残り時間が取れなかったので、終了時刻から現在時刻引いて出してます。

id:aiomock

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

2009/09/21 13:21:58
id:houjou_crm No.5

houjou_crm回答回数2ベストアンサー獲得回数02009/09/21 17:32:44

ポイント18pt

オークションじゃないけど同じようなことやってます。

①「Pear::HTTP」でやるのが常套手段だと思っています。今後も活躍するのでPearの使い方は経験しといた方が良いと思いますよ。Pear使うのが初めてなら「http://www.phpbook.jp/」で勉強してみてください。

②正規表現で対象データを抽出することができます。「eregi」「正規表現」でググってみてください。同じような事例が沢山出てくると思います。


他力本願

http://www.tarikin.net/

id:aiomock

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

2009/09/21 20:43:44
id:ymlab No.6

ymlab回答回数507ベストアンサー獲得回数342009/09/22 14:31:12

ポイント18pt

面白そうだから私もkakaku.comとAmazonとヨドバシカメラを比較するサイトを作ってみました。


<html>
<head>
</head>
<body>
<?php
$d302eKakaku = file("http://kakaku.com/item/20445510653/");
$d302eAmazon = file("http://d.hatena.ne.jp/asin/B0007XFH4Y");
$d302eYodobashi = file("http://www.yodobashi.com/ec/product/100000001000519297/index.html?backquery=5wrePU0ewpctOE9yOSgRFBc9_gwMBNscYMaDHMZI-z456CV_c_Mw8FAZrrrLAuzKsBMAnY5eT6nCZlGZG5Ubpw..");
//kakaku.com 最安値情報を得る
preg_match("/(.*)(&yen;)([0-9,]+)(.*)/", $d302eKakaku[88], $matches);
$d302eKakakuValue = $matches[3];
//Amazon の最安値情報を得る
$d302eAmazon[201] = mb_convert_encoding($d302eAmazon[201], "sjis");
preg_match("/(.*)(li)(.*)(Amazon)(.*)([0-9,]+)(円)(.*)/",$d302eAmazon[201], $matches);
$d302eAmazon[201] = $matches[5];
preg_match("/(.*)(価格)(.*)(.*)((定価)(.*)/",$d302eAmazon[201], $matches);
$d302eAmazon[201] = $matches[3];
preg_match("/(.*)(<strong>)(.*)(<\/strong>)(.*)(円)(.*)/",$d302eAmazon[201], $matches);
$d302eAmazonValue = $matches[3];
//Yodobashi 価格
//
$d302eYodobashi[200] = mb_convert_encoding($d302eYodobashi[200],"SJIS", "UTF-8");
preg_match("/(.*)(¥)([0-9,]+)/", $d302eYodobashi[200], $matches);
$d302eYodobashiValue = $matches[3];
print "MACHE=[";print_r($matches);print"]";
?>
<h2>
	D302E
</h2>
<table>
<tr>
<td>
<img src = "http://img.kakaku.com/images/productimage/fullscale/20445510653.jpg" width = "200" />
</td>
<td width = "30">
<?php print $d302eKakaku[129];?>
</td>
</tr>
</table>
<table border = "1">
    <tr>
	<td>
	    <a href = "http://kakaku.com/item/20445510653/">
		    価格.com 最安値
	    </a>
	</td>
	<td>
	    <a href = "http://www.amazon.co.jp/exec/obidos/ASIN/B0007XFH4Y/hatena-q-22>
		    Amazon最安値
	    </a>
	</td>
	<td>
	    <a href = "http://www.yodobashi.com/ec/product/100000001000519297/index.html?backquery=5wrePU0ewpctOE9yOSgRFBc9_gwMBNscYMaDHMZI-z456CV_c_Mw8FAZrrrLAuzKsBMAnY5eT6nCZlGZG5Ubpw..">
		    Yodobashi 最安値
	    </a>
	</td>
    </tr>
    <tr>
	<td align="right">
	    <font color = "red" size = "5">&yen;<?php print $d302eKakakuValue?></font>   
	</td>
	<td align = "right">
	    <font color = "red" size="5">&yen;<?php print $d302eAmazonValue;?></font>   
	</td>
	<td align = "right">
	    <font color = "red" size="5">&yen;<?php print $d302eYodobashiValue;?></font>   
	</td>
    </tr>
</table>
<?php

//print_r( $d302eYodobashi);
?>
</body>
</html>

id:aiomock

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

2009/09/23 16:37:29
  • id:aiomock
    例えばですが

    http://page12.auctions.yahoo.co.jp/jp/auction/p170009654

    このページにある。(ヤフオクトップページからとりあえず取ってきました。。。)


    現在の価格 : 46,000 円

    残り時間 : 2 日

    入札件数 : 9

    の 現在価格 と 残り時間 と 入札件数

    46000

    2日

    9

    という数字を取ってくるとしたらどのようなPHPスクリプトになるかという実例を挙げていただけると大変わかりやすいです。

    どんなプロセスをたどっていけば達成できるか でもかまいません。

    お手数をおかけしますがわかるかたおりましたらよろしくお願いいたします。
  • id:jtarokuroki
    ①と②PHPじゃないのですがhttp://q.hatena.ne.jp/1250623193#a942081で紹介されているhttp://www.f3.dion.ne.jp/~element/msaccess/AcTipsVbaXMLHTTP.htmlで取得とか?
  • id:kn1967
    サンプルコード集のほうを見れば載ってるのだけど、
    出品リストよりも、詳細のほうにリンクしておいたほうがよかったかな?
    http://developer.yahoo.co.jp/sample/auctions/sample5.html
       ↓
    (1)サンプルの中で AuctionItemDemo.php から不要部分を削って、
      必要な項目だけを表示するように変更してテスト。
    (残り時間は取得項目に無いので、終了時間と現在時刻を使って計算する必要あり)
       ↓
    (2)AuctionItemDemo.php にデータベースへの書き込み処理を追加してテスト。
       ↓
    (3)本番用のシステムに加える。

    (1)の改造は不要部分を削るだけだから難しくないと思うし、
    どのように項目を取得するかも理解できるはず。
    さらに、必要部分のデータのやりとりだけで済むのでネットワーク負荷も軽く、
    レスポンスもあがるので時間切れ等の心配も少しだけど減る。
    yahooサーバ側としても残り時間を計算して載せたり、
    ヘッダやサイドバーなどを付加するというような余計な負担が減る。

    以上、追記。
  • id:chrono1742
    kn1967様
    恐れながら、kn1967様の回答やコメントについて疑問に感じたところを記します。

    ・お示しになったサンプルコードはYahoo!オークションAPIを用いるものであり、質問者が求めている②とは目的が違います。makeworld様が示されている方が目的にマッチしています。

    ご検討をよろしくお願いいたします。
  • id:kn1967
    私にはaiomockさんのこれまでの質問に多数回答してきたという経緯があるため、
    「コメント欄に記されたページはあくまでも例であって、
    aiomockさんの真の目的はこれまで通りヤフオクからのデータ取得と管理」だと理解し、
    そのため行ったのが回答1。
    (1行目と2行目はオーバートークのところもありますので反省材料ですけど・・・。)

    それはさておき、全ての回答者が、そこまで知っているとも限らないし、
    また、そこまで事前調査する必要性もまた無い訳だから、
    aiomockさんの質問とコメントだけを見て、回答2のようになるのも当然。


    話は変わって・・・、
    決まり文句のように「検討」で〆ておられるけど、何を検討すれば良い?
    (1)横合いから出てくる勝手な疑問コメントを放置するか否か?
    (2)回答内容を見直せ?
    (3)回答スタイルを見直せ?
    エトセトラ、エトセトラ・・・。
    抽象的な表現ではなく、ズバっと書いてくれたほうが楽なんですけど。
  • id:kamikun
    >何を検討すれば良い?

    普通に「私のこの指摘が正しいか否か」じゃないでしょうか。
  • id:Reiaru
    回答を行った後に検討も何もありませんよね (はてなのシステム上、回答の訂正も削除もできませんので)。
    仮に当人がそれを検討しようと思ったとしても手後れです。

    修正のお願いならばまだ理解できますが、これは chrono1742 様の日本語がちょっとおかしいですよ(笑)
  • id:chrono1742
    kn1967様

    kamikun様が仰る通り、私は、回答内容が間違っていないかどうかご検討下さいと言っています。

    質問者は、

    > ① 指定したURL にアクセスして
    > ② そのページのHTMLを取得 取得したデータを変数に保存 
    > ③ 法則性のあるhtmlの中から必要なデータを正規表現で抜き出す。

    と書かれていますので、WebAPIで処理するのではなく、明らかにHTMLサイトの解析を意味しています。
    それなのに、どうして

    > aiomockさんの真の目的はこれまで通りヤフオクからのデータ取得と管理」だと理解し、

    と勝手に解釈されるのか理解に苦しみます。

    makeworld様の回答の方が直接的で、回答内容も簡便です。
  • id:chrono1742
    Reiaru様
    > 回答を行った後に検討も何もありませんよね

    回答回数は2回まで許されていますから、検討のうえ、修正や訂正はできますよ。
  • id:kn1967
    >理解に苦しみます。

    どうして回答1のようになったのかについては一応説明しましたが、
    真に理解するためにはaiomock氏のこれまでの質問を精査するとともに、
    氏に対してkn1967がどのようなコメントや回答を行ってきたかも精査しないことには、
    理解できなくても当然ですし、精査したのであれば相当に理解できるはずです。

    失礼ながら、精査してもなお理解できないというスキルしかお持ちでないのだとすれば、
    私が何を答えようともchrono1742さんは理解できないことでしょうし、
    そもそもの話として、質問者である aiomock 氏が私の回答を、どのように受け止め、
    どのように進めていくかだけの話ですから、chrono1742さんが疑問に思おうが、
    理解できなかろうが、知ったことではないです。


    >回答回数は2回まで

    コメント欄が開いていない場合や、質問者からの返答に対して新たに項目が増える場合などは、
    2回目以降の回答投稿を行う場合もありますが、間違いが判明した場合はコメント欄に入れますし、
    ポイント付きメッセージ送信でコメントを送る時もあります。そもそも、
    こちらの一方的ミスを補うために、強制的に10ポイント消費が増えるというのは、
    chrono1742さんが頻繁に使う「質問者のため」という言葉にも反しますよね。
    質問者のポイントを無駄に消費させてよいものかよくよく検討しなおしてください。
  • id:kn1967
    TakiTake さんがシンプルにまとめてくださいましたね。

    chrono1742 の相手なんかせずに動作テストすりゃよかったと反省するよ・・・。
    kmond2 に絡まれた時と同じパターンじゃん! 成長しとらんな > ワシ。

    コメント欄を下手に賑わせて、重ね重ね申し訳ない>aiomockさん
  • id:chrono1742
    aiomock様

    回答欄でkn1967様が示されている方法、およびTakiTakeさんが回答されている2番目の方法は、WebAPIが返すXMLを処理するものです。
    ご質問にある「法則性のあるhtmlの中から必要なデータを正規表現で抜き出す」とは異なる方法ですので、よくご検討ください。
  • id:kn1967
    >ご質問にある「法則性のあるhtmlの中から必要なデータを正規表現で抜き出す」とは異なる方法ですので、よくご検討ください。


    「データベースに保存する」が目的であって、そこにたどり着く手段が違うだけだと、やっと気づいたのかな?
    (1)phpの関数を用いた汎用的に応用の利く方法
      fopen
      file
      file_get_contents (aiomock氏の環境で使えたっけ? phpのバージョン忘れた・・・。)
      など
    (2)ライブラリを用いた方法
      pear
      など
    (3)ヤフオク専用の方法
      WebAPI (この場合、正規表現は不要というだけ)

    どれを選択するかは、もちろんaiomockさんの自由。
  • id:TakiTake
    訂正です。
    round(($end_time - time()) / 86400) の
    roundはfloorの方が適切でしたね。

    終了時刻と現在時刻の差分を取る
    86400で割って秒単位を日単位にする
    roundで整数に丸め込む <- これだと四捨五入なんで、小数点以下切捨てのfloorの方が適切

    あと、個人的な意見としては
    一般的なサイトの取得なら、file系関数使うなりPEARのライブラリ使えばいいし
    特定サイトかつAPIが公開されているならば、そちらを使うほうが目当てのデータ取得し易くてお勧めです。
  • id:aiomock
    皆さんご回答大変ありがとうございます。

    おかげさまでとても便利になりました。

    色々やり方がありよさそうだったのですが、自分自身の力不足もあり

    今回は一番自分の身近であるhtmlでのやり方を採用させていただきました。

    色々ご回答していただいた方本当にありがとうございます。
  • id:aiomock
    今回の質問に関してですが

    kn1967さんのいっている

    真の目的はこれまで通りヤフオクからのデータ取得と管理 は間違いではありません。

    しかし、今回一番取っ付き易かった回答を選びました。

    やりやすそうな回答があがっていたので、食わず嫌いなところがありました。

    もっとも技術的に少し抵抗を感じたのがあります(PHPに関しては素人のため)

    kn1967さんのいっている目的に関してはあっております。

    そして僕が回答を選ぶ基準は一番やりやすそうなものをいつも選んでいます。

    PHPを勉強するのは楽しいですが、目的を達成できるのが選ぶ基準として高いです。

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

トラックバック

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

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

絞り込み :
はてなココの「ともだち」を表示します。
回答リクエストを送信したユーザーはいません