Puppeteer Edit

  • パズル認証や2段階認証は、正面から突破するより、1回は手動で補助してログインし、cookieをやりとりすれば、たいていはしばらく追加認証を回避できる。(毎回、追加認証を課すサイトには通用しない。)cookieはPuppeteerのコードで明示的に取得・保存する必要がある。headlessブラウザに(自動的に)保存されるものは助けにならないようだ。(サイトによって違うかも。)
  • (毎回の)パズル認証を(簡単に)回避できたサイト:
    • 三井住友カード
  • headlessだとうまく巡回できない(headlessを無効にすれば順調な)サイトもある。例えば、三井住友カードはheadlessだといまのところ巡回に成功していない。headlessで動かないと、VPSのCentOSで動かすのが面倒だ(普通、クラウドのCentOSにX Windowは入れない。)。cronで定期的に実行するには、VPSが望ましい。次善の策として、新たに、自宅サーバーにGNOME Desktop付きのCentOS 7を入れた。(CentOS 6ではheadless Chromeは動かないようだ。)これでいまのところ三井住友カードも自動巡回できている。
  • cronで動かすならtry-catchを書かないと、時間切れなど何か予期せぬことが起きる度にメモリに貯まっていく。自動終了しない。

Error: Node is either not visible or not an HTMLElement Edit

単に、指定したセレクタが複数あるだけかも。例えばinput[name="password"]が2つあるときに、await page.typeやawait page.focusなどは上記エラーが出る(ことがある)。そういうときはclass: ElementHandleでオブジェクトのリストを取得し、リストの番号で目的のオブジェクトを操作すればよい。例えば2つ目を扱いたいなら、

let items = await page.$$('input[name="password"]');
items[1].click();

pageクラスと書式が同じものもあれば違うものもある。例えばelementHandle.typeは、セレクタを引数に取らない。puppeteer/api.md at master · GoogleChrome/puppeteer · GitHub

Node.js Edit

cheerio Edit

  • 不要な要素をcheerioのメソッドで取り除く例:
    //table内にあるtableを削除
    $('table table').remove();
    
    //8列目が存在しない行を削除。全ての行の内、8列目が不存在の行を全て削除。
    $('tr:not(:has(td:nth-child(8)))').remove();
    
    //8列目が空の全ての行を削除。全ての行の内、8列目が空の行を全て削除。
    // [注意] 8列目が存在しないと効果なし。8列目がない行を削除という意味(存否判断)では使えない。
    $('tr:has(td:nth-child(8):empty)').remove();
    
    // td.blue以外の全てのtdを削除。全てのtdを、td.blueを除き、削除。
    $('td:not(td.blue)').remove();
    
    //一行目(見出し行)を削除
    $('tr:nth-child(1)').remove();
    

文字コード Edit

