PowerShellでbit目次を検索したい
2023年12月、PowerShellでbit目次を検索するスクリプトを作成しました。
先日、コンピュータ・サイエンス誌『bit』の総合目次を作成して便利に使っています。索引(単語)にテクニカルターム(キーワード)の索引があるのですが、ここにないキーワードで記事を探すのがちょっと面倒です。
PowerShellはWEBスクレイピングが簡単にできるので、PowerShellスクリプトでbit総合目次を検索してみようと挑戦しました。
bit総合目次を検索
bit総合目次は、1月号~12月号をひとつのHTML文書「bit_yyyy.html」として年ごとに目次を掲載しています。
その中は、下記のような構成となっています。
タグ | 内容 |
---|---|
<h2> | YYYY-MM 形式で年月 |
<dt> | タイトル |
<dd> | 内容など |
HTML文書から<h2>タグ、<dt>タグ、<dd>タグを抽出したテキストからキーワードを検索すれば良いわけです。
「Invoke-WebRequest」で指定したWEBページにアクセスして、bit目次のHTMLを取得します。
そして、「getElementsByTagName()」で<h2>タグ、<dt>タグ、<dd>タグを抽出することを考えました。
しかし、個別に抽出するのでタグの対応関係がとれなくなってしまいます。
<h2>タグ、または、<dt>タグ、または、<dd>タグを一度に抽出することはできないのです。
どのような手法でこれを実現するか少し悩みました。
これは、いつか来た道だな。昔もこんなことを考えたことがあるなと思いブログを見直しました。
「JavascriptによるDOM操作で目次を生成する方法」で同じようなことをやっているではないですか。
クラス名で抽出する方法があるので、抽出したいタグに同じクラス名を追加すれば良いのです。
そして、getElementsByClassName()を使って対象タグを抽出します。
PowerShellスクリプト
bit目次を検索するPowerShellスクリプトは次のようになります。
#
### bit 総合目次 キーワード検索
#
#
function search_key($url ,$key) {
# == Get HTML
try {
$response = Invoke-WebRequest -Uri $url -TimeoutSec 5
} catch {
Write-Host "Error ",$url
return
}
$oHtml = $response.ParsedHtml
set_class $oHtml "h2" "search"
set_class $oHtml "dt" "search"
set_class $oHtml "dd" "search"
#
$cls_elms = $oHtml.getElementsByClassName("search")
foreach($cls_elm in $cls_elms) {
switch ($cls_elm.tagName) {
({$_ -eq "h2"}) { $yyyymm = $cls_elm.innerText.Substring(0,7) }
({$_ -eq "dt"}) { $dt_text = $cls_elm.innerText.Replace("`n", "") }
({$_ -eq "dd"}) { $dd_text = $cls_elm.innerText.Replace("`n", "") }
}
if ($cls_elm.tagName -eq "dd") {
$chk = check_key $dt_text+" "+$dd_text $key
if ($chk -gt 0) {
Write-Host $yyyymm $dt_text $dd_text
}
}
}
}
# $Elmの タグ$Tag に クラス$Class を追加
function set_class($Elm ,$Tag ,$Class) {
$tag_elms = $Elm.getElementsByTagName($Tag)
foreach($tag_elm in $tag_elms) {
$oClass = $tag_elm.ClassName
$tag_elm.ClassName = $Class+" "+$oClass
}
}
# テキスト$textからキーワード$keyを探す 戻り値=1(有)/0(無)
function check_key($text ,$key) {
$text = " "+$text+" "
$rc_chk = 0
if ($key -match '\d+') {
if ($text -match "[^\d]$key[^\d]") {
$rc_chk = 1
}
} else {
if ($text -match "[^A-Z]$key[^A-Z]") {
$rc_chk = 1
}
}
return($rc_chk)
}
#
### Main
#
# $debugPreference = "Continue"
#
$yyyy_s = 1974
$yyyy_e = 1992
$url_base = "http://my-web-site.iobb.net/~yuki/bit/"
#
Write-Host "bit 総合目次 キーワード検索 Start!"
$key = Read-Host "Please input KEY word " # キーワード入力
Write-Host "`r`n",$key
#
for ($yyyy = $yyyy_s; $yyyy -le $yyyy_e; $yyyy++) {
$url = $url_base+"bit_"+$yyyy+".html"
# Write-Debug $yyyy
search_key $url $key
}
関数 search_key
関数 search_keyは、指定したWEBページをスクレイピングして検索キーワードに該当するbit誌の年月、タイトル、内容を表示します。
引数 | 説明 |
---|---|
$url | WEBページのURL |
$key | 検索キーワード |
戻り値 | 無し |
- $urlで指定したWEBページにアクセスして、$oHtmlにHTML情報を読み込みます。
- <h2> タグに class=”search” を追記します。
- <dt> タグに class=”search” を追記します。
- <dd> タグに class=”search” を追記します。
- getElementsByClassName()でクラス名”search”を順次アクセスします。
- タグ種別により、HTML情報を取得します。
- <h2> タグなら、先頭7文字の年月を$yyyymmに格納
- <dt> タグなら、タイトルを$dt_textに格納
- <dd> タグなら、内容などを$dd_textに格納
- <dd> タグを検出したとき、関数 check_keyで$dt_textと$dd_textに検索キーワードに該当するかチェックします。
該当した場合、「$yyyymm $dt_text $dd_text」を出力します。
関数 set_class
関数 set_classは、HTMLページの指定したタグにクラス名を追記します。
引数 | 説明 |
---|---|
$Elm | HTMLページ |
$Tag | HTMLタグ |
$Class | 追記するクラス名 |
戻り値 | 無し |
getElementsByTagName()で指定したタグを順次アクセスして、クラス名を追記します。
例えば、<h2>タグにクラス”search”を追記する場合は、「<h2>1974-01 (通巻59号)</h2>」のHTMLは「<h2 class=”search”>1974-01 (通巻59号)</h2>」となります。
関数 check_key
関数 check_keyは、テキスト内を検索キーワードで検索して、該当の有無を返します。
引数 | 説明 |
---|---|
$text | 検索するテキスト |
$key | 検索キーワード |
戻り値 | 1 : 有り / 0 : 無し |
- 検索するテキスト$textの前後にスペースを追加します。
- 検索キーワード$keyが数字のとき、”[^\d]$key[^\d]”にマッチするか調べます。
これは、検索キーワードの前後が数字以外ということを示しています。
その結果、キーワード「6800」は、「・・・MC68000・・・」というテキストにはマッチしません。 - 検索キーワード$keyが数字以外のとき、”[^A-Z]$key[^A-Z]”にマッチするか調べます。
これは、検索キーワードの前後が英字以外ということを示しています。
その結果、キーワード「MAC」は、「・・・EMACS・・・」というテキストにはマッチしません。
なお、-match演算子は、英字の小文字と大文字を区別せずに比較しますので、小文字でも大文字でもマッチします。
メイン
- 検索対象の年を定義します。 $yyyy_s=1974 、$yyyy_e=1992
- 検索キーワード$keyを入力します。
- 年$yyyyを$yyyy_s~$yyyy_eの間繰り返します。
- アクセスするbit総合目次のURLを作ります。
- 関数 search_keyで指定したURLにアクセスして、検索キーワードに該当したらbit誌情報を出力します。
bit目次検索の実行
PowerShellスクリプトを実行してみます。
キーワードとして「vax」を入力します。少し時間がかかりますが、以下のように指定したキーワードに該当するbit誌の情報を表示します。
PS E:\ps> .\bit_search.ps1
bit 総合目次 キーワード検索 Start!
Please input KEY word : vax
vax
1982-07 32ビット・スーパーミニコンのOS [02] VAX/VMS 今野肇
1985-01 DEC,メインフレーム市場に進出 ――VAXファミリーの最上位機種発表 栗田昭平
1986-12 Common Lispアラカルト [04] VAX LISP 川合進
1988-07 DECがVAXコンピュータ9機種を一挙に発表 栗田昭平
1990-01 タンデムのCyclone,DECのVAX900発表で熾烈化するメインフレーム市場 栗田昭平
PS E:\ps>
便利なbit目次検索
bit総合目次は、bit誌の目次を閲覧できるので便利です。
それに加えて、このPowerShellスクリプトは、任意のキーワードで検索できるので、さらに便利になります。
みなさん、活用してください。