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

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

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

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

MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

PHP

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

Q&A

1回答

2128閲覧

DBの値が一致したら更新

web_tanaka

総合スコア9

スクレイピング

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

MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

PHP

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

0グッド

0クリップ

投稿2018/08/06 16:46

編集2018/08/07 04:35

前提・実現したいこと

PHP初心者です。ちょっと説明が下手ですが、他サイトの指定classの<h1>要素の値を取得をして、DBの値と一致したら特定のカラムのみ全件更新させたいと思っています。

発生している問題・エラーメッセージ

プログラムは出来ていますが、全件に更新させたいのですが、なぜかDBの最後のレコードしか更新されません。
サイトのスクレイピングにphpQuery-onefile.phpを利用しています。

該当のソースコード

<?php try { $pdo = new PDO('mysql:host=localhost;dbname=##;charset=utf8', '##', '##', array(PDO::ATTR_EMULATE_PREPARES => false)); } catch (PDOException $e) { exit('データベース接続失敗。'.$e->getMessage()); } $stmt = $pdo->query('SELECT * FROM model'); while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) { $ttitle = $row['url']; } require_once 'phpQuery-onefile.php'; $html = file_get_contents($ttitle); $doc = phpQuery::newDocument($html); $test = $doc['.test2 h1']->text(); try { // 静的プレースホルダを指定 $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); // DBエラー発生時は例外を投げる設定 $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $stmt = $pdo->prepare('UPDATE model SET status=:status WHERE url=:url'); //トランザクション処理 $pdo->beginTransaction(); try { $stmt->bindParam(':status', $test); $stmt->bindParam(':url', $ttitle); $stmt->execute(); //コミット $pdo->commit(); } catch (PDOException $e) { //ロールバック $pdo->rollback(); throw $e; // } // 接続を閉じる $pdo = null; } catch (PDOException $e) { // UTF8に文字エンコーディングを変換します echo mb_convert_encoding($e->getMessage(), 'UTF-8', 'SJIS-win'); die(); }

試したこと

どうしても最後のレコードしか反映されない状態で悩んでいます。
ご教授をお願いします。

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

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

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

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

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

guest

回答1

0

インデントが整理されていなくて非常に見づらいのでそこは調整していただきたいところですが、

php

1while($row = $stmt -> fetch(PDO::FETCH_ASSOC)) { 2 $ttitle = $row["url"]; }

上記、= で$ttitleに代入しているので常に最後の情報しか保持していませんよ。
while内でupdateも行うか配列で保持して配列ループ内でupdateされては?

ループ中の情報を別の配列変数に受ける ミニマムコード

php

1$a = []; // []はarray()の省略。 2for($i=0;$i<100;$i++){ 3 $a[] = $i; //$a[]のように[]で受けることで0番目から順番に情報を詰め込む 4} 5 6foreach($a as $b){ 7 echo $b; 8} 9

投稿2018/08/06 20:59

編集2018/08/07 03:29
m.ts10806

総合スコア80850

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

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

web_tanaka

2018/08/06 22:28

回答ありがとうございます。 while($row = $stmt -> fetch(PDO::FETCH_ASSOC)) { } この中にupdateするように組み込むということでしょうか?
m.ts10806

2018/08/06 22:39

問題の原因は分かったんですよね? あとは扱いたい情報を全て利用するように軌道修正するだけです。 回答にも書いたようにやり方は1つではありません。 要件や状況次第ではもっとシンプルに同様の効果をあげられる方法も存在するはずです。
web_tanaka

2018/08/06 22:46

まだ全部は理解できていない状態です。 $ttitleに代入しているので常に最後の情報しか保持されないことは理解できましたけど、配列することによって改善できるということでしょうか? 例えばですけど、クエリした結果を配列に入れてからupdateするような形でしょうか? それとも、updateをループさせないといけないでしょうか?
m.ts10806

2018/08/06 22:50

今のつくりを踏襲するのであればUPDATEのSQLは1つずつ発行しているので ループさせないといけないですね。 もちろん工夫すれば1回のSQLで実行するのは不可能ではないですが、 いずれにしても格納した配列のループは必要です。
m.ts10806

2018/08/06 22:58

一番簡単なのは回答の1つ目にあるwhileの中でupdateもしてしまうことです。
web_tanaka

2018/08/06 23:01 編集

回答ありがとうございます。ようやく理解できました。 ですが、今の状態のwhile($row = $stmt -> fetch(PDO::FETCH_ASSOC)) { $ttitle = $row["url"]; }は一応全件取得できてる状態なのでこちらの文はループできているという認識でいいのでしょうか? UPDATEのsqlにはループ文がないのでループされてないのは理解できてます。それが原因で一つのレコードしか反映されてない状態でよろしいでしょうか?
m.ts10806

2018/08/06 23:09 編集

> $ttitle = $row["url"]; }は一応全件取得できてる状態なのでこちらの文はループできているという認識でいいのでしょうか? おそらくほしい情報は全件取得できていてループはされていますが、保持が常に最新の値のみとなっています。UPDATEの方にループがない以前の問題です。 下記echoの結果で「99」が出力されるのと同じ状態です。 $a = ""; for($i=0;$i<100;$i++){ $a = $i; } echo $a; 0~98は$iには入ってきていて$aに「都度代入」されるため、値が上書きされ続けていき、最後の値しか残らないわけです。 回答の繰り返しとなりますが、 上書きされ続けるのを回避するには、「上書きされる前に使ってしまう」か「配列として全情報を受け取っておいて都度使う」のどちらかです。 やりとりをしていて感じた事でもしかしたら失礼に当たるかもしれないですが、 後者の「配列として受け取る」のコードの書き方が分からないということでしょうか・・?
web_tanaka