Perl Edit

  • (先ず簡単な方から。)URLエンコードされている文字列を取り扱う(例えばApacheのログファイルの解析)には、単にURLデコードしただけでは駄目。URLデコード後、直ちにPerlの内部表現に「デコード」する。さもないと他の文字列と整合性がとれなくなる。例えば、一般に全ての文字列は、出力の際、エンコードする。URLデコードした文字列について、デコードされる前にエンコードされると二重エンコードになり、文字化けする。
  • (これは意外だった。)URLエンコードされている文字列を含むファイル(例えばApacheのログファイル)を読み取るとき、「open(IN, '<:utf8'...」や「use open IN => ":utf8";」でデコードすると、(その後、Encode::decode_utf8しようがしまいが)スクリプトのリテラル(use utf8;前提)と(正規表現や文字列比較演算子で)マッチしなくなる。リテラルによる正規表現や文字列比較演算子が使えない。文字化けはないので、上記より気付きにくい。use open INやbinmode INを便利なプラグマとして、雛形として使っていることは少なくないのでは。
  • 「<:utf8」ではなく「<:encoding(UTF-8)」でも変わらず。「:utf8 は、さらなるチェックなしにデータが UTF-8 としてマークしますが、 :encoding(UTF-8) はデータが実際に有効な UTF-8 かどうかをチェックします。 」perlfunc - Perl 組み込み関数 - perldoc.jp
  • 「binmode IN, ":utf8";」でも同様に駄目になる。
  • 下記のコードで試せる。
    use utf8;
    use strict;
    use warnings;
    use Encode;
    use Devel::Peek;
    
    my $str = '%E6%97%85%E8%A1%8C'; # 旅行
    my $file = 'test.bin';
    my $str_decoded = decode_utf8( &urldecode ($str));
    print "basis:$str_decoded\n";
    Devel::Peek::Dump($str_decoded);
    print qq(\n);
    
    open (OUT, ">$file");
    binmode OUT;
    print OUT $str;
    close OUT;
    
    # -------------------------------------------------------
    # デコードせず読み込み
    open (IN, "<$file");
    #binmode IN;
    my $str1_from_file = <IN>;
    close IN;
    &compare($str,$str1_from_file);
    print qq(\n);
    
    
    # -------------------------------------------------------
    # デコードして読み込み
    open(IN, '<:utf8', $file);
    #binmode IN;
    my $str2_from_file = <IN>;
    close IN;
    &compare($str,$str2_from_file);
    
    # -------------------------------------------------------
    # URLデコード
    sub urldecode{
    	my $uri = shift(@_);
    	$uri =~ tr/+/ /;
    	$uri =~ s/%([0-9A-Fa-f][0-9A-Fa-f])/pack('H2', $1)/eg;
    	return $uri;
    }
    # 比較
    sub compare{
    	my @sample = @_;
    	# URLデコード前
    	&sameornot(@sample);
    
    	# URLデコード
    	my @sample_urldecoded = map {urldecode($_)} @sample;
    	&sameornot(@sample_urldecoded);
    
    	# 内部表現へのデコード
    	my @sample_decoded = map {decode_utf8($_)} @sample_urldecoded;
    	&sameornot(@sample_decoded);
    
    	sub sameornot {
    		$_[0] eq $_[1] ? print "same\n" : print "differnet\n";
    	}
    	# 正規表現
    	if ($sample_decoded[1] =~ /旅行/) {
    		print "1) regex works\n";
    	}
    	# 念のためdecode_utf8前で試す
    	if ($sample_urldecoded[1] =~ /旅行/) {
    		print "2) regex works\n";
    	}
    
    	print "compared:$sample_decoded[1]\n";
    	print "before decode_utf8\n";
    	Devel::Peek::Dump($sample_urldecoded[1]);
    	print "after decode_utf8\n";
    	Devel::Peek::Dump($sample_decoded[1]);
    }
    
  • 途中「Wide character in print」と言われるが、それが正しい。むしろ3番目の出力箇所で出ないことの方が意外だった。
  • このような結果になる。
    $ perl test2.pl
    Wide character in print at test2.pl line 12.
    basis:旅行
    SV = PV(0x1018ee0) at 0x1037980
      REFCNT = 1
      FLAGS = (PADMY,POK,pPOK,UTF8)
      PV = 0x110a940 "\346\227\205\350\241\214"\0 [UTF8 "\x{65c5}\x{884c}"]
      CUR = 6
      LEN = 16
    
    same
    same
    same
    1) regex works
    Wide character in print at test2.pl line 73.
    compared:旅行
    before decode_utf8
    SV = PVMG(0x10d7a20) at 0x1037188
      REFCNT = 1
      FLAGS = (POK,pPOK)
      IV = 0
      NV = 0
      PV = 0x1122220 "\346\227\205\350\241\214"\0
      CUR = 6
      LEN = 16
    after decode_utf8
    SV = PV(0x1019740) at 0x1037218
      REFCNT = 1
      FLAGS = (POK,pPOK,UTF8)
      PV = 0x1097030 "\346\227\205\350\241\214"\0 [UTF8 "\x{65c5}\x{884c}"]
      CUR = 6
      LEN = 16
    
    same
    same
    differnet
    compared:旅行
    before decode_utf8
    SV = PVMG(0x10d7a50) at 0x10370e0
      REFCNT = 1
      FLAGS = (POK,pPOK,UTF8)
      IV = 0
      NV = 0
      PV = 0x110acb0 "\303\246\302\227\302\205\303\250\302\241\302\214"\0 [UTF8 "\x{e6}\x{97}\x{85}\x{e8}\x{a1}\x{8c}"]
      CUR = 12
      LEN = 16
    after decode_utf8
    SV = PVMG(0x10d7960) at 0x10371e8
      REFCNT = 1
      FLAGS = (POK,pPOK,UTF8)
      IV = 0
      NV = 0
      PV = 0x1030240 "\303\246\302\227\302\205\303\250\302\241\302\214"\0 [UTF8 "\x{e6}\x{97}\x{85}\x{e8}\x{a1}\x{8c}"]
      CUR = 12
      LEN = 16
    

メモ Edit

  • printfの記法は気が滅入る。表で値を与えてみた。
  • 普通の書き方

    printf "<tr><td $tdclr_host>%s<td>%s<td>%s<td>%.60s<td $tdclr_stts>%s<td>%.50s</tr>\n",substr($host,-30),"$mon $date",$clock,$uri,$stts,$ua;

  • 表で
    	my @printform = split /\n/, <<END;
    <tr>		
    <td $tdclr_host>%s	@{[substr($host,-30)]}	%h host, 式展開の記法
    <td>%s			$mon $date		日付
    <td>%s			$clock			時刻
    <td>%.60s		$uri			%rからページ名切り出し
    <td $tdclr_stts>%s	$stts			status code
    <td>%.50s		$ua			User-Agent
    </tr>		
    END
    	for (@printform) {
    		@_ = split /\t+/;
    		if (defined $_[1]) {
    			printf qq($_[0]),$_[1];
    		} else {
    			print qq($_[0]);
    		}
    	}
    
  • CGIプログラムをroot名義で動かしたいことがある。sudoを使えば可能。当初誤解していたのだが、sudoersに適切な記載をすれば、その条件で、自動的に実行ユーザーが変わるのだと思っていた。(mod_rewriteのように。)正しくはsudoコマンドが必要。sudoコマンドで、対象コマンド等を呼んで初めて実行ユーザーが変わる。
    • CGIスクリプトそれ自体をsudoで呼び出し実行する(CGIとして)ことは非現実的なので、CGIスクリプトの中で本命のスクリプトないしコマンドをsudoで呼び出すことになる。sudoersに登録する対象コマンド等は、その本命スクリプトないしコマンドになる。ただし、/bin/cpや/sbin/iptablesのようなコマンドを登録するのは影響範囲が広すぎ、危険だ。反面、スクリプトを守るのが要になるので、「chown root.root スクリプト」しておくとよい。
  • 理由不明の文字化けで困っていたが、PerlのCGIモジュールを更新したら直った。同じコードが別環境で問題なかったので気付いた。CGI::escapeHTML()。2018年 4月26日
    Package namespace         installed    latest  in CPAN file
    CGI                            3.63      4.38  LEEJO/CGI-4.38.tar.gz
    

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2018-06-14 (木) 20:15:40 (155d)