獲取網站圖標Icon


  通常情況下,做網站的都會給自己的網站添加一個Icon,瀏覽器上一長排的標簽頁,用Icon來區分就顯得更加醒目。現在想找一個沒有Icon的網站並不好找,可見沒有Icon的網站是多么的業余啊。"什么?你問Icon是什么?你走吧,這是討論技術的地方!"

   

  想知道如何獲取Icon,就要弄明白怎樣設置Icon。先討論一下設置Icon,再介紹獲取Icon,並提供相應Java代碼以供參考。

一. 設置網站Icon

   設置Icon有兩種方式:

  1. 看一下我們專業的博客園,看到灰色部分了嗎,在head標簽中有個link標簽,將rel設置為"shortcut icon",href 設置為Icon的位置,type設置成實際圖標類型就OK了。這個Icon文件不是必須以favicon.ico命名,也可以選擇png等其他格式的圖片。

  2. 如果用第一種方式,每個頁面都要寫link,是不是挺麻煩的,可能會用模板之類的東西自動生成,這個我不懂啦。如果瀏覽器發現html中沒有寫明Icon位置,就自動到網站根目錄下嘗試讀取favicon.ico文件。再看一下我們專業的博客園,看到了嗎,Icon顯示出來了。注意:根目錄下的文件就必須以favicon.ico命名了。考慮到瀏覽器兼容性,大部分的網站除了在html中指定Icon的位置,同時也會在網站根目錄下存放Icon文件。

  

二. 獲取網站Icon

  知道怎么設置Icon,獲取Icon就很簡單了。解析html相對來說比較麻煩,可以直接到網站根目錄下嘗試讀取favicon.ico。如果沒有,再解析html(話說我試了很多常用網站,都可以從根目錄下讀取,想找個根目錄下不存放Icon的網站還真不容易,這時我想到了12306,試了一下果然沒有啊,事情並沒有想象的那么簡單,12306會奇葩到你想不到,后邊再說)。思路就是這樣,很簡單,但是在實現的過程中會有很多細節問題。用java代碼實現一下吧,並詳細說明可能遇到的細節問題。

  下邊是獲取Icon地址的入口函數,傳入網絡地址即可。

    // 獲取Icon地址
    public static String getIconUrlString( String urlString ) throws MalformedURLException {

        urlString = getFinalUrl( urlString );
        URL url = new URL( urlString );
        String iconUrl = url.getProtocol() + "://" + url.getHost() + "/favicon.ico";// 保證從域名根路徑搜索
        if ( hasRootIcon( iconUrl ) )
            return iconUrl;
        
        return getIconUrlByRegex( urlString );
    }

   getFinalUrl是獲取網址經過3XX跳轉之后的url地址,如果沒有跳轉就返回原來的url。防止有些網址會出現跳轉的情況,所以先搞到跳轉之后的網址在進行獲取。java的HttpUrlConnection默認情況下會自動跳轉,為什么還要手動獲取呢?比如www.rayli.com會跳轉到www.rayli.com.cn,我要訪問 www.rayli.com/favicon.ico,我希望跳轉到www.rayli.com.cn/favicon.ico。但實際情況卻跳轉到了www.rayli.com.cn,這樣就造成我判斷錯誤,所以需要手動解析跳轉后的地址。

   hasRootIcon函數判斷網站根目錄下是否存在favicon.ico文件,注意在傳入url之前要保證傳入的是根路徑地址,因為有些網站跳轉過后並不是跳轉到根目錄,當正常響應並且存在返回內容時就認為有指定文件。getConnection函數是根據url獲取一個HttpUrlConnection。

    // 判斷在根目錄下是否有Icon
    private static boolean hasRootIcon( String urlString ) {
        HttpURLConnection connection = null;

        try {
            connection = getConnection( urlString );
            connection.connect();
            return HttpURLConnection.HTTP_OK == connection.getResponseCode() && connection.getContentLength() > 0;
        }
        catch ( Exception e ) {
            e.printStackTrace();
            return false;
        }
        finally {
            if ( connection != null )
                connection.disconnect();
        }
    }

  getIconUrlByRegex是根據正則表達式從html中獲取Icon地址,getHead方法是獲取網頁的head結束標簽之前的文本,然后用正則表達式匹配內容,這里的正則表達式有兩個,這是因為rel和href的順序是不固定的。匹配到以后判斷一下是否為相對路徑,如果是的話做進一步處理。

private static final Pattern[] ICON_PATTERNS = new Pattern[] {
            Pattern.compile( "rel=[\"']shortcut icon[\"'][^\r\n>]+?((?<=href=[\"']).+?(?=[\"']))" ),
            Pattern.compile( "((?<=href=[\"']).+?(?=[\"']))[^\r\n<]+?rel=[\"']shortcut icon[\"']" ) };
// 從html中獲取Icon地址
    private static String getIconUrlByRegex( String urlString ) {

        try {
            String headString = getHead( urlString );
            
            for ( Pattern iconPattern : ICON_PATTERNS ) {
                Matcher matcher = iconPattern.matcher( headString );
                
                if ( matcher.find() ) {
                    String iconUrl = matcher.group( 1 );
                    if ( iconUrl.contains( "http" ) )
                        return iconUrl;

                    if ( iconUrl.charAt( 0 ) == '/' ) {//判斷是否為相對路徑或根路徑
                        URL url = new URL( urlString );
                        iconUrl = url.getProtocol() + "://" + url.getHost() + iconUrl;
                    }
                    else {
                        iconUrl = urlString + "/" + iconUrl;
                    }
                    return iconUrl;
                }
            }
        }
        catch ( Exception e ) {
            e.printStackTrace();
        }
        return null;
    }

 

三. 測試一下

  整個流程就是這樣的,測試一下吧,爬取hao123的一級域名,一共一百多個。代碼如下,沒啥好說的,結果顯示除了沒有Icon的網站和不能正常響應的網站,都可以得到Icon地址。但是,有一個網站除外,那就是我們偉大的12306。訪問www.12306.cn時,其中有一段js,判斷如果網址是www.12306.cn則locayion到http://www.12306.cn/mormhweb/。我靠,你用js跳轉我就直接沒轍了。哎,隨它去吧,各位可知道用js跳轉的壞處呀,如果禁用了js你看到的就是白花花的一片,像棉花、像銀子、像白雲、像一張白紙啊,親,我的想象力又被你激發了!

    // 爬取一級域名
    private static Set<String> getUrls( String urlString ) {

        Set<String> urlSet = new HashSet<String>();
        Pattern pattern = Pattern
                .compile( "(http|https)://www\\..+?\\.(aero|arpa|biz|com|coop|edu|gov|info|int|jobs|mil|museum|name|nato|net|org|pro|travel|[a-z]{2})" );
        Matcher matcher = pattern.matcher( getHtml( urlString ) );
        
        while ( matcher.find() ) {
            urlSet.add( matcher.group() );
        }

        return urlSet;
    }
public static void main( String[] args ) throws IOException {
        long startTime = System.currentTimeMillis();

        Set<String> urlSet = getUrls( "http://www.hao123.com/" );
        for ( String urlString : urlSet ) {
            System.out.println( urlString );
            System.out.println( getIconUrlString( urlString ) );
        }
        
        System.out.println( urlSet.size() );
        System.out.println("耗時:"+(System.currentTimeMillis() - startTime)+" ms" );
    }

 

 特殊情況比較多,代碼肯定有不完善的地方,歡迎交流指正,完整代碼供下載: IconFinder.java


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM