Greasemonkey/Tampermonkey Edit

table -> csv Edit

他人のページに勝手に「このテーブルをダウンロード」ボタンを付けて、ダウンロードできるようにする工夫。Greasemonkey (Tampermonkey)を初めて知ったときは、「なるほど。こんなことができるんだ」と大いに感激したものだ。以下のスクリプトを使うと、他人のページのテーブルの下部にダウンロードボタンが現れる。押すと、テーブルの内容がCSVファイルでダウンロードされる。

myJCBwithcsvbutton2.jpg

自分のページは自分だけが改変できるし、他人のページはその管理者だけが改変できる、というのは必ずしも正しくない。勝手にボタンを付けることは可能だ(他にもいろいろできる)。ハッキング(不正侵入)とは違う。相手方がこちらのブラウザーに送り届けた画面情報を、こちらのブラウザーの側で変更しているだけだ。相手のサーバー上にあるデータを変更しているわけではないし、相手のサーバーに特別なデータを出させているわけでもない。通常は、相手は、こちらが改変していることを感知できない。(ただし、相手の著作権や商標権の侵害にはなり得るので、改変した画面の二次利用には注意。)

ネットに同等品は幾つかあるが、JCBのサイトでworkしなかったので作った。jQueryを使用。jQueryはGreasemonkey/Tampermonkeyで動く動かないという話があるようだが、少なくとも現時点では最新のChromeブラウザ(Windows)と最新のjQueryの組合せで特に問題ないようだ。2018年 5月

次のライブラリを使用。GitHub - OmbraDiFenice/table2csv: A simple jQuery plugin to convert HTML tables to CSV

// ==UserScript==
// @name        <table> to csv
// @namespace   https://over.6pb.info/
// @include     https://club.dccard.co.jp/*
// @include     https://my.jcb.co.jp/iss-pc/member/*
// @require     https://over.6pb.info/lib/jquery.min.js
// @require     https://over.6pb.info/lib/table2csv.js
// @grant       none
// ==/UserScript==

(function() {
$('table').each(function() {
	var $table = $(this);
	var $button = $("<button type='button'>");
	$button.text("Exp");
	$button.insertAfter($table);

	$button.click(function() {
		$table.table2csv(); //単にダウンロードするならこれだけ
	});
});
})();
  • 実際にJCBの明細(速報)を扱うにはexcludeRows: 'thead tr'を加えた方が良い。
  • この文章を書いた翌日、DCカードの明細(速報)画面に仕様変更があり、上記のコードでは正常にテーブルを取れなくなった。個別のコードが必要。

  • こんなに短いならbookmarkletでもできそうだが、bookmarkletだと別スクリプトや外部ファイル(ライブラリなど)をincludeできないはず。

Greasemonkey/Tampermonkeyで対応できないもの Edit

yet another JavaScript入門 Edit

仕事でJavaScriptを始めた人を除き、何がJavaScriptを使うきっかけになるのだろうか。私はChromeブラウザとJavaScriptを使うと、画面上に書いてある情報を抜き出すのが楽になる(手作業で一つ一つコピペしなくて済む)ことだった。

現在表示しているページからURL一覧を抜き出す Edit

例えば、外国為替情報 : 三井住友銀行のページから、「今月」のPDF(毎日アップされる)の、URL一覧を取得したいとする。(2018年5月現在。将来、先方の仕様が変更されたら動かない。)

現在表示しているページについて何か調べたい・操作したいときは、ChromeブラウザのDeveloper Toolsを開き(F12キーを押す)、Consoleタブにスクリプトを記入・実行する。スクリプトは、一行ずつConsoleに書くのではなく、メモ帳に書いてから、全部の行の分をまとめてConsoleにペーストする。

  • 現在表示しているページの特定の領域(CSSで指定)内のリンクを一覧する
    var elms = document.querySelectorAll('#tabbox1 div li a');
    for (var i=0; i <elms.length; i++) {
    	console.log(elms[i].href);
    }
    
  • 参考: 領域をXPathで指定する
    var elms = document.evaluate('//*[@id="tabbox1"]/div//li/a', document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null );
    for (var i=0; i <elms.snapshotLength; i++) {
    	console.log(elms.snapshotItem(i).href);
    }
    
  • 結果を、別窓に出力する
    var elms = document.querySelectorAll('#tabbox1 div li a');
    var w = window.open('about:blank');
    w.document.open();
    w.document.write('<textarea id="export" rows="40" cols="100">');
    for (var i=0; i <elms.length; i++) {
    	w.document.write(elms[i].href + "\n");
    }
    w.document.write('</textarea>');
    
  • 結果を、ファイルに保存する
    var elms = document.querySelectorAll('#tabbox1 div li a');
    var text = '';
    for (var i=0; i <elms.length; i++) {
    	text += elms[i].href + "\n";
    }
    var blob = new Blob([text], {type: "text/plain"});
    var a = document.createElement("a");
    a.href = URL.createObjectURL(blob);
    a.target = '_blank';
    a.download = 'url.txt';
    a.click();
    

