Google Adsenseがハーバライフ系の広告に占拠されつつある件

このサイトのように、IT系の話が多いサイトだと、 Googleアドセンスに自動表示される広告はIT系の広告が多い。 インターネットという場所がら、もともとそういう系統の広告主の絶対数が大きいのだろうし。

ところが、生活ネタとか食事ネタとか、非IT系のコンテンツを多く持つサイト/ブログだと、 Adsenseを貼っても出てくる広告は「ハーバライフ」系だらけでうんざり、といった現象が増加傾向にあるようだ。

AdSenseハーバライフ系広告対策室
実際、ふつーにブログ書いてて、たいした広告収入を期待するわけじゃないけどとりあえずGoogleAdsense申し込んで貼ってみたら、表示される広告はハーバライフだらけでした、なんてことになったらかなり萎えるだろうし、そもそも自分のブログの記事のそばに

「こたつが職場で年収1億でした」(←nofollowにしとく)

なんてふうな広告が表示された日にゃ、 「うるせんだよ腐れマルチ商法が!俺のサイトに出てくんな!俺まで同類に見られるじゃねえか!」といった感じになるのが人情というものである。

というわけで、とっととなんとかしてください→Googleの中の人&ハーバライフの中の人。

そういえば、アドセンスからちょっと話が飛ぶのだが、 先月、ドリコムブログでの広告表示の方法が変わった件では、ユーザーからもう非難ごうごう。 実際、ドリコムブログで書かれているブログをいくつかのぞいてみると、たとえばちょっとした詩のようなものを書いている記事の真下に結婚情報サービスや出会い系サイトの広告が画像つきで出てたりして、これはブログ書く側としても嫌なんじゃないかなー、といった感じの現象がそこかしこに。

先日日記に「ラグ●ロク」というオンラインゲームの記事を書いたら「RMT業者の広告」が載せられました。(RMT:ゲーム内で稼いだ架空通貨を現実の通貨で売買する事  ゲーム内でも規約違反とされ、また犯罪の温床と見られている行為)
なんていうコメントもあった。

ちなみにドリコムはつい先日、業績の大幅な下方修正を発表してこれまた非難ごうごう。

ドリコム、2007年3月期赤字転落へ--営業不振で売上高は従来予想の6割 (CNET Japan 2007/4)
広告ってむずかしいね。

再構築中。。。

MTのバージョンアップのついでにテンプレートもすべてデフォルトに戻して、再構築中です。 「いつもとデザイン違うぞ?!」とぎょっとされた方、ご心配なく。

訪問済みリンクの色は変えるべし

見ての通り、ブログのデザインをいじってみた。 というより、MovableTypeのいろいろなプラグインを使ってみたかったのだがそれにはMTのバージョンを上げる必要があり、またそもそもこれまでのデザインが実はMT2.x時代に提供されていたテンプレートを元にしていたせいかデザイン上もいろいろと不都合があり、どうしたもんかなーと思ってとりあえずMTをバージョンアップしてデザインテンプレートもデフォルトに戻し、いちから組みなおしてみたという次第。

MTのスタイルキャッチャーでいろんな提供サイトのCSSの中から適当に選んだのだが、どれを選んでもリンクの色が固定されていたり、固定されていなくても訪問済みと未訪問とで変化がわかりづらい色にしてあったりで、困った。 結局、しょうがないのでいくつかの要素について自分でCSSを追加するはめになった。

つまり、こんなふうに↓なっているデザインが非常に多いのだ。

a:link { color : green; } /*未訪問のアンカー*/
a:visited { color : green; } /*訪問済みのアンカー*/
まだ見てないページとすでに見たページのリンクを同じ色にして何が楽しいんだろう?もう読んだページとまだ読んでないページとが一目でわからなくて、使いづらいことこのうえ無いと思うんだが?

