[BlueLeaf1336]> PROBLEMS> 探求其之弐 マイクロソフト技術情報目次作成>

再始動

historyTOP

2006/09/13:作成

はじめにTOP

すごく久しぶりです。最近、msnews.microsoft.com の microsoft.public.jp.msinformation が方針を変えたらしくて、マイクロソフト技術情報の追加や更新の情報が送られてこなくなり、月一回の新着セキュリティ情報だけになってしまったような感じです。

そんなこんなで再開しようと思っています。ちなみに、前回はどうやってデータを保持するかで邪魔くさくて頓挫してたんですが、Delphiでmdbを操作 - 003 で、mdb ファイル(Accessの使っている形式)を Delphi から操作するクラスを書いたので、これを使うことにします。というか、これをやるためにクラスを書いた、が正解です。

また、技術情報のダウンロードは、リンクタグ作成 HrefBuilder でやっているので(もちろん前回・前々回でも)、これを流用できそうです。

少しだけ復習TOP

マイクロソフト技術情報のデータです。「ソース」とあるのは、ダウンロードして無断で拡張子をtxtに変えたものです。UTF-8 なのでブラウザ上で見ると化けまくっているかも知れません。

しかもどうしようもないぐらい改行が入っていません。ただ、これについては逆に楽ともいえます。でも、改行なしを前提に、ってのもやりすぎでしょうけど。

「未作成」分については、普通のブラウザで見た場合、マイクロソフトのサーバーがそれなりにリダイレクトして、エラーページに飛ばされてしまうので、ここに無断掲載しているのもその飛ばされたページのものです。

ただ、リンクタグ作成 HrefBuilder で書いた処理だと、ブラウザのようにリダイレクト先のページのソースを取ってこれません。しかし、今回の場合そっちの方が都合が良いともいえます。

それ以前に、未作成ページについてはサーバーがコード「302」を戻してくるので、ソースをダウンロードする必要もないし、ダウンロードすべきでないと思います。逆に存在するページの場合は、「200」が戻るので、この場合はソースのダウンロードまで行うようにかなり初期の段階で切り分けることができます。

マイクロソフト技術情報の目次に要りそうな情報TOP

http://support.microsoft.com/?scid=kb;ja;256986 の ソース をじっと眺めて決めていきます。

当然ページ全体をダウンロードすれば「最終更新日」「リビジョン」なんかも取れるんですが、ここでは、ヘッダだけ </;head> までの情報だけでやりくりできるものに限ることにします。もっというと、<XMLREADER> までとします。

WebサーバにGETコマンドを送る では何の説明もなく、<XMLREADER> としていましたが、今回改めてソースを眺めてみて、<XMLREADER> 以降 </;head> までは技術情報に関する情報は無い(たまたまかも...)ようなので、今回もそれで行きます。この辺は、できる限りダウンロードする量を減らしたい、それだけの理由です。

というわけで、<html> から <XMLREADER> までのコードをココに引用して、技術情報に関係してそうな箇所を 赤色 で強調してみます。

ちなみに、これはブラウザの「ソースの表示」で取得していますので、クライアントのGET要求に対するサーバーのレスポンスデータが抜けていますが、それはそれなりにさばいた後とします。


<html><head><script type="text/javascript" src="/common/script/gsfx/common.js?4"></script><script>setcookieval("gssSITE","gn");</script><script type="text/javascript">SaveToFavoritesData.savingMsg='¥u4fdd¥u5b58¥u4e2d';SaveToFavoritesData.connectionErrorMsg='¥u63a5¥u7d9a¥u3067¥u304d¥u307e¥u305b¥u3093¥u3067¥u3057¥u305f';SaveToFavoritesData.savedMsg='¥u3053¥u306e¥u30da¥u30fc¥u30b8¥u3092¥u4fdd¥u5b58¥u3057¥u307e¥u3057¥u305f';SaveToFavoritesData.noSaveErrorMsg='¥u4fdd¥u5b58¥u3067¥u304d¥u307e¥u305b¥u3093¥u3067¥u3057¥u305f';SaveToFavoritesData.surveyUrl='¥x2fcommon¥x2fsurvey.aspx¥x3fscid¥x3dsw¥x3bja¥x3b1167¥x26surveystyle¥x3dpopup¥x26showpage¥x3d1¥x26site¥x3dgn¥x26siteregion¥x3dja¥x26url¥x3d%2fDefault.aspx%3fscid%3dkb%3bja%3b256986¥x26p0¥x3dkb¥x26p1¥x3dja¥x26p2¥x3d256986';SaveToFavoritesData.noCookieUrl='¥x2fgp¥x2fnocookies';</script><script>var g_currentContent='kb¥x3bja¥x3b256986';</script><script type="text/javascript" src="/common/script/fx/survey.js?4"></script><meta name="robots" content="noarchive"><meta name="KBParents" content="8593 3198 1163 5886 5887 5891 5892 5914 3219 1173 5917 3221 6728 3223 5918 3222 5924 3228 7341 7274 1131 7940 7017 5732 3071 7941 7936 7606 3188 6842 5872 5881 3194 6843 6719 6519 6321 6912 6898 7482 6713 6513 1139 10435 7864 9980 5902 3208 1167 5903 "><meta name="Keywords" content="kbinfo kbregistry kbenv kbfaq kbpubtypekc kbmsccsearch KB256986"><meta name="Description" content="Microsoft Windows レジストリについて説明し、その編集方法に関する情報を提供します。"><meta name="MS.LOCALE" content="ja"><meta http-equiv="content-type" content="text/html; charset=utf-8"><script>var gCookieDomain='';</script><title>Microsoft Windows レジストリの説明</title><XMLREADER>

