WEBスクレイピングGUIデスクトップアプリケーション feat.ひよっこフロントエンド

## はしがき
できれば1月中に書きたかったけど寒くてできんかった。
毎日やってる某単純作業が面倒で自動化したいなって思ったのがことの発端。
スクレイピング(今回はブラウザ自動操作)の自動化はすでにできていたけど、CLIでコマンド流すだけなの機械的だなあてことでGUIの作成を考え始める。
今回全て初めて扱った技術なのでこんなの作ったよってのと所感とかを述べたいと思います。

## 実行環境 & 使用技術
- macOS 12.2.1
- Python 3.11.1
- selenium 4.7.2
- tkinter 8.6

## 構成
`構成図`
![attend.py.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3078763/9e3b8c2a-d5c4-65cf-14fb-d92834b7a562.png)

`ディレクトリ構成`
```
.
├── scraping.py    // スクレイピング操作の関数
├── gui.py　　　　　　　　　　　　　　　　　　// GUIアプリのUI/UX
└── global_var.py  // ↑２つで相互的に扱う変数の状態管理
└── database
    ├── user.csv
    └── Users
        └── {Username}.csv
        └── {Username}.csv
        └── {Username}.csv

```
### 仕様
- スクレイピング時にログインが必要なので、メアドパスワードをアプリに保存。
- GUIにメアドパスワードが表示されている状態は避けたかったので保存先にcsvファイルをモックとして使用。その際`UserName`を集める`User.csv`、メアドパスワードの情報を持った`{UserName}.csv`の二種類を作成。
- プルダウンに`UserName`一覧を表示、選択された`UserName`のcsvファイルの情報とスクレイピング操作時に記入事項があるので、ボタン押下時にそのテキスト情報を`scraping.py`に渡してスクレイピングを実行。

## 詰まった点
### selenium(スクレイピング)
#### 要素取得できない問題
結論：iframe要素を操作対象のiframeに変更する。
```
    # iframe切り替え
    iframe = driver.find_element(by=By.XXX, value="XXX")
    driver.switch_to.frame(iframe)
```
>`iframe` : HTMLファイルの中に別のHTMLファイルを埋め込める。要は別のページ扱い。🙄🙄🙄

seleniumを使ってブラウザ操作する際は操作対象のURLに遷移、ブラウザ内の要素の`id`,`class`,`XPath`等を指定してDOM操作を行うのだけど、なぜか処理が行われずにセッションが終わってしまい????????だった。
何がタチ悪いってエラーが出なかったから原因の追求に結構時間を要してしまった。
iframeについても地図を埋め込むときになんか使ったなくらいの認識だったから勉強になりました。。
### tkinter
#### tkinter起動しない問題
結論 : Tcl/Tkをインストールする。
```
## エラー内容
 in <module> import _tkinter 
# if this fails your python may not be configured for tk modulenotfounderror:
 no module named '_tkinter'
```
> `Tcl/Tk` : スクリプト言語のTclでGUI開発を行うためのツール
`tkinter` : Tcl/Tkを扱うためのライブラリであり、Pythonに標準搭載されている。

しかし、pyenv環境でpythonをインストールするとTcl/Tkはついてこないのでインストールしないといけない。
pythonの環境構築をする際[progateの記事](https://prog-8.com/docs/python-env)を参考に言われるがままCLI操作をしていたので、これが良くなかった。流石に自分が今何を使って何をしているくらいは知っとくべきだった。
また、インストールの後に環境変数を設定しないといけなかったのだがホームディレクトリ直下ではなく現在のディレクトリでファイルを作ってしまったり環境変数をコピペし間違えたりで何回かインスコアンスコ繰り返していらんことしてた。

### python
#### 循環インポート問題
結論 : (というか今回の対処法)グローバル変数だけを格納する`global_var.py`を用意して循環インポートを回避する。
```
## エラー内容
AttributeError: partially initialized module 'xxx' has no attribute 
(most likely due to a circular import)
```
> Reactで子コンポーネントに関数を渡す要領で関数と変数の受け渡しをしようとしてフツーにダメだった。

ざっくり図解すると、、
![import_false.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3078763/e709cada-efe2-f4a2-c729-ad4dae8c9e1a.png)
上の図のように相互的に関数、変数を`import`しようとしてできんよって言われたので、

![import_true.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3078763/29e03810-b138-5885-6f4c-f102a687dbaa.png)
変数を管理するフォルダを作成し、循環を避ける。redux等のstoreの要領？


## 課題とか
機能面的にはユーザーデータの削除や更新とかもGUIで追加したい。
また、今回はデスクトップアプリだったので今度はさらに実用的なWebアプリをやりたい、Djanogoとかですかね？　もしくはフロント技術ベースでデスクトップアプリ？

また、JavaScriptn以外の言語を初めて触れたのでpythonならではの部分をさらに深堀していけたらと思います。


## あとがき
この記事書いてる時に気づいたけど`scraping.py`起動のボタン押下時に`scraping()`の引数に`UserData`渡せば`scraping.py`で変数をインポートする必要ないから循環インポートにならないで済むやん、て。いや一人だと気づかんね（）
恥ずかしすぎるのでなかったことにしようかと思ったけど学びはあったし記録として残します。
グローバル変数のフォルダは状態遷移があるのがわかりやすいしいいよねって自分を思わせて筆をたたむ。

他にも、pythonどころかプログラミングも初心者なので違うよとかもっいいのあるよとかあればお待ちしております。


### 参考
[【Python】Selenium：no such element: Unable to locate elementの解決（iframe要素取得）](https://office54.net/python/scraping/selenium-element-iframe)
[【Python3】macのpyenv環境下でtkinterを使えるようにする。](https://qiita.com/M0304/items/0621c45a14db10931097)