そういえばデザインってスゴイんだってことをもっと本気で言わなきゃダメだと思う:DESIGN IT! w/LOVEという記事が人気を集めているらしいのだが、このブログもまた同様にアンカーリンクの色が薄い緑で固定されてしまっている。いや、書いてあることからすればこんなツッコミは重箱の隅のそのまた隅っこのほう以外の何物でもないことは重々承知しておりますが。デザインって大切です。うん。

ところで、次のようなMT用CSSテンプレートさがしてます。

  • アンカータグに余計な装飾をいれてないCSS
  • 横幅を固定しないリキッドデザイン
  • MT3.xのスタイルキャッチャー機能に対応 (面倒だから^^;)

see also:
訪問済みリンクの色は変えるべし (Alertbox 2004/5)

Googleアドセンスでデリヘルの広告が表示されてる件

いやべつに騒ぐほどではないといえばないのだが。

とあるサイトの関係者との立ち話ついでにこんな相談された。 「いやあ、うちのサイトのアドセンス広告にデリヘルの広告が表示されることがあるらしくってさ。ちょっと困るんだよね」 で、後日そのハードコピーを送ってもらった。なるほど。たしかに某地方都市のデリヘルがGoogleアドワーズに出稿しているようだ。都市名のキーワードで出稿しているため、コンテンツを地域ごとに分けている知り合いのサイトのページ上のアドセンス枠に表示されてしまったという次第。

知り合いのサイトは情報の内容的にはまったくのノンアダルト。女性ユーザーも多いと思われる。そんなところにデリヘルの広告が表示されちゃったら、確かに困る。

Googleの広告編集ガイドラインにはこんなことが書かれている。

成人向けコンテンツとアダルト コンテンツ
  • Google では担当者がお客様の広告を確認し、それぞれのケースに応じて "非成人向けコンテンツ"、"成人向けコンテンツ"、"アダルト コンテンツ" のカテゴリに分類しています。
  • 担当者が各カテゴリに分類した後、アダルト コンテンツなどの成人向けの内容を含む広告は、AdWords の広告ポリシーに従っていることが確認された場合は基本的に承認されます。
  • 成人向けのコンテンツは、パートナー サイトへの掲載が許可されない場合があります。 その場合は、Google の検索結果ページのみに広告が掲載されることになります。
  • "アダルトコンテンツ" に分類された広告は、ドイツおよびインドなどの特定の国では掲載が許可されないため、これらの国の Google 検索ページおよび Google ネットワークには表示されません。
成人向けに分類しそこねて、パートナーサイトへ掲載されてしまってるということか。まあ、人為的なミスなんだろうなあ。

知り合いには、アドセンスのフィルタ設定機能を使えと言っておいたが、これ、万が一こういうザル状態が続くようなことになればコトだと思う。そうならないことを祈りつつ寝る。

see also:
Google Adsenseがハーバライフ系の広告に占拠されつつある件

華麗なるJAXB

要するに「Java内部でのデータの持ち回り方法」としてのJAXBにちょっと期待してみたいという話であって、タイトルは単なる思いつきである。

むかーし、Strutsに触っていてアクションフォームBeansの存在意義に疑問を感じたことがある。

public final class HogehogeForm extends ActionForm {
  private String name;
  public void setName(String name) {this.name=name;}
  public String getName() {return name;}
}
こんな感じのやつをいちいち手で書かなければならないこと&アクションフォームにはロジックを埋め込んではいけないということが腹立たしかった。まあそのほうがセキュリティ上も良いとかいろいろ理由はあるのだが、それにしても納得いかない感はあった。なんか、めんどくさいやん。

DynaActionFormと呼ばれるものが使えるようになった頃にはこの手間は少し軽減されたらしい。 そもそもEclipseなどの開発ツールによる、Javaクラス内のプロパティに対するsetter/getterメソッドを自動生成してくれるような補完機能もめずらしくなくなってきたこともあり、単調なコードをゴリゴリ書く作業もちょっとは減った。

