馬情報のHTMLデータ

HTML文章中のレース情報の下の方にある horseList に馬情報が埋め込まれています。その horseList は頭数分あります

馬情報は、下記下線中の要素 Waku(枠番)、Umaban(馬番)、HorseName(馬名)、Barei(馬齢)、Txt_C(斤量)、Jockey(騎手)、Trainer(厩舎)、Weight(馬体重) に埋め込まれています

馬情報の取得

プログラム的には、Waku、Umaban、HorseName、Barei、Txt_C、Jockey、Trainer、WeightをキーワードにしてHTMLから抽出すればデータ取得できることになります。ここでは下記クラスにデータを格納しています

	/*************************/
	/*       馬情報クラス       */
	/*************************/
	// オッズと人気はうまく取れないので削除。多分随時変更して表示するので、最初の取得ドキュメントに表示データが入ってこない為と思われる
	public class HorseInfo
	{
		public InfoData<int>     WakuNum           = new InfoData<int>( -1 );		// 枠番
		public InfoData<int>     HorseNum          = new InfoData<int>( -1 );		// 馬番
		public InfoData<string>  Horse             = new InfoData<string>( "" );	// 馬名
		public InfoData<string>  HorseLink         = new InfoData<string>( "" );	// 馬名リンク
		public InfoData<string>  Gender            = new InfoData<string>( "" );	// 性別
		public InfoData<int>     Age               = new InfoData<int>( -1 );		// 年齢
		public InfoData<double>  Weight            = new InfoData<double>();		// 斤量
		public InfoData<string>  Jockey            = new InfoData<string>( "" );	// 騎手
		public InfoData<string>  JockeyLink        = new InfoData<string>( "" );	// 騎手リンク
		public InfoData<string>  Barn              = new InfoData<string>( "" );	// 厩舎
		public InfoData<double>  HorseWeight       = new InfoData<double>();		// 馬体重
		public InfoData<double>  HorseWeightDiff   = new InfoData<double>();		// 馬体重差
		public List<HistoryInfo> History           = new List<HistoryInfo>();		// 履歴情報
	}

まず、Htmlの文字列取得を GetHtmlText() で取得し、HorseList を頭数分取得し nodes 配列に格納して、各馬毎の馬情報取得を GetHorseInfo() で行う。以下の Info 変数は HorseInfo クラスです

				string htmlText = GetHtmlText( Url );
				if( htmlText == "" )
				{
					return false;
				}
				var htmlDoc = new HtmlAgilityPack.HtmlDocument();
				htmlDoc.LoadHtml( htmlText );
				var nodes = htmlDoc.DocumentNode.SelectNodes( "//tr[@class=\"HorseList\"]" );
				if( nodes == null )
				{
					return false;
				}

				// 馬情報クリア
				Info.Clear();
				for( int index = 0; index < nodes.Count; index++ )
				{
					// 各馬毎の馬情報取得
					GetHorseInfo( nodes[ index ], out HorseInfo info );
					// 各馬毎の馬情報セット
					Info.Add( info );
				}
				return true;
			}

GetHorseInfo() 関数は、ノード nodes[ index ] を引数としてコールされます。このノード内から Waku、Umaban、HorseName、Barei、Txt_C、Jockey、Trainer、Weight をキーワードにしてHTMLからデータを抽出します

馬齢性別の Barei については、地方競データの名称が Age なので両方に対応させてます
斤量についてはTxt_C で取得しています。馬齢性別でも Txt_C がセットされているので2つ取得されるかとも思ったのですが、理由は不明ですが1つで取得できています(とりあえず様子見)
騎手については、地方競馬では span、中央競馬では td で定義されているので両方に対応させてます

・馬名には、レース履歴情報がリンクしているので child.GetAttributeValue( “href”, null ) でリンク先を取得します

・馬齢性別からは、性別と年齢を取得します