手作業でやるより簡単で、間違いがない。

表の加工 Edit

Google Sheets/Google スプレッドシートが便利だ。

1次元から2次元へ Edit

データの取得は左側のように1次元のことが多いだろう。内容を把握するには右側のような2次元にするのが普通だ(クロス集計)。Google Sheetsを使うと簡単だ。「=B3」みたいに個々ベタに埋め込むとメンテが困難を極める。

googlesheetswinsat.jpg

F2=TRANSPOSE(UNIQUE(A2:A))
E2=UNIQUE(C2:C)
F2=FILTER($B:$B,$E2=$C:$C,F$1=$A:$A)
G2=FILTER($B:$B,$E2=$C:$C,G$1=$A:$A)
F3=FILTER($B:$B,$E3=$C:$C,F$1=$A:$A)
  • F2だけなら「=FILTER(B:B,E2=C:C,F1=A:A)」でよい。これを他のセルにコピーするため絶対番地にする。

表(Excelなど)から特定の列と行を抽出する Edit

やり方は色々あるが,私がよく使うのはfilter関数。(Google Sheets/Google スプレッドシートのもの。Excelにはない。)軽くて,条件設定も柔軟。例えば,シート1の列Bと列D,列FからG,以上から(このように飛び飛びでもよい),列Aの値が4で,かつ列Cの値が"車"の行だけを取り出すなら

=filter({'シート1'!b:b,'シート1'!d:d,'シート1'!f:g},'シート1'!a:a=4,'シート1'!c:c="車")

UNIXのパイプのようにそのままsortやuniqueをかけられるのも重宝する。

vlookupに2つ以上の条件を付ける Edit

vlookupだと、条件を一つしか付けられないが、filterなら幾つでも付けられる。これはExcelにはない大きな利点だ。


ただ、filterはarrayformulaと組みにできない不利もある。複数条件のvlookupをarrayformulaと組みにするため、複数条件のvlookupを1条件に書き直すアプローチもある。

例えば、求める値がC列、検索語と検索範囲のペアが、A列に対しD列、B列に対しE列(2条件)のとき、つまり

=filter(c:c,a2=d:d,b2=e:e)

のとき(行2の式)、A列とB列を連結して1列にし、同じくD列とE列も連結して1列にすることで、1条件に書き換えることができる。

A列とB列を連結して1列にa2:a&b2:b
D列とE列を連結して1列にd2:d&e2:e
検索語d2:d&e2:e
検索範囲{a2:a&b2:b,c2:c}この2列目がC列
検索範囲を配列に変換arrayformula({a2:a&b2:b,c2:c})
=arrayformula(vlookup(d2:d&e2:e,arrayformula({a2:a&b2:b,c2:c}),2,false))

しかしかなり遅いようだ。

他のファイルから抽出する Edit

これもやり方は色々あるが,私が使うのはimportrangeとquery関数。これに対しimportrangeとfilter関数でも同じことができ、この方がとっつきやすいが、filter関数を使って別ファイルから取り込むには何回もimportrangeを書く必要があり、記述がごちゃごちゃする。(後日、変更があったとき、直すのに手間が増える。)

  • なお、「ファイル」は正確には「spreadsheet」。spreadsheetの中の個別のシートが「worksheet」または「sheet」。

例えば、同じファイルのシートs1から{C5:C,F5:F,T5:U}の列を,N5:N>=5の行に限り,抜き出すなら:

=filter({'s1'!C5:C,'s1'!F5:F,'s1'!T5:U},'s1'!N5:N>=5)

これと同じことを別のファイルに対して行うには:

=query(importrange("https://docs.google.com/...","C5:U"),"select Col1, Col4, Col18, Col19 where Col12>=5")
  • 記法の違い:
    • importrangeは読み込み範囲を飛び飛びで指定できないので,一旦広く取り込む。
    • 取り込んだ列に順にCol1,...の番地が付く。Cは必ず大文字。
    • where以下に行の条件を書く。

親ファイルで作業シートを作り,それを別ファイルでimportしても同じことはできる。2段階で処理する。それならfilterだけで抽出できるので,query関数を新たに覚える必要がない。しかし200万セル制限があるので,作業シートを作る(特に親ファイルで)のはなるべく避けたい。

importrangeするとgetLastRow()はworkしない Edit