しかし、しばらくたつと今度はO/Rマッピングツールも組み合わせてどうのこうのというのが流行(?)になり、struts-config.xmlのややこしさにもまだ慣れきってないうちからさらにhibernate-mappingのXMLだとかを書けだのそれ用の永続化クラスを書けだのそれってStrutsのアクションフォームとどう違うのよ?兼用できないの?え?無理ぽい?そうですか(涙)。みたいな感じで冗長なコーディング作業がさらに増えそうにしか感じなかった。

他のフレームワークに浮気しようかとか思っても、たとえばSeaser系列のO/RマッピングツールであるところのS2DAOなんかでも、DTOと呼ばれる、プロパティとそのsetter/getterだけを備えた単純なコードをいっぱい作らなければならず、使ってる方法/技術の名前が変わっただけで本質的にあまり変わってないようにしか見えなかった。いやまあ、JavaBeansってそういうもんだからしょうがないんじゃんと言ってしまえばそれまでだが。

しばらくJavaフレームワークの話から遠ざかっていたら、最近、WEB+DB PRESS Vol.38に、コードジェネレータを作ろうとかアクションフォームとDTOの詰め替え処理が面倒だとかいう記事が載っていて、やっぱりそういう話になるよなあなんて思ってた。

そうこうしている間に、まったく別な方面で、「HTMLじゃなくてXMLで情報を出すのになんかいい方法ないかな?ほら、最近流行のWeb-APIってやつでさ」みたいな話からJAXBに行き当たった。 JAXBとは、XMLデータを入出力するためのコードをJavaで書く際のコードジェネレータみたいなものである。

ためしにと思って、アマゾンの商品データのXML定義ファイル(XSD形式)を、JAXBが提供するxjcコンパイラなるものに食わせてみたら、getProductname()/setProductname()のようにXMLのタグと属性のひとつひとつに対するsetter/getterメソッドを含むすべてのソースコードを自動生成してくれたではないか!!それを画面上で見た瞬間に、 Javaアプリ内でのデータ層/AP層/プレゼン層の3層間での情報のうまいやりとり方法に悩んでいたことを思い出した。

もしかして、お前じゃないか?JAXB!?

なにしろXMLだ。strutsとかseaserとか将来的にどう転ぶかわからないようなフレームワーク技術に依存した技術ではない。strutsとXMLを比べてどうのこうのというのも変な話だが、実感として標準により近い技術のほうが安心感があるに決まってる。

PCのブラウザ向けにHTML出力するのは当然のこと、携帯向けもよろしくねもちろん3キャリア対応でねとか、PDF形式の帳票出せるようにしたいからよろしくとか、最近流行のWeb-APIでXML形式もお願いね、とかなんだとか、とにかくプレゼン層でやりたいことは増える一方だ。

だからこそ、情報はとりあえずXML出力で統一するから、、XSLTでHTMLに変換するなり、PDF出力はXSL-FOするなり、Web-APIぽく提供したければそのままXMLで出すなりJSONに変換するなり、とにかくデザインの手段は好きなようにしてね、みたいな流れになるのは必然じゃないだろうか。

だとすれば、XMLの定義ファイル=XSD=は当然つくらざるを得ないしその作業に抵抗はない。そしてJAXBはその定義ファイルを読んで理解しsetter/getter群を一手に引き受けて書いてくれるという。なんだかすごくしっくりくる。おまけにJava6以降ではJAXBは標準技術扱い(って言うのかしらんが)だと言う。こうなってくると、少なくともAP層とプレゼン層の情報のやりとりの技術はJAXB(とXML)で決まりとすら思えてくる(というのはオーバーかな)。

とか考えていたら、hyperjaxb2なるプロジェクトを見つけた。やはり筆者程度で思いつくアイデアならとうの昔に思いついて具体化に着手している先人はいるものだ。つまりAP層にあるJAXBオブジェクトとDB層とを直接マッピングしようというhybernateの拡張(?)の技術らしい。この流れもまた必然に感じる。