2018/08/06 23:24

度々回答ありがとうございます。 下記echoの結果で「99」が出力の件はすごく理解できました。 調べてみると配列にはarrayなどを使っていますが、まさにその通りです。 恥ずかしながらも配列として受け取る方法がまだ分かってない状態です。 何故、一つのレコードしか更新されないのかとしか疑問に思っていなかったですが、mts10806様のおかげで今ようやく理解できたって感じです。ですがまだ実現はできていません。試行錯誤中でございます。
m.ts10806

2018/08/06 23:30

>配列として受け取る方法がまだ分かってない状態です。 私の提示したミニマムコードを例にするとこんな感じ $a = []; for($i=0;$i<100;$i++){ $a[] = $i; } foreach($a as $b){ echo $b; } 冗長ですがあくまで例として。 ちなみに最初のfor内でechoをするのが「上書きされる前に使ってしまう」です。 ミニマムコードだと配列で受け取った後にさらにループするのはかなり冗長に見えてしまうかもしれませんが、 要件次第でその方が効率よく処理できたり、可読性も上がったり、メンテナンスもしやくすくなったりします。 そういった意味でも「やり方は1つではない」ということになります。 全体のコードのバランスや要件を考えたらもっと簡略化できる可能性もあります。 「絶対にこうしなきゃいけない」というルールはないので、状況に応じて柔軟にコードを変化させると良いです。
web_tanaka

2018/08/07 03:25 編集

回答ありがとうございます。 $stmt = $pdo->query("SELECT url FROM model"); while($row = $stmt -> fetchAll(PDO::FETCH_ASSOC)) { $arr = array ( $row['url'] ); このように配列としてやりましたが、そのあとの処理がどうもうまくいかないです。 var_export($row);でURLが[0],[1]などに入っているのは確認できています。 require_once("function/phpQuery-onefile.php"); $html = file_get_contents($row); $doc = phpQuery::newDocument($html); $test = $doc[".show_deny h1"]->text(); $html = file_get_contents($row); ここに配列を渡したいのですが記述方法がまったく分からない状態です。 これらを使ってループ文の組み方が分からないといった方がいいかもしれません。 良ければ引き続きご教授をしてもらえると嬉しい限りです。
m.ts10806

2018/08/07 03:27

配列にするのは受ける方ですよ。 私のミニマムコード参考にしてます? $a[] = $i; と $a = [$i]; では全く違いますよ。 ひとまず質問本文にやってみたところを含めた改修コード全文を追記してください。
m.ts10806

2018/08/07 03:37

ループの組み方というより配列の組み方と言ったほうが正しいですね。 ひとまず簡単な方を試してください。「上書きされる前に使ってしまう」 ・whileの閉じカッコをコード末尾に移動 ・require_once("phpQuery-onefile.php");をwhileよりも前に移動 ・$pdo = null;をwhileの閉じカッコよりも後に移動 でとりあえずできると思います。 ただ、コードはこのままでは読みにくいのでインデントはきちんと整理してください。
web_tanaka

2018/08/07 04:16

度々回答ありがとうございます。 なるほどです。閉じカッコも気を付けないとループが途中で終わってしまうのですね。 ご教授ありがとうございます。 ループがどういったものなのか簡単なサンプルを参考にしながら実行結果などを確認してますので頑張ってみたいと思います。
m.ts10806

2018/08/07 04:18

関数やクラスもそうですが「スコープ」というのは常に気にしてください。 変数もスコープ外では使えないこともあります。 http://php.net/manual/ja/language.variables.scope.php どのような機能を調べるにしてもまず最初はPHPマニュアルを見てください。 機能紹介だけではなく上記のようなスコープのことや注意点なども詳しく書かれていますし、User Contributed Notesでは例文も投稿されています。
web_tanaka

2018/08/07 04:23

まったく聞いたことない言葉ばかりなので本当勉強になります。 URLまでありがとうございます。参考にさせてもらいます。 今週頑張って実行できるようにしますのでまた報告させてもらいます。その時はお世話になるかもしれませんがよろしくお願いします。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問