シートの最終行を知りたいとき、対象列がIMPORTRANGEで読み込んだ列の場合、getLastRow() はworkしないようだ。998になる。自力で地道に中身を検査する必要がある。

  var col = 1; // 調べる列
  var lastrow = 0;
  var cells = sheet.getDataRange().getValues(); // 実際のシートの大きさ(最終行)を調べる作業変数
  for (var i = 0; i < cells.length; i++) {
    if (!cells[i][col-1].match(/\w/)) { //配列添字なのでcol-1
      lastrow = i; // 現在のcells[i]は空行を指しているので、cells[i-1]が最終行になり、最終行の行番号はi。
      break; //Perlのlastはbreak。continueはnext。
    }
  }

queryで空のセルが出る Edit

「109.69」と「=(P707+Q707)/2」など、ベタに値を入れたセルと、計算式で値を作ったセルとが混在していると、queryで取り込んだとき、値が空になることがある。query関数は、列の型が数値か文字列かを自動判定しており、その際、どちらが多いかで判定するそうだ。列が数値と判定されると、文字列はblankに変換される。Cf. GoogleスプレッドシートのQuery関数で結果が空になる謎仕様と回避策。間にfilterがあっても、違いは引き継がれる模様。

COUNT in ARRAYFORMULA Edit

  • ARRAYFORMULAとcountifは組合せ可能。countaは不可。
  • countifは(ARRAYFORMULAと組む際)「(検索範囲,条件範囲)」の順。
    =UNIQUE(A2:A)=ARRAYFORMULA(countif(A1:A,B2:B14))
    EUREUR20
    EURHKD32
    EURMYR43
    EURSGD15
    EURTWD41
    EURUSD316
    EURCAD2
    EURCNY18
    HKDKRW7
    HKDGBP8
    HKDHRK7
    MYRTHB1
    MYRTRY1
    MYR
    SGD
    以下続

データ変換 Edit

TSV Edit

  • 段落区切りデータや,スペース文字で桁揃えして表のように整形されたデータを,TSVに変換する。その他,行と列の入替え,PukiWiki表への変換などもできる。
  • 例1
    • 入力(データを作る際は段落区切りの方が楽である。TSVへの加工は機械にやらせればよい。)
      銘柄
      コード
      
      エーザイ
      <4523.T>
      
      小野薬品工業
      <4528.OS>
      
      東燃ゼネラル石油
      <5012.T>
      
    • 出力1(TSV)
      銘柄	エーザイ	小野薬品工業	東燃ゼネラル石油
      コード	<4523.T>	<4528.OS>	<5012.T>
      
    • 出力2(行列入替え)
      銘柄	コード
      エーザイ	<4523.T>
      小野薬品工業	<4528.OS>
      東燃ゼネラル石油	<5012.T>
      
  • 例2(スペース文字で桁揃えして表のように整形されたデータ)
    • 入力(人間には意味が取れるが,エクセルには入力できない。)
       1)エーザイ <4523.T>           5.11%           884,659          17
       2)小野薬品工業 <4528.OS>       5.03%           434,449          11
       3)東燃ゼネラル石油 <5012.T>    4.88%           448,755           5
      
    • 出力(TSV)
      1)エーザイ	<4523.T>	5.11%	884,659	17
      2)小野薬品工業	<4528.OS>	5.03%	434,449	11
      3)東燃ゼネラル石油	<5012.T>	4.88%	448,755	5
      
      • コラム数を指定して変換することもできるし,自動認識もできる。場合場合だが,自動の方がうまく行くことが多いようだ(アルゴリズムが違う。)。

ローマ字 Edit

長音 Edit

Unicode code pointcharacterUTF-8 encoding (hex)Unicode character name
U+0100Āc4 80LATIN CA­PI­TAL LET­TER A WITH MACRON
U+0101āc4 81LATIN SMALL LET­TER A WITH MACRON
U+0112Ēc4 92LATIN CA­PI­TAL LET­TER E WITH MACRON
U+0113ēc4 93LATIN SMALL LET­TER E WITH MACRON
U+012AĪc4 aaLATIN CA­PI­TAL LET­TER I WITH MACRON
U+012Bīc4 abLATIN SMALL LET­TER I WITH MACRON
U+014CŌc5 8cLATIN CA­PI­TAL LET­TER O WITH MACRON
U+014Dōc5 8dLATIN SMALL LET­TER O WITH MACRON
U+016AŪc5 aaLATIN CA­PI­TAL LET­TER U WITH MACRON
U+016Būc5 abLATIN SMALL LET­TER U WITH MACRON

添付ファイル: filegooglesheetswinsat.jpg [詳細] filemyJCBwithcsvbutton2.jpg [詳細]

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2018-06-24 (日) 09:35:25 (27d)