あれ? WebサーバにGETコマンドを送る (2005年7月) のときと並びが変わっています。でもまあ、<XMLREADER> 以前、というルールは生きているようなのでこのまま行くことにします。

連続していてわかりにくいので少し分解します。

もちろん上記が取得するためのURLはわかっています。つまり、文書番号もわかっています。

さて、「title」と「Description」はわかりやすいです。問題は「Keywords」と「KBParents」です。

「Keywords」の方は意味はわかります。kbregistry はレジストリに関係しているヨ、kbenv は 環境(ENVironment)関係、kbfaq は FAQ だろう、kbpubtypekc は... なんだこれ。kbmsccsearch も不明。まあ、これの意味はどこかにあるんでしょう。よしとしよう。

でも、これをデータベースに保存するとして、「kbinfo kbregistry kbenv kbfaq kbpubtypekc kbmsccsearch KB256986」をひとつの文字列として持っちゃっていいのか? 後で使えるか? でもばらばらにしてしまうと、たった一つの文書に対して、7個(しかも上限個数たぶんなし)のデータとなると、もうテーブルを分けて7レコードになったりして、一体技術情報がいくつあると思とんねん状態です。

さらに「KBParents」となるとお手上げです。意味はわからないし(Parents だけにこの技術情報の親?)、50個もあります。技術情報が10000件(100000から999999までで総当りで調べないといけないので90万ページ、そのうち1%強しか有効なページがないとして)あったら、個別に持つと50万件! mdb の処理できる量と思えません。ま、本体だけで 10000レコードもあれば、破綻しそうですが。

あれですね。ひとつの文字列で持つことにしましょう。ということで...

マイクロソフト技術情報の目次の項目TOP

次のように決めました。

内容フィールド名型とサイズその他
文書番号KBID6桁文字列主キー NOT NULL
URLURL60桁文字列NOT NULL
レスポンスコードRESCODE3桁文字列-
タイトルTITLE長めの文字列-
説明DESCRIPTION長めの文字列-
キーワードKEYWORDS長めの文字列-
KBParentsKBPARENTS長めの文字列-
取得日GETDATE日付文字列(年月日時分秒)-

タイトルや説明などは、mdb で扱える文字列の長さで決めたいと思います。確か Memo 型にしてしまうと、LIKE 検索が利かなかったと思うので、TEXT 型の最大長かそれに順ずる長さとしたいと思います。

文書番号とURL以外がNULL可なのは、浅い考えがあってのことです。

今のところサーバーへの接続とソースのダウンロードはスレッドでやるつもりです。このときスレッドがどの文書番号を取得しに行くか、をスレッドの起動側で決めようかと。このときレスポンスコードをダウンロードの進捗ステータスみたいに使おうと。

なので、

  1. レスポンスコードが NULL のままの一番小さい文書番号をダウンロード対象とする。見つからなければ文書番号の最大値+1 をダウンロード対象とする。
  2. 文書番号・URL だけのレコードを作る。
  3. スレッドにその文書番号を渡し、レスポンスコードを 0 にする(予約する)。
  4. スレッドはその文書番号(とURL)でダウンロードする。
  5. ダウンロードが終われば、文書番号をキーに残りの項目を埋める。
    サーバーのレスポンスが「200」以外ならサーバーのレスポンスコード以外は NULL のままで。

このままだと、アプリケーションが強制終了などでダウンロードが完了しなかった場合に、レスポンスコードが 0 のままダウンロードもされてないごみデータが残ってしまうので、アプリケーション起動時にでもごみデータのクリア(レスポンスコード 0 データの一括削除)が要りそうですが、基本的にはこれが全てです。

そういうテーブルの CREATE 文TOP

まずは悲しい結果から。

次はうれしい結果

まさか ADO で Catalog.Tables['表名'].Columns['列名'].Properties['Jet OLEDB:Allow Zero Length'] = True にするのか? オフラインでやってるとこういうときに調べられないのがつらいです。

それはそれとして、CREATE 文はこんな感じです。

CREATE TABLE MSKBINDEX (
    KBID TEXT(6) NOT NULL,
    URL TEXT(50) NOT NULL,
    RESCODE TEXT(3),
    TITLE MEMO,
    DESCRIPTION MEMO,
    KEYWORDS MEMO,
    KBPARENTS MEMO,
    GETDATE TEXT(14),
    CONSTRAINT PK_MSKBINDEX PRIMARY KEY (KBID)
);

仕方が無いので、これでテーブルを作った後に、指定したテーブルの文字列型フィールドの Nullable=True のものについては Jet OLEDB:Allow Zero Length=True にするような処理を通すか。邪魔くさいです。

Delphiでmdbを操作 - 003 の方で処理を作成してきました。うまく動いているようです。

長くなってきたので、このページはココまで。

EOFTOP