しかし、さらに掘り下げると、【レポート】Java SE 7の「プロパティ」が見えてきた - setter/getterのないJavaへ (1) Java SE 7の新文法「プロパティ」とは(マイコミジャーナルと 2007/5)という記事まで行き当たってしまい、JAXBはもちろんすべては過渡的な技術に過ぎないのかと思うと気が遠くなってきたので酒飲んで寝ることにする。

追記:
ところで、例えば楽天のAPIをはじめ、国内企業のAPIサービスの多くが、そのXSDなりDTDなりの定義ファイルを公開してない。っていうか作ってない/作る意味がわかってないんじゃないかという疑いすらある。ちゃんと作って公開しようよ。 上で書いたようにアマゾンみたいに。こういう技術のための定義ファイルなんだから。

一向に学習能力を見せない栃木県警察

失笑。

栃木県警サイトのリンクポリシーが後退? (スラッシュドット ジャパン 2007/5)

see also:

「Webサイトというものは、それを作った組織と人間の情報リテラシーの熟度を映し出す鏡である。」( グーテンベルグ 1450年) (嘘)

JASRACもJASARCだし裁判官も裁判官

訴える側も、それを聞き入れて裁く側も、知識不足ばかりでなく、アタマがおかしくなってるとしかいいようがない。

以下は、 音楽保存サービス:ストレージ利用は著作権侵害 東京地裁-今日の話題:MSN毎日インタラクティブの切り抜きである。

どうみてもただのストレージサービスにしか見えない。これで著作権侵害?やってられん。

と思ったら、 高部真規子 - Google 検索 してみると、IT関連の訴訟で、物議をかもすおかしな判決を出す裁判官として有名な人らしい。どおりでね。

そういえば海外でもこんな話があるらしい。

英国の判事が5月16日、インターネット上でテロ活動を扇動した容疑で起訴された3人の男性の公判中に、「Webサイト」などの基本的な用語を理解するのが難しいと認めた。
ITmedia News:「Webサイト」が分からない――裁判官が公判中に告白(2007/5)
だがしかし、こうした裁判官に同情する気にはまったくなれない。はっきりいってそれほど難しい部類に入る専門知識ではない。裁判官という職業からみて知識不足もはなはだしい。

see also:
副作用が大きすぎるストレージ・サービス違法判決 (栗原潔のテクノロジー時評Ver2 [ITmedia オルタナティブ・ブログ] 2007/5)

アマゾンのページの横幅がそろそろ限界?

アマゾンのページ上部のタブの数が増えすぎ。横幅が900ピクセル近くなっており、ブラウザに横スクロールバーが出てしまいがちなっている。

2004年のこの記事を書いてたころからそろそろ限界じゃね?と思っていたのだが、ついにそのときが来たかな。それでも3年持ったわけだが。

アメリカ本国のアマゾンはとっくの昔にタブを廃止してくる。取り扱い商品ジャンルが増えてくると、楽天市場みたいなカテゴリ表示方式にするか、パーソナライズ機能に磨きをかけるかの選択がいよいよもって重要になってきそう。

DoS攻撃をはじくためのPHPスクリプト

絨毯爆撃ブラウザという単語を目にしたのはこの記事が最初だった気がする。

このところはてなブックマークへの過度なアクセスがよく見られます。User-Agent などを見ていても特殊な bot などのものではなく、その多くが Internet Explorer や Firefox などの一般のブラウザのそれを名乗っています。
中には、目立たないようにそういった User-Agent を敢えて名乗っているリクエストもありそうですが、どうもそれらの挙動を見てるに、巡回系のソフトウェアや先読み系のブラウザのような振る舞いが多そうです。ページ内に表示されたリンクを節操なくすべて辿るということで、僕は勝手に絨毯爆撃系ブラウザなんて呼んでますが。
naoyaのはてなダイアリー - 絨毯爆撃系ブラウザ (2005/11)

