PHPがメインの経験者が、Pythonを始めて４日目の話（subprocess）色々

#はじめに
Pythonを始めて３日目の話の続きにそのまま４日目も書こうかと思いましたが、かなり長くなりそうなので４日目の話を新たに用意して移動する事にしました。今回は PHP の exec を Python の subprocess で利用する話がメインになります。PythonをLinuxの機能の一部として使うような用途では参考になるかと思います。バッチ処理に近いですが、それを Python で実行するメリットもあるでしょう。
######話が飛ぶ理由のお断り
しっかりプログラミング言語を勉強（研究）されている方は体系的に整理した内容を書いておられます。皆さん素晴らしいと思います。私の場合は道具としてコンピュータやプログラム言語を使っているという立場ですので、その都度必要になった内容を調べて形にしている為に一般的な流れとは違ってしまいます。「のような事」を始めると必要になる内容になってしまいますので、参考になる部分だけ拾ってお使い頂ければと思います。
######１．ファイルのフォーマットを調べる（拡張子が無い Word Excel PowerPoint PDF の識別）
WEBから落としたファイルのフォーマットを調べる必要があるので、PHPでは以下を実行して戻り値を調べてファイルの拡張子を付けていました。ファイルの拡張子を見て何のファイルかを判断しているプログラムが未だに多いので、こちらで行う必要があります。将来は不要になりそうですが、現在はまだ必要です。

``` file.php
exec('file -i -b data/default.xlsx', $out, $ret);
echo $out[0];
// 戻り値は以下となります
// application/vnd.ms-excel; charset=binary
```

``` file.py

import subprocess
args = ['file','-i','-b','default.xlsx']
proc = subprocess.run(args,stdout = subprocess.PIPE, stderr = subprocess.PIPE)
string = proc.stdout.decode("utf8")
none = 'no'
if string.find('excel') < 0:
	print(none)
elif string.find('excel') > 0:
	print(string)
# 戻り値は以下となります
# application/vnd.ms-excel; charset=binary
```
PHPもPythonも当然のように同じ戻り値です。
######２．PDFをテキストファイルに変換する
これも subprocess でやろうとしていたのですが、pdftotext のモジュールを Linux に組み込んで使う方法が見つかり、さてどうしたものか悩みだしました。その方法が次のリンクにあります。[pdftotext で PDF をテキストに変換](https://qiita.com/ekzemplaro/items/0ac1bd99a5565067763b) この記事といいますか、コードをざっと見て複雑になるな？と思ったら表示画面まで用意してくれておられるので、そこは後で参考にさせていただくとして単純に subprocess でやってみます。相変わらず PHP のコードと比較してみましょう。

``` pdftotext.php

$command ="pdftotext -layout -nopgbrk data/*.pdf";
shell_exec($command);
```

``` pdftotext.py

import subprocess
args = ['pdftotext','-layout','-nopgbrk','data/sjd23d_mn.pdf'] # (ファイル名を指定しないと変換しない)
args = ['pdftotext','-layout','-nopgbrk',"data/*.pdf"] # （ダブルコーテーションでアスタリクスで指定出来る）
proc = subprocess.run(args)
```
すぐには動かず少し変えて動くようにはなりましたが、ファイル名をアスタリクスで拾っての変換が最初は出来ませんでした。この件はコードに書きましたがダブルコーテーションでファイル名の指定を囲むとアスタリクスで指定出来るようになります。subprocess のパラメータを指定する形で書いてしまったので駄目だった訳ですが、この違いは重要ですね。（これは私にとって）

######３．PDFを画像に変換する

``` pdftoppm.php

$command ="pdftoppm -jpeg data/*.pdf data/";
shell_exec($command);
```

``` pdftoppm.py

import subprocess
args = ['pdftoppm','-jpeg',"data/*.pdf","data/"]
args = ['pdftoppm','-jpeg','data/sjd23d_mn.pdf','data/']
proc = subprocess.run(args)
```
結果はPDFを画像に変換する場合はファイル名を指定しないと駄目なようです。PHPと若干動作が違いますね。恐らく pdftoppm も Python にインポートして使う方法があるのでしょうが、それは別の機会にします。
######４．圧縮ファイルの解凍（日本語ファイル名の文字化け対処）

``` unar.php

$command = 'unar -f data/data/selenium-master.zip -D -o data';
shell_exec($command);
```

``` unar.py

import subprocess
args = ['unar','-f','data/selenium-master.zip','-D','-o','data/']
# パスワードが必要な場合
args = ['unar','-f','-p','passw','data/selenium-master.zip','-D','-o','data/']
proc = subprocess.run(args)
```
圧縮ファイルの解凍はこれで良さそうです。
######５．selenium
これは簡単には出来そうにないので少し先にします。
######６．フォルダやファイルの一括削除
これは unar で解凍したファイルの痕跡を消すためにどうしても必要でした。まず PHP でどうやっているかを示します。これを Python でもやる訳ですが、色々と方法がありそうなのでこれから検討してみます。

```delete.php

foreach (glob($relative.'/data/*.*') as $file) {
  unlink($file);
}
foreach (glob($relative.'/data/*') as $file) {
  unlink($file);
  remove_directory($file);
}

function remove_directory($dir) {
    $files = array_diff(scandir($dir), array('.','..'));
    foreach ($files as $file) {
        // ファイルかディレクトリによって処理を分ける
        if (is_dir("$dir/$file")) {
            // ディレクトリなら再度同じ関数を呼び出す
            remove_directory("$dir/$file");
        } else {
            // ファイルなら削除
            unlink("$dir/$file");
            //echo "ファイル:" . $dir . "/" . $file . "を削除\n";
        }
    }
    // 指定したディレクトリを削除
    return rmdir($dir);
}
```
- Pythonの場合、ディレクトリ名を指定すれば中身があるディレクトリも一発で消せる方法があるのですね

```delete.py

import pathlib
import shutil
p = pathlib.Path('selenium-master')
shutil.rmtree(p)
```
- Pythonで指定したディレクトリ内のファイルとディレクトリを一気に消す（まあ、綺麗な方でしょう）

```all_del.py

import shutil
import glob
import os
# ディレクトリ内のファイルとフォルダのリストを my_list に入れます。
my_list = glob.glob("./data/*")
# my_list の中身を最後まで流します。
for value in my_list:
# ファイルなのかフォルダなのかで消去するコマンドを分けます。
	if os.path.isfile(value):
		os.remove(value)
	elif os.path.isdir(value):
		shutil.rmtree(value)
```
この方法、コードを掲載しているサイトが以外に無いですね。これを使うと消したいファイルの拡張子を選択する事もできます。何より圧縮ファイルを解凍したのを消したかったのです。もっと綺麗な方法があったら是非教えて欲しいです。
######７．サニタイジング
PHPだと標準で関数が用意されてますが、Python はあまり見掛けないようですね。

```sanitizing.php

$wfull = htmlspecialchars($wtarget, ENT_QUOTES);
```

このような方法があるようですが、もう少し検討してみたいと思います。

```sanitizing.py

import cgi
inlist = 'https://www.yahoo.co.jp/'
transform = cgi.escape(inlist)
print(transform)
# https://www.yahoo.co.jp/
inlist = '"><script>alert(document.cookie);</script>'
transform = cgi.escape(inlist)
print(transform)
# まあサニタイジングに対処できてますね
# "&gt;&lt;script&gt;alert(document.cookie);&lt;/script&gt;
```