【Python】妻に真夜中のダンスレッスン予約を強要されたので、Webスクレイピングで回避を試みようとしている話 （７．importについて確認せよ）

前回は、<a href="https://qiita.com/sibulabo/items/edbf835b3dd2931d7b09">「６．プログラミングの始まり」</a>について発信しました。
今回は、いよいよプログラミングに突入！と意気込み、mainメソッドをコーディングしようと思っていましたが、import周りの理解が不足していることがあらわになり、そちらに時間をさくことにしました。

## 必要なパッケージの import

seleniumを使用するために、必要なパッケージ、関数、あるいはクラスを importする必要があります。今回は、この import周りについて理解を深めようと思います。

## まず、ライブラリ、パッケージ、モジュール、関数（クラス）の関係を理解する
import周りを理解するには、これらの関係を知っている必要があります。関係図を以下に記します。（以下の説明は理解することを優先しており、厳密には違うかもしれません。ご了承ください。:relaxed:）
- モジュールは、関数またはクラスがコーディングされたPythonファイル（xxx.py）です。
- パッケージは、Pythonファイル（モジュール）が集まったフォルダです。パッケージにパッケージを含めることもできます。その場合、下層のパッケージをサブパッケージといいます。
- ライブラリは、パッケージで構成された最上層のフォルダです。（ライブラリは最上層のパッケージといえます。）
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2915699/afa85450-0b50-8355-3a22-1e0a01382762.jpeg" width="70%">

## サンプルのimport文を使って確認
実際にググったサンプルプログラムにあった import文を使って確認します。
直訳すると、「"selenium.webdriver.common.by"から By をインポートする。」になります。
```reserveLesson.py
from selenium.webdriver.common.by import By
```
**import By** の **By** は、何者でしょうか？ print文で確認してみます。
```whats_By.py
from selenium.webdriver.common.by import By
print(By) # Byは何もの？
--実行結果--
<class 'selenium.webdriver.common.by.By'>
```
**class** と出力されました。モジュールに定義されているクラスのようです。

次に **By** の上の **by** について確認します。Byがクラスなので、上層の by はモジュールだと予想しますが、どうでしょうか？
```wahts_by.py
from selenium.webdriver.common import by
print(by) # byは何もの？
--実行結果--
<module 'selenium.webdriver.common.by' from 'c:\\reserveLesson\\env\\lib\\site-packages\\selenium\\webdriver\\common\\by.py'>
```
**module** と出力され、物理ファイルの場所も出力されました。やはり、モジュール（by.py）でした。

:::note
標準ライブラリ、外部ライブラリは、仮想環境のフォルダ下に配置されています。
osなどの組み込みライブラリは、グローバルなPythonフォルダ下に配置されていることも別途確認できました。
:::

## Byクラスが定義されている by.pyファイルを確認してみます。
byの物理フォルダがわかったので、エクスプローラーで確認してみます。
![WS000022.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2915699/a865adcd-47d5-5e2b-adf8-a6f02521be0d.jpeg)
seleniumのフォルダ構成を見てわかるように、fromで指定されているドット(.)は、フォルダ階層の区切りを表しているようです。
```text:from句とフォルダパスの比較
from selenium.webdriver.common.by
                ↓
\selenium\webdriver\common\by.py
```
関係図とフォルダ構成は以下のとおりです。
![WS000000.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2915699/2b03c62f-8ba9-8fd6-5555-34fa31398271.jpeg)


## by.pyファイルの中身も確認してみます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2915699/55bcf695-ab02-490e-539e-014d9132cc21.jpeg" width="80%">

Byクラスが定義されていることが確認できますね。

後に登場する find_element関数の引数として、By.ID や By.XPATH を指定できるのは、このクラスを importしているからですね。

## パッケージについても確認してみます。
関数（クラス）、モジュールのインポートを確認しましたが、ついでにパッケージについても確認してみます。ここでは、seleniumライブラリの webdriverパッケージについて確認してみました。

```whats_webdriver.py
from selenium import webdriver
print(webdriver)
--実行結果--
<module 'selenium.webdriver' from 'c:\\reserveLesson\\env\\lib\\site-packages\\selenium\\webdriver\\__init__.py'>
```
**module** と表示されました。**package** と表示されるのかなと思いましたが、そうではないみたいです。語尾のファイル名に **\_\_init\_\_.py** というファイル名が確認できます。この **\_\_init\_\_.py** がパッケージであることを示しているそうです。 パッケージの実体は **\_\_init\_\_.py**ファイルであり、そのファイルのあるフォルダ名がパッケージ名なのだと理解しました。 **\_\_init\_\_.py** については、別途機会を作って調べてみるつもりです。
## importのメリット
importすることで関数、またはクラス使用時にパッケージ名を省略できるので、見通しの良いコードが実現できるメリットがあります。先程の Byクラスを例に取ると、あるとき、ないときでコードのみやすさがかなり違ってきます。ないと冗長で読みづらいです。

```import_By_あるときないとき.py
# import Byのある時
elm = driver.find_element(By.ID, "submit")
# import Byのないとき
elm = driver.find_element(webdriver.common.by.By.ID, "submit")
```

まとめる時間が少ないため分かりづらい説明になってしまいましたが、自身としては import周りの知識が深まりました。自作のライブラリを作成する際にも少し役立ちそうです。

> 今回は、import周りについて理解を深めました。
> 次回は、いよいよブラウザを開いて閉じるぐらいできればいいなと思っています。
> では、良い週末を！