・馬体重からは、馬体重と体重変化を取得します

		// Node:馬情報が入ったURL内ノード
		// Info:取得した馬情報
		private static void GetHorseInfo( HtmlNode Node, out HorseInfo Info )
		{
			Info = new HorseInfo();

			var htmlDoc = new HtmlAgilityPack.HtmlDocument();
			htmlDoc.LoadHtml( Node.InnerHtml );
			string strData;

			// 枠番取得
			var nodes = htmlDoc.DocumentNode.SelectNodes( "//td[starts-with(@class, \"Waku\")]" );
			if( nodes != null )
			{
				strData = GetInnerStr( nodes[ 0 ] );			// ノード内の文字列取得
				if( Int32.TryParse( strData, out int result ))
				{
					Info.WakuNum.Data = result;
				}
			}
			// 馬番取得
			nodes = htmlDoc.DocumentNode.SelectNodes( "//td[starts-with(@class, \"Umaban\")]" );
			if( nodes != null )
			{
				strData = GetInnerStr( nodes[ 0 ] );			// ノード内の文字列取得
				if( Int32.TryParse( strData, out int result ))
				{
					Info.HorseNum.Data = result;
				}
			}
			// 馬名取得
			nodes = htmlDoc.DocumentNode.SelectNodes( "//span[starts-with(@class, \"HorseName\")]" );
			if( nodes != null )
			{
				strData = nodes[ 0 ].InnerText.ToString().Replace("\n","");// ノード内の文字列取得(改行無視)
				Info.Horse.Data = strData;
				foreach( HtmlNode child in nodes[ 0 ].ChildNodes )
				{
					strData = child.GetAttributeValue( "href", null );
					if(( strData != null ) && ( strData != "" ))
					{
						Info.HorseLink.Data = strData;
						break;
					}
				}
			}
			// 馬齢性別取得
			// 地方競馬の場合
			nodes = htmlDoc.DocumentNode.SelectNodes( "//span[starts-with(@class, \"Age\")]" );
			if( nodes == null )
			{
				// 中央競馬の場合
				nodes = htmlDoc.DocumentNode.SelectNodes( "//td[starts-with(@class, \"Barei\")]" );
			}
			if( nodes != null )
			{
				strData = GetInnerStr( nodes[ 0 ] );			// ノード内の文字列取得
				if( strData.Contains( "牡" ))
				{
					Info.Gender.Data = "牡";
				}
				if( strData.Contains( "牝" ))
				{
					Info.Gender.Data = "牝";
				}
				if( strData.Contains( "セ" ))
				{
					Info.Gender.Data = "セ";
				}
				if( Info.Gender.Data != "" )
				{
					if( Int32.TryParse( strData.Replace( Info.Gender.Data, "" ), out int result ))
					{
						Info.Age.Data = result;
					}
				}
			}
			// 斤量取得
			nodes = htmlDoc.DocumentNode.SelectNodes( "//td[starts-with(@class, \"Txt_C\")]" );
			if( nodes != null )
			{
				strData = GetInnerStr( nodes[ 0 ] );			// ノード内の文字列取得
				if( Double.TryParse( strData, out double result ))
				{
					Info.Weight.Data = result;
				}
			}
			// 騎手取得
			// 地方競馬の場合
			nodes = htmlDoc.DocumentNode.SelectNodes( "//span[starts-with(@class, \"Jockey\")]" );
			if( nodes == null )
			{
				// 中央競馬の場合
				nodes = htmlDoc.DocumentNode.SelectNodes( "//td[starts-with(@class, \"Jockey\")]" );
			}
			if( nodes != null )
			{
				strData = GetInnerStr( nodes[ 0 ] );			// ノード内の文字列取得
				Info.Jockey.Data = strData;
				foreach( HtmlNode child in nodes[ 0 ].ChildNodes )
				{
					strData = child.GetAttributeValue( "href", null );
					if(( strData != null ) && ( strData != "" ))
					{
						Info.JockeyLink.Data = strData;
						break;
					}
				}
			}
			// 厩舎取得
			nodes = htmlDoc.DocumentNode.SelectNodes( "//td[starts-with(@class, \"Trainer\")]" );
			if( nodes != null )
			{
				strData = GetInnerStr( nodes[ 0 ] );			// ノード内の文字列取得
				Info.Barn.Data = strData;
			}
			// 馬体重取得
			nodes = htmlDoc.DocumentNode.SelectNodes( "//td[starts-with(@class, \"Weight\")]" );
			if( nodes != null )
			{
				strData = GetInnerStr( nodes[ 0 ] );			// ノード内の文字列取得

				GetUmaWeight( strData, out double weight, out double weightDiff );
				Info.HorseWeight.Data     = weight;
				Info.HorseWeightDiff.Data = weightDiff;
			}
		}