PR

Step2 過去の株価をDBに登録(phpQueryを使ってスクレイピング)

過去の株価をDBに登録 PHP

株価テーブルの作成

まずは株価を登録するテーブルを作成しておきます。

CREATE TABLE IF NOT EXISTS `stock_d_stock_tbl` (
  `stock_code` varchar(10) NOT NULL COMMENT '銘柄コード',
  `stock_date` date NOT NULL COMMENT '日付',
  `opening_price` int(11) NOT NULL COMMENT '始値',
  `high_price` int(11) NOT NULL COMMENT '高値',
  `low_price` int(11) NOT NULL COMMENT '安値',
  `closing_price` int(11) NOT NULL COMMENT '終値',
  `trading_volume` int(11) NOT NULL COMMENT '出来高',
  `adjusted_closing_price` int(11) NOT NULL COMMENT '終値調整',
  `del_flag` int(1) DEFAULT '0' COMMENT '削除フラグ',
  `up_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '更新日時'
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='株価';

プライマリーキーの設定

ALTER TABLE `stock_d_stock_tbl` ADD PRIMARY KEY (`stock_code`,`stock_date`);

HTMLを解析

下記の手順で必要なデータを取得していきます。
1.銘柄ページから対象銘柄の過去の西暦一覧を作成
2.西暦一覧をループして対象銘柄のデータを1年ごとに取得する
3.1年分のデータを登録する

銘柄のページから過去何年の株価情報が存在しているか

下記の関数で対象銘柄の存在している西暦一覧を取得します。

function getStockPages($url) {
	// 取得したwebサイトを読み込む
	$html = phpQuery::newDocumentFile($url);
	$lists = $html['#base_box > div > ul > li > a'];
	$pages = array();
	foreach(pq($lists) as $item) {
		if (!ctype_digit(pq($item)->html())) {
			continue;
		}
		array_push($pages, pq($item)->text());
	}
	return $pages;
}

下記は銘柄コードと西暦一覧を渡し、銘柄1つ分の過去の株価をすべて登録する関数です。

function insertStockYear($stock_code, $pages) {
	global $mysqli;
	// 指定された年数分ループ
	foreach($pages as $index) {
		// 対象銘柄の1年分の株価を取得するURLを作成
		$url = "https://kabuoji3.com/stock/" . $stock_code . "/" . $index . "/";
		// 取得したwebサイトを読み込む
		$html = phpQuery::newDocumentFile($url);
		// 株価部分を取得
		$trs = $html['#base_box > div > div.data_contents > div > div > div > table > tr'];
		// 取得した1年間の株価数分ループ
		foreach(pq($trs) as $tr) {
			// 銘柄コード
			$stock_date = pq($tr)->find('td:nth-child(1)')->text();
			// 始値
			$opening_price = pq($tr)->find('td:nth-child(2)')->text();
			// 高値
			$high_price = pq($tr)->find('td:nth-child(3)')->text();
			// 安値
			$low_price = pq($tr)->find('td:nth-child(4)')->text();
			// 終値
			$closing_price = pq($tr)->find('td:nth-child(5)')->text();
			// 出来高
			$trading_volume = pq($tr)->find('td:nth-child(6)')->text();
			// 終値調整
			$adjusted_closing_price = pq($tr)->find('td:nth-child(7)')->text();
			// 登録用SQL作成
			$sql = "INSERT INTO stock_d_stock_tbl (stock_code, stock_date, opening_price, high_price, low_price, closing_price, trading_volume, adjusted_closing_price) VALUES (";
			$sql = $sql . "'" . $stock_code . "', '" . $stock_date . "', " . $opening_price . ", " . $high_price . ", " . $low_price . ", " . $closing_price . ", " . $trading_volume . ", " . $adjusted_closing_price . ") ";
			$sql = $sql . "ON DUPLICATE KEY UPDATE opening_price = " . $opening_price . ", high_price = " . $high_price . ", low_price = " . $low_price . ", closing_price = " . $closing_price . " , trading_volume = " . $trading_volume . " , adjusted_closing_price = " . $adjusted_closing_price;
			// DBへ登録
			$mysqli->query($sql);
		}
	}
}

銘柄×西暦数ループするのですべてやろうとするとかなりの時間がかかりるので注意してください。

ブラウザなどから呼び出すとタイムアウトするのでコマンドラインから実行するかこまめに呼び出す工夫が必要です。

過去の株価を登録

銘柄×西暦数ループするのですべてやろうとするとかなりの時間がかかります。

ブラウザなどから呼び出すとタイムアウトするのでコマンドラインから実行するかJavaScriptなどからこまめに呼び出すような工夫が必要です。

とりあえず下記が全体のソースですがリメイクしてみてください。

<?php
// phpQueryの読み込み
require_once("./phpQuery/phpQuery.php");

$mysqli = new mysqli('サーバ', 'ID', 'パスワード', 'db_stock');
if ($mysqli->connect_error) {
	echo $mysqli->connect_error;
	die('接続失敗です。'.mysql_error());
} else {
	$mysqli->set_charset("utf8");
}

// 銘柄の一覧を取得
$sql = "SELECT stock_code FROM stock_m_name_tbl ORDER BY CAST(stock_code AS SIGNED)";

if ($result = $mysqli->query($sql)) {
	while ($row = $result->fetch_assoc()) {
		$stock_code = $row['stock_code'];

		$url = "https://kabuoji3.com/stock/" . $stock_code . "/";
		echo $url . "\r\n";
		$pages = getStockPages($url);
		asort($pages);
		insertStockYear($stock_code, $pages);
	}
	$result->close();
}

function getStockPages($url) {
	// 取得したwebサイトを読み込む
	$html = phpQuery::newDocumentFile($url);
	$lists = $html['#base_box > div > ul > li > a'];
	$pages = array();
	foreach(pq($lists) as $item) {
		if (!ctype_digit(pq($item)->html())) {
			continue;
		}
		array_push($pages, pq($item)->text());
	}
	return $pages;
}

function insertStockYear($stock_code, $pages) {
	global $mysqli;
	// 指定された年数分ループ
	foreach($pages as $index) {
		// 対象銘柄の1年分の株価を取得するURLを作成
		$url = "https://kabuoji3.com/stock/" . $stock_code . "/" . $index . "/";
		// 取得したwebサイトを読み込む
		$html = phpQuery::newDocumentFile($url);
		// 株価部分を取得
		$trs = $html['#base_box > div > div.data_contents > div > div > div > table > tr'];
		// 取得した1年間の株価数分ループ
		foreach(pq($trs) as $tr) {
			// 銘柄コード
			$stock_date = pq($tr)->find('td:nth-child(1)')->text();
			// 始値
			$opening_price = pq($tr)->find('td:nth-child(2)')->text();
			// 高値
			$high_price = pq($tr)->find('td:nth-child(3)')->text();
			// 安値
			$low_price = pq($tr)->find('td:nth-child(4)')->text();
			// 終値
			$closing_price = pq($tr)->find('td:nth-child(5)')->text();
			// 出来高
			$trading_volume = pq($tr)->find('td:nth-child(6)')->text();
			// 終値調整
			$adjusted_closing_price = pq($tr)->find('td:nth-child(7)')->text();
			// 登録用SQL作成
			$sql = "INSERT INTO stock_d_stock_tbl (stock_code, stock_date, opening_price, high_price, low_price, closing_price, trading_volume, adjusted_closing_price) VALUES (";
			$sql = $sql . "'" . $stock_code . "', '" . $stock_date . "', " . $opening_price . ", " . $high_price . ", " . $low_price . ", " . $closing_price . ", " . $trading_volume . ", " . $adjusted_closing_price . ") ";
			$sql = $sql . "ON DUPLICATE KEY UPDATE opening_price = " . $opening_price . ", high_price = " . $high_price . ", low_price = " . $low_price . ", closing_price = " . $closing_price . " , trading_volume = " . $trading_volume . " , adjusted_closing_price = " . $adjusted_closing_price;
			// DBへ登録
			$mysqli->query($sql);
		}
	}
}

$mysqli->close();

?>

過去のデータを一通り登録した後は毎日の株価を登録していくものも作ってみてください。

スクレイピングはサイトが突然閉じてしまうリスクもあるということとあまりにも頻繁にアクセスしているとアクセス規制がかけられてしまう場合もあるので注意してください。

銘柄登録の記事は下記へ

Step1 銘柄一覧をDBに登録

タイトルとURLをコピーしました