スクレイピングによってDB更新 - PHPプロ!Q&A掲示板

4967

  • 募集中!! 0P

スクレイピングによってDB更新

質問日時 / 2018年8月7日 07:54    回答数 / 3件

Questioner:  php_tanaka  このエントリーをはてなブックマークに追加 

キーワード / PHP    mysql   

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


  1. <?php
  2. try {
  3. $pdo = new PDO('mysql:host=localhost;dbname=##;charset=utf8','##','##',
  4. array(PDO::ATTR_EMULATE_PREPARES => false));
  5. } catch (PDOException $e) {
  6.  exit('データベース接続失敗。'.$e->getMessage());
  7. }
  8.  
  9.  
  10. $stmt = $pdo->query("SELECT * FROM model");
  11. while($row = $stmt -> fetch(PDO::FETCH_ASSOC)) {
  12.  $ttitle = $row["url"]}
  13.  
  14.  
  15.  
  16. require_once("phpQuery-onefile.php");
  17.  
  18. $html = file_get_contents($ttitle);
  19.  
  20. $doc = phpQuery::newDocument($html);
  21.  
  22.  
  23. $test = $doc[".test2 h1"]->text();
  24.  
  25.  
  26. try{
  27.     // 静的プレースホルダを指定
  28.     $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARESfalse);
  29.  
  30.     // DBエラー発生時は例外を投げる設定
  31.     $pdo->setAttribute(PDO::ATTR_ERRMODEPDO::ERRMODE_EXCEPTION);
  32.  
  33.     $stmt = $pdo->prepare("UPDATE model SET status=:status WHERE url=:url");
  34.  
  35.     //トランザクション処理
  36.     $pdo->beginTransaction();
  37.  
  38.     try{
  39.  
  40.         $stmt ->bindParam(':status'$test);
  41.         $stmt ->bindParam(':url'$ttitle);
  42.         $stmt->execute();
  43.  
  44.         //コミット
  45.         $pdo->commit();
  46.  
  47.     }catch (PDOException $e) {
  48.         //ロールバック
  49.         $pdo->rollback();
  50.         throw $e//
  51.     }
  52.     // 接続を閉じる
  53.     $pdo = null;
  54. }catch (PDOException $e) {
  55.     // UTF8に文字エンコーディングを変換します
  56.     echo mb_convert_encoding($e->getMessage(),'UTF-8','SJIS-win');
  57.     die();
  58. }
  59.  
  60.  
  61. ?>

おそらく$ttitle = $row["url"];で代入させてしまっているため、最後の情報しか更新されない状態です。ですが、まったく改善方法が見当たらないのでご教授お願いします。


ツリー一覧

┗A01shimix>おそらく$ttitle = $row["url"];で代入させてしまっ
 ┗A01-1php_tanaka回答ありがとうございました。 綺麗ですぐに理解する
  ┗A01-1-1shimix>if (trim($test) === '') { continue; } >ここの文

回答一覧

並び替え:

A01 参考になった
answerershimix [8月7日 11:47]

>おそらく$ttitle = $row["url"];で代入させてしまっているため、
>最後の情報しか更新されない状態です。

それがわかっていれば改善は容易いと思いますが・・・
  1. <?php
  2. // connect to DB
  3. try {
  4.         $pdo = new PDO('mysql:host=localhost;dbname=##;charset=utf8''##''##'
  5.                         [PDO::ATTR_EMULATE_PREPARES => falsePDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION]);
  6. } catch (PDOException $e) {
  7.         die('connect to DB aborted : ' . $e->getMessage());
  8. }
  9. // url from model
  10. try {
  11.         $arr_ttitle = [];
  12.         $stmt = $pdo->query('SELECT * FROM model');
  13.         while($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
  14.                 $arr_ttitle[] = $row["url"];
  15.         }
  16. } catch (PDOException $e) {
  17.         die('DB aborted : ' . $e->getMessage());
  18. }
  19.  
  20. require_once("phpQuery-onefile.php");
  21.  
  22. // update
  23. try {
  24.         $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARESfalse);
  25.         $stmt = $pdo->prepare("UPDATE model SET status=:status WHERE url=:url");
  26.         // ここからループ処理
  27.         foreach ($arr_ttitle as $ttitle) {
  28.                 $html = file_get_contents($ttitle);
  29.                 $doc = phpQuery::newDocument($html);
  30.                 $test = $doc[".test2 h1"]->text();
  31.                 if (trim($test) === '') { continue}
  32.                 $pdo->beginTransaction();
  33.                 try {
  34.                         $stmt ->bindParam(':status'$test);
  35.                         $stmt ->bindParam(':url'$ttitle);
  36.                         $stmt->execute();
  37.                         $pdo->commit();
  38.                 } catch (PDOException $e) {
  39.                         $pdo->rollback();
  40.                         throw $e//
  41.                 }
  42.         }
  43.         // ループ処理ここまで
  44. } catch (PDOException $e) {
  45.         die($e->getMessage());
  46. }
  47. ?>
こんな感じじゃないでしょうかねぇ・・・

例外生成の設定を接続時に行うように変更したり、接続がutf-8なのにエラーメッセージをsjis→utf-8変換していたのを省いたりしています。

トランザクション処理も『?』なんですが、一応はそのまま残しています(このあと更新を追加する予定があるのかなと)。

この意見に回答する

ツリーへ TOPへ

A01-1
replyerphp_tanaka [8月7日 13:19]

回答ありがとうございました。
綺麗ですぐに理解することができました。
複数の値を受け渡す場合はやはりループ文を使わないといけないのですね。
そもそも配列の組み方さえあんまり理解できませんでした。
とても勉強になりました。

if (trim($test) === '') { continue; }
ここの文はどんな処理をさせているのでしょうか?

この意見に回答する

ツリーへ TOPへ

A01-1-1
replyershimix [8月8日 08:26]

>if (trim($test) === '') { continue; }
>ここの文はどんな処理をさせているのでしょうか?

本来は取得時点での例外発生を捕捉するとか値がfalseかどうかだとは思いますが、何が最適か不明だったので「何らかの継続不能な状態になっていたらスキップする」処理を埋め込む位置だけ示すために一行入れました(汗

#本来は空白でも「空白で更新」すべきですので削除してかまいません

外部ドキュメントの処理なので「処理できる構造になっていなかった」などの想定外の事態はあり得るのかなと・・・

この意見に回答する

ツリーへ TOPへ

<<質問一覧へ



Pick Up Q&A

Q
ログファイルの中の空のデータ行を削除したい
 このエントリーをはてなブックマークに追加 
A
ログのデータ個数(列数)が固定で、空のログが"<><><>"だと既知であれば if ($line === "<><><>") { continue; } で読み飛ばしてもいいのでは? ...

>>続きを読む

まずは配列や文字列の扱いから、じっくり勉強して行きましょう。

▲解説者:岡本(アシアル株式会社 教育コーディネーター兼 システムエンジニア)