今も(たぶんこれからも)相変わらず「絨毯爆撃ブラウザ」は存在し、ときどきやってきてはサーバーの負荷を急上昇させてくれるので始末が悪いというか、困る。

困る度合いというのはWebサイトの性質やサーバー構成、内部のアプリのつくりによって千差万別なのだが、筆者の知る某サイトの場合、ページアクセスがあるたびに背後のDBサーバーでインデックスの効きにくいSQLが走ってしまうという厄介な構成(それをまずどうにかしろという話はまあアレだオトナの事情という奴だ)であるため、絨毯爆撃系ブラウザが来襲するとWebサーバではなくDBサーバのほうが悲鳴をあげる。

その悲鳴も一瞬ですむのならまあ別にほっといてもよいのだが、最近どうも、5分、10分とその状態が続くことがあるらしく、その間負荷あがりっぱなし&他の閲覧者も巻きぞえ食って「なんか重いよ?!」の苦情が。。。

という相談を受けてためしに作ってみたのが下記のスクリプト。

class_antidos.php:
<?php
require_once('Cache/Lite.php'); 
/**
 * DoSまがいの連続アクセスであるかどうかを判定するクラス
 *
 * 任意の識別コード(IPアドレスとか)毎に
 * アクセス時刻のリストをキャッシュしておき、
 * それを判定材料とする
 */
class antidos {

    /**
     * インターバル秒。
     * この秒数の間のアクセス数をカウントする
     */
    var $interval;

    /**
     * インターバル秒あたりの最大アクセス数。
     * これを超えるとDoSと判断させる
     */
    var $accesslimit;

    /**
     * Cache_Liteのインスタンス
     */
    var $cacheobj;

    /**
     * Cache_Liteのグループid
     */
    var $cache_groupid;

    /**
     * Cache_Liteの有効期間(秒)
     */
    var $cache_lifetime;

    /**
     * Cache_Liteが使うキャッシュファイルの
     * 保存先ディレクトリ。
     */
    var $cache_dir;

    /**
     * コンストラクタ
     * @param string
     */
    function antidos() {
        // 以下では20秒間の間に15回以上アクセスして
        // きたIPアドレスをはじく
        $this->interval = 20;
        $this->accesslimit = 15;

        // interval < lifetimeでなければならない。
        // とりあえず60秒
        $this->cache_lifetime = 60;

        // キャッシュのグループid。必須ではないが
        // 念のため割り当て。名前は何でも良い
        $this->cache_groupid = "antidos";

        // キャッシュ保存先ディレクトリ。
        // /dev/shm などのtmpfsなファイルシステムに入れると
        // 速くなってよいかもしれないが、
        // 実際のところ小さなファイル群なので
        // 通常のext3なんかでもOSのページキャッシュに
        // 全部乗れちゃうかもしれない。
        $this->cache_dir = "/tmp/";

        // Cache_Liteのインスタンス
        $this->cacheobj =& new Cache_Lite(array(
            'cacheDir' => $this->cache_dir, 
            // 数が多いかもしれないので2層にしておく
            'hashedDirectoryLevel' => 2,
            'lifeTime' => $this->cache_lifetime
        ));
        return TRUE;
    }

    /**
     * DoSかどうか判定する。
     * @param string $id 端末特定のための何らかの文字列。IPアドレスなど
     * @return boolean DOSならtrue、でなければfalseを返す
     */
    function doscheck($id) {
        // Web画面ではなくCLI(コマンドライン)で実行され
        // ている場合は無条件にfalseを返す
        if (PHP_SAPI == "cli") { return false; }

        // 過去のアクセス状況をキャッシュから取得
        $utimelist = $this->getdata($id);

        // 現在時刻をアクセス状況に追加
        $utimelist[] = time();

        // アクセス状況をキャッシュに保存しておく
        $this->savedata($utimelist, $id);

        // まだアクセス制限数ぶんもカウントが
        // 記録されていない場合は当然false
        if (count($utimelist) < $this->accesslimit) {
            return false;
        }

        // 念のため逆順ソート
        rsort($utimelist, SORT_NUMERIC);

        // アクセス数カウンタ
        $cnt = 0;
        // 初回アクセス時刻
        $ts = array_shift($utimelist);
        // 判定処理
        foreach ($utimelist as $t) {
            $cnt++;
            if ($ts - $t < $this->interval 
                && $cnt > $this->accesslimit) 
            {
                return true;
            }
        }
        return false;
    }

