LoginSignup
9
7

More than 5 years have passed since last update.

阿部寛のホームページをPHPでDOMる

Last updated at Posted at 2014-08-12

HTML を正しい文字コードで DOMDocument にしたい

DOMDocument が勝手に meta 検出してくれたら良いのだけど。
とりあえず自前で文字コード検出して、うまく変換して、DOMDocument を作る実験。

阿部寛のホームページが安定して昔ながらの文字コードを使ってくれているので実験材料に良い。
http://abehiroshi.la.coocan.jp/

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=x-sjis">
<title>阿部寛のホームページ</title>
</head>
<frameset cols=18,82>
  <frame src=menu.htm marginheight=0 marginwidth=0 scrolling=auto name=left>
  <frame src=top.htm marginheight=0 marginwidth=0 scrolling=auto name=right>
</frameset><noframes></noframes>

そもそも frame が懐かしい。

作成したコード

<?php
// HTML全体からtitleを取得
function html2title($html){
    // まずは UTF-8 で決め打ち
    $htmlEncoded = mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8');
    $doc = new DOMDocument();
    @$doc->loadHTML($htmlEncoded);

    // metaからcharset検出
    $charset = '';
    $elements = $doc->getElementsByTagName("meta");
    for($i = 0; $i < $elements->length; $i++){
        $e = $elements->item($i);

        // charset属性をチェック
        // <meta charset="utf-8"/>
        $node = $e->attributes->getNamedItem("charset");
        if($node){
            $charset = $node->nodeValue;
            break;
        }

        // http-equiv属性をチェック
        // <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        $node = $e->attributes->getNamedItem("http-equiv");
        if($node && strcasecmp($node->nodeValue, 'content-type') == 0){
            $node = $e->attributes->getNamedItem("content");
            if($node && preg_match('/[\; ]charset ?\= ?([A-Za-z0-9\-\_]+)/', $node->nodeValue, $m)){
                $charset = $m[1];
                break;
            }
            continue;
        }
    }

    // 検出されたcharsetがUTF-8じゃなかったら
    if($charset !== '' && !preg_match('/^utf\-?8$/i', $charset)){
        // 文字コード変換し直して
        $htmlEncoded = mb_convert_encoding($html, 'HTML-ENTITIES', $charset);
        // DOMも構築し直す
        $doc = new DOMDocument();
        @$doc->loadHTML($htmlEncoded);
    }

    // title取得
    $elements = $doc->getElementsByTagName("title");
    for($i = 0; $i < $elements->length; $i++){
        $e = $elements->item($i);
        return $e->textContent;
    }

    // titleが見つからなかった場合
    return false;
}

// -- -- 実験コード -- -- //
// x-sjis の例
$body = file_get_contents("http://abehiroshi.la.coocan.jp/");
$title = html2title($body);
echo "title = $title\n";

// euc-jp の例
$body = file_get_contents("http://d.hatena.ne.jp/");
$title = html2title($body);
echo "title = $title\n";

// Shift_JIS の例
$body = file_get_contents("http://www.tohoho-web.com/www.htm");
$title = html2title($body);
echo "title = $title\n";

// UTF-8 の例
$body = file_get_contents("http://qiita.com/");
$title = html2title($body);
echo "title = $title\n";

実行結果

title = 阿部寛のホームページ
title = はてなダイアリー - 写真・画像・動画付き日記を無料で
title = とほほのWWW入門
title = Qiita - プログラマの技術情報共有サービス

はてなダイアリーがいまだに euc-jp だったというのが意外。

関連

おわり

おそらくこれまでに何千人もが同じようなコード書いてるような気がするわけで、
DRY原則に真っ向から立ち向かってしまっている感なんだけど、
良いサンプルが見つからなかったので自分で作ってしまった。

もっとスマートな(というかデファクトでかつ安心できる)方法があれば知りたいです。。。

9
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
7