ちょっと必要になったので、ここの記事を参考にしました。
随分簡易的な物になってしまいました。
投稿用に改めて修正したのですが、目的の情報(ここから遅延情報の取得)が取れた事以外確認してないです。その為、しっかりとした検証が出来てないです。参考程度にしてください
ちょっと説明
- pythonのHTMLparserクラスのような使い勝手の物を目指しました。
- タグ、属性、データそれぞれが読みこまれた時に各々のメソッドが呼ばれます。
- 属性値はディクショナリで渡されます。
- コメント、空要素はタグとして認識しないようにしています。
コード
paser.cs
class parser
{
private string html_data;
private int data_index = 0;
private int reverse_index = 0;
private string html_tag;
private string attr_name;
private string tag_attr;
private string main_data;
private char delim;
private Dictionary<string, string> attribute_list = new Dictionary<string, string>();
private string[] empty_tag_list = new [] {"area","base","basefont","br","col","frame","hr","img","input","isindex","link","meta","param"};
//value reset
public void reset()
{
html_data = "";
data_index = 0;
reverse_index = 0;
html_tag = "";
attr_name = "";
tag_attr = "";
main_data = "";
}
//check empty tag
public bool empty_tag()
{
bool tag_flg = true;
foreach (string n in empty_tag_list)
{
if (n.ToLower() == html_tag)
{
tag_flg = false;
}
}
return tag_flg;
}
//check end tag
public void end_tag_check()
{
string e_tag = "";
int tmp_index = data_index;
data_index++;
if (html_data [data_index] == '/')
{
data_index++;
blank_remove ();
while ((html_data [data_index] != '>') && (html_data [data_index] != ' ') && (!check_eof ()))
{
e_tag += html_data [data_index];
data_index++;
}
}
//reverse index
data_index = tmp_index;
if (e_tag != html_tag)
{
main_data += html_data [data_index];
data_index++;
}
}
//check end of file
public bool check_eof()
{
if (data_index >= (html_data.Length - 1))
{
return true;
}
else
{
return false;
}
}
//remove blank
public void blank_remove()
{
while ((html_data[data_index] == ' ') && (!check_eof()))
{
data_index++;
}
}
//check tag
public void check()
{
while ((html_data[data_index] != '<') && (!check_eof()))
{
data_index++;
if ((html_data.Length - data_index) > 3)
{
if ((html_data[data_index] == '<')
&& (html_data[data_index + 1] == '!')
&& (html_data[data_index + 2] == '-')
&& (html_data[data_index + 3] == '-'))
{
while ((html_data[data_index] != '-')
&& (html_data[data_index + 1] != '-')
&& (html_data[data_index + 2] != '>'))
{
data_index++;
}
data_index += 3;
}
}
}
//end tag check
if ((html_data.Length - data_index) > 1) {
if (html_data[data_index + 1] == '/' || (html_data[data_index + 1] == '!'))
{
while ((html_data[data_index] != '>') && (!check_eof()))
{
data_index++;
}
data_index++;
}
}
}
//get tag
public void get_tag()
{
while ((html_data[data_index] != '>') && (html_data[data_index] != ' ') && (!check_eof()))
{
html_tag += html_data[data_index];
data_index++;
}
//html_tag = html_tag.ToLower(); こっちの方がいいかもしれない
find_tag(html_tag);
}
//get attribute
public void get_attribute()
{
while( (html_data[data_index] != '>') && (html_data[data_index] != '/') && (!check_eof() ) )
{
while ((html_data[data_index] != '=') && (!check_eof()))
{
attr_name += html_data[data_index];
data_index++;
}
data_index++;
delim = html_data[data_index];
data_index++;
while ((html_data[data_index] != delim) && (!check_eof()))
{
tag_attr += html_data[data_index];
data_index++;
}
attribute_list.Add(attr_name, tag_attr);
attr_name = "";
tag_attr = "";
data_index++;
blank_remove();
}
find_attribute(html_tag, attribute_list);
}
//get data
public void get_data()
{
while ((html_data[data_index] != '<') &&(html_data[data_index+1] != '/') && (!check_eof()))
{
main_data += html_data[data_index];
data_index++;
if ((html_data[data_index] == '<'))
{
end_tag_check();
}
}
find_data(html_tag, attribute_list, main_data);
}
//find tag
public virtual void find_tag(string tag)
{
}
//find atrribute
public virtual void find_attribute(string tag, Dictionary<string, string> attr_list)
{
}
//find data
public virtual void find_data(string tag, Dictionary<string, string> attr_list, string data)
{
}
public void parse()
{
while (!check_eof())
{
check();
if (!check_eof())
{
if ((html_data[data_index] == '<') && (html_data[data_index+1] != '/'))
{
data_index++;
blank_remove();
get_tag();
blank_remove();
if (html_data[data_index] != '>' && empty_tag())
{
get_attribute();
blank_remove();
}
if (html_data[data_index] == '>')
{
data_index++;
blank_remove();
if (html_data[data_index] != '<')
{
reverse_index = data_index;
get_data();
data_index = reverse_index;
}
}
if(html_data[data_index] == '/')
{
data_index++;
}
}
else if (html_data[data_index] == '>' && empty_tag())
{
data_index++;
reverse_index = data_index;
get_data();
data_index = reverse_index;
}
}
attribute_list.Clear();
html_tag = "";
main_data = "";
}
}
public string paga_data
{
get
{
return html_data;
}
set
{
reset();
html_data = value;
}
}
}
実装方法
下記をオーバーライドしてください。
paser.cs
//~~~~~~~~~~
//find tag method
public virtual void find_tag(string tag)
{
}
//find atrribute
public virtual void find_attribute(string tag, Dictionary<string, string> attr_list)
{
}
//find data
public virtual void find_data(string tag, Dictionary<string, string> attr_list, string data)
{
}
//~~~~~~~~~~
ここから遅延情報を取り出す例です。
呼び出し元でこんな感じに実装します。
main.cs
//~~~~~~~~~~
//使いたいところで下記の"parse();"を呼び出す
public void parse()
{
Dictionary<string, string> url_list = new Dictionary<string, string>();
string page;
parser1 ps = new parser1();
page = GetPage("http://www.jikokuhyo.co.jp/search/detail/line_is/kanto_takasaki");
ps.paga_data = page;
ps.parse();
}
public static string GetPage(string url)
{
WebResponse response = null;
Stream stream = null;
StreamReader
reader = null;
try
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
response = request.GetResponse();
stream = response.GetResponseStream();
if (!response.ContentType.ToLower().StartsWith("text/"))
return null;
string buffer = "", line = "";
reader = new StreamReader(stream);
while ((line = reader.ReadLine()) != null)
{
buffer += line + "\r\n";
}
return buffer;
}
catch (WebException e)
{
System.Console.WriteLine("Can't download:" + e);
return null;
}
catch (IOException e)
{
System.Console.WriteLine("Can't download:" + e);
return null;
}
finally
{
if (reader != null)
reader.Close();
if (stream != null)
stream.Close();
if (response != null)
response.Close();
}
}
//~~~~~~~~~~
class parser1 : parser
{
private bool state;
private string comment;
public parser1()
{
state = true;
}
public bool status
{
get
{
return this.state;
}
set
{
this.state = value;
}
}
public string m_comment
{
set
{
this.comment = value;
}
get
{
return this.comment;
}
}
//find tag
public override void find_tag(string tag)
{
}
//find atrribute
public override void find_attribute(string tag, Dictionary<string, string> attr_list)
{
}
//find data
public override void find_data(string tag, Dictionary<string, string> attr_list, string data)
{
if (tag == "div")
{
foreach (KeyValuePair<string, string> sPair in attr_list)
{
if (sPair.Key == "class" && sPair.Value == "corner_block_row_detail_d")
{
if ( (data != "\r\n現在、平常通り運転しています。") && (data !="\r\n情報提供時間は4:00~翌2:00となっています。") )
{
//なにかする
m_comment = data;
status = false;
}
else
{
}
}
}
}
}
}
//~~~~~~~~~~
後々役に立つと思ったけど、今のところ遅延情報の取得以外に使ってないです。