    /**
     * キャッシュを取得。過去のアクセス時刻utimeの配列として返す。
     * キャッシュがヒットしなければ空の配列を返す。
     * 
     * @return array
     */
    function getdata($cacheid) {
        $data = $this->cacheobj->get($cacheid, $this->cache_groupid);
        if (empty($data) == true) {
            return array();
        }
        $ar = explode(",", $data);
        return $ar;
    }

    /**
     * キャッシュに配列を保存する
     *
     */
    function savedata($utimelist, $cacheid) {
        // 逆順ソートしておく
        rsort($utimelist, SORT_NUMERIC);
        $ar = array();
        $c = 0;

        // アクセス制限数プラスアルファ程度の個数を
        // キャッシュ保存すればよいんじゃないかと
        foreach($utimelist as $t) {
            $c++;
            $ar[] = $t;
            if ($c > $this->accesslimit + 10) {
                break;
            }
        }
        // キャッシュの保存。配列はカンマ区切りに変換
        return $this->cacheobj->save(
            implode(",", $ar), 
            $cacheid, 
            $this->cache_groupid
        );
    }

}

?>
こんな感じで呼び出して使う↓
<?php
require_once('antidos_class.php'); 
$obj =& new antidos();
// 端末特定にはとりあえずIPアドレスを使う
if ($obj->doscheck($_SERVER["REMOTE_ADDR"]) == true) {
    // header("Service Unavailable", TRUE, 503); //とかやるのもいいかも
    echo "too many access!!!!!";
    exit; //強制終了!
} else {
    echo "welcome!";
    //通常処理を続ける。。。
}
?>

注意点、その他。

  1. mod_cbandとかmod_throttleとかmod_limitipconnとかそういうApacheモジュールもあるよ

    そのとおりである。しかし、事情によってはApacheモジュールの追加よりもアプリ改造のほうが試しやすいということもありうるだろう。いずれにせよそうしたApacheモジュールも、このスクリプトも、それぞれ一長一短あるのでご利用は計画的に。
  2. PHPでやったんじゃ、Webサーバに負荷がかかるのは変わらなくね?

    そのとおりである。が、PHP上でものすごいでかい処理をしているとか、あるいは上に書いたようにDB側に負荷がかかってしまうとかいう場合にはその直前で止めることができるわけだからそこそこ効果がある。
  3. 端末の特定にIPアドレスを使うってのはちょっと。プロキシ経由のアクセスとかが巻き添えにされがち?

    そのとおりである。たとえば企業内LAN上の端末が外部のひとつのWebサイトにアクセスするときはアクセス元IPがその企業のプロキシサーバ(あるいは単なるNATルーターかもしれない)のIPに集約されるため、その企業内の複数人が普通にアクセスしてるだけなのにそれをdos攻撃と誤認するような状況はありうる。が、端末の特定は別にIPアドレスに限らない。「IPアドレス+なんらかのユニークなCookie値」とかそういうのでもいいはずである。例えば、GoogleAnalyticsを入れてるWebサイトは多いが、それ用のCookie値(utmaとかutmbとかいろいろ)を勝手に拝借することも可能だろう。
  4. 携帯端末は?

    とりあえずキャリアのゲートウェイのIPアドレス一覧は各社から公開されているのでそれらのIPはDoS判定から除外するようなコードを追加すればよいと思う。 (絨毯爆撃ブラウザ搭載の携帯端末なんて登場されたらそれはそれで困るが)
そんな感じ。