世紀末の墓

世紀末の墓

IT系寄りの雑記

webブラウザを自作したい!(3)

今回は前回言ってたように戻る進む再読込とかとか





ではなく、「サイトのアイコンを適用する」です。

サイトのアイコンを適用する

え?それだけ?

はいそれだけです(それ以外にもちょっとあるよ)


コレがわりと苦労しました。

簡単そうに見えてこれ持ってるプロパティとかなさそうで、html内部からURL探して持ってくる必要がありました。

もっといい方法ありそうですが、とりあえずぶん殴る形式になっちゃいました。知ってる人おしえてください・・・><

それではSSから
f:id:silmin:20170806094419p:plainf:id:silmin:20170806094435p:plain

まあこんな感じで変わってますね。

ソースコード

private void Browser_Navigated( object sender, WebBrowserNavigatedEventArgs e )
{
    //this.Text = browser.DocumentTitle;
    this.urlBox.Text = browser.Url.ToString();

    string iconUrl = getIconUrl( e );
    this.Icon = getIcon( iconUrl );
}

private string getIconUrl( WebBrowserNavigatedEventArgs e )
{
    foreach( HtmlElement linkTag in this.browser.Document.GetElementsByTagName("link") )
    {
        string relAttribute = linkTag.GetAttribute("rel");
        string iconUrl;

        if( relAttribute == "shortcut icon" || relAttribute == "icon" )
        {
            iconUrl = linkTag.GetAttribute("href");
            if( iconUrl.StartsWith("http") ) return iconUrl; 
            else if( iconUrl.StartsWith("/") ) return "http://" + e.Url.Host + iconUrl;
            else return e.Url.ToString() + iconUrl;
        }
    }
    return "http://" + e.Url.Host + "/favicon.ico";
}

//url -> Icon
private Icon getIcon( string url )
{
    WebClient webClient = new WebClient();
    using( MemoryStream stream = new MemoryStream( webClient.DownloadData( url ) ) )
    {
        Icon icon = new Icon( stream );
        return icon;
    }
}

private void Browser_DocumentCompleted( object sender, WebBrowserDocumentCompletedEventArgs e )
{
    this.Text = browser.DocumentTitle;
}

ざっくりいじった所だけ貼りました。

getIconUrl()でアイコンのURLを引っぱってきて、getIcon()でURLからアイコンを取得する感じです。

private string getIconUrl( WebBrowserNavigatedEventArgs e )
{
    foreach( HtmlElement linkTag in this.browser.Document.GetElementsByTagName("link") )
    {
        string relAttribute = linkTag.GetAttribute("rel");
        string iconUrl;

        if( relAttribute == "shortcut icon" || relAttribute == "icon" )
        {
            iconUrl = linkTag.GetAttribute("href");
            if( iconUrl.StartsWith("http") ) return iconUrl; 
            else if( iconUrl.StartsWith("/") ) return "http://" + e.Url.Host + iconUrl;
            else return e.Url.ToString() + iconUrl;
        }
    }
    return "http://" + e.Url.Host + "/favicon.ico";
}

ホントにぶん殴りコードですね・・・^^;
とりあえずlinkタグのやつを全部抽出してその中のrel探してきて、その属性がicon系なら引っ張るって感じですね。
それでも無かったらfavicon.icoにあるんじゃねってことで最後です。

C#スクレイピングしたこと無かったので苦戦しました・・・。
でも完成してみたら、割りと読みやすいというかわかりやすいコードになりました。

もっといい方法ないかなぁ(ボソッ

private Icon getIcon( string url )
{
    WebClient webClient = new WebClient();
    using( MemoryStream stream = new MemoryStream( webClient.DownloadData( url ) ) )
    {
        Icon icon = new Icon( stream );
        return icon;
    }
}

getIcon()はurlからアイコンを持ってくるメソッドです。
urlの示すデータを読み込んで、それをアイコンとして読み出す、ってイメージでしょうか。


んでそれらを↓でまとめるって感じになってます。

private void Browser_Navigated( object sender, WebBrowserNavigatedEventArgs e )
{
    //this.Text = browser.DocumentTitle;
    this.urlBox.Text = browser.Url.ToString();

    string iconUrl = getIconUrl( e );   //url持ってきて
    this.Icon = getIcon( iconUrl );     //アイコンにする
}


ここで気がついた人もいるかもですが、タイトルを取得するイベントを

WebBrowser.Navigated()

WebBrowser.DocumentCompleted()

に変更しました。

Navigatedだとまだサイトに案内できただけで、中身をすべてロードできていない(?)状態らしいです。
実際に、Navigatedだとタイトルを取得できないサイトが複数ありました。(←これはタイミングの問題でもあるかも)

DocumentCompletedは、サイトの中身のロードが完了すると発生するイベントなので、これを利用しようという結論になりました。これだと全部タイトルがしっかり適用されました。

大した変更じゃないけど、結構重要なのでやっておきました。



それでは今回はここまで。
次回こそは、戻る進む再読込つくろう!(全然難しくないんだけどね())