[Python]ローカルのフォルダ内にあるHTMLソースファイルの全リンクを抽出

## 経緯
https://qiita.com/akira-hagi/items/749f70127ee1d4fa4206

ほぼ前回の続きです
webページのソースをディレクトリそのままにスクレイピング、

詳しく述べると、
`https://www.hoge.com/huga/hoge/index.html`と`https://www.hoge.com/huga/index.html`のソースをまとめて取得するとき、
ドメイン名をトップディレクトリとし、
```
└── www.hoge.com
     └── huga 
          ├── hoge ── index.html
          └── index.html
```
のようにしてローカルに持ってきました

このHTMLソース群の中からリンク（aタグのhref要素やimgタグのsrc要素など）を抽出したいと考えました
~~スクレイピングする時にわざわざソースをローカルに落とさずに直で抽出すればいいじゃんというツッコミは無しでお願いします~~

## とりあえず思いつくままに書く
```python
from bs4 import BeautifulSoup
import os

def fileGetLink(path):
 if os.path.isdir(path):
        fileList = os.listdir(path)
        for file in fileList:
            fileGetLink(os.path.join(path, file))
 else:
  soup = BeautifulSoup(open(path, encoding='utf-8'), 'html.parser')     

  for link in soup.find_all("a"): # aタグを取得
        with open('./hogeLink.txt', "a", encoding='UTF-8', newline='\n') as f:
         if link.get("href") is None:
          continue     
         f.write(link.get("href") + "\n")

  for link in soup.find_all("img"): # imgタグを取得
        with open('./hogeLink.txt', "a", encoding='UTF-8', newline='\n') as f:
         if link.get("src") is None:
          continue     
         f.write(link.get("src") + "\n")

  for link in soup.find_all("link"): # linkタグを取得
        with open('./hogeLink.txt', "a", encoding='UTF-8', newline='\n') as f:
         if link.get("href") is None:
          continue     
         f.write(link.get("href") + "\n")

  for link in soup.find_all("script"): # scriptタグを取得
        with open('./hogeLink.txt', "a", encoding='UTF-8', newline='\n') as f:
         if link.get("src") is None:
          continue     
         f.write(link.get("src") + "\n")   

fileGetLink('./www.hoge.com')  
```
冗長だなあ
## 解説
```python
def fileGetLink(path):
 if os.path.isdir(path):
        fileList = os.listdir(path)
        for file in fileList:
            fileGetLink(os.path.join(path, file))
```
再帰検索してます
ファイルだったら処理、フォルダだったら検索、というのを繰り返しています
```python
 soup = BeautifulSoup(open(path, encoding='utf-8'), 'html.parser')     

  for link in soup.find_all("a"): # aタグを取得
        with open('./hogeLink.txt', "a", encoding='UTF-8', newline='\n') as f:
         if link.get("href") is None:
          continue     
         f.write(link.get("href") + "\n")

  for link in soup.find_all("img"): # imgタグを取得
        with open('./hogeLink.txt', "a", encoding='UTF-8', newline='\n') as f:
         if link.get("src") is None:
          continue     
         f.write(link.get("src") + "\n")

  for link in soup.find_all("link"): # linkタグを取得
        with open('./hogeLink.txt', "a", encoding='UTF-8', newline='\n') as f:
         if link.get("href") is None:
          continue     
         f.write(link.get("href") + "\n")

  for link in soup.find_all("script"): # scriptタグを取得
        with open('./hogeLink.txt', "a", encoding='UTF-8', newline='\n') as f:
         if link.get("src") is None:
          continue     
         f.write(link.get("src") + "\n")   
```
find_allでまとめて取得して`hogeLink.txt`に書き出す処理です
NoneTypeで止まることあるので引っ掛けてcontinueしています

## 反省と修正
### 冗長過ぎてダサい
find_allの部分が冗長だなあと自分でも思いました
Beautiful Soupの公式ドキュメントを見ると、
タグを配列にして複数条件いけるおーとのことです
>Recall from Kinds of filters that the value to name can be a string, a regular expression, a list, a function, or the value True.

https://www.crummy.com/software/BeautifulSoup/bs4/doc/#the-name-argument

```python
 soup = BeautifulSoup(open(path, encoding='utf-8'), 'html.parser')     
  for link in soup.find_all(["a","link"]): 
        with open('./hogeLink.txt', "a", encoding='UTF-8', newline='\n') as f:
         if link.get("href") is None:
          continue     
         f.write(link.get("href") + "\n")

  for link in soup.find_all(["script","img"]):
        with open('./hogeLink.txt', "a", encoding='UTF-8', newline='\n') as f:
         if link.get("src") is None:
          continue     
         f.write(link.get("src") + "\n")   
```
こんな感じでスッキリしました

### 再帰処理いらない説
`os.walk`というディレクトリ下のファイル全てを検索してくれる関数があるそうです
以下参考記事

https://qiita.com/hasepy/items/8e6a0757da1ce074ce87

```python
def fileGetLink(path):
 for pathName, dirName, fileName in os.walk(path):
  for file in fileName:
   path = os.path.join(pathName,file)
   soup = BeautifulSoup(open(path, encoding='utf-8'), 'html.parser') 
```
コンパクトになりました

## 最終的な実装
```python
from bs4 import BeautifulSoup
import os

def fileGetLink(path):
 for pathName, dirName, fileName in os.walk(path):
  for file in fileName:
   path = os.path.join(pathName,file)
   soup = BeautifulSoup(open(path, encoding='utf-8'), 'html.parser') 
    for link in soup.find_all(["a","link"): 
        with open('./hogeLink.txt', "a", encoding='UTF-8', newline='\n') as f:
         if link.get("href") is None:
          continue     
         f.write(link.get("href") + "\n")

    for link in soup.find_all(["script","img"]):
        with open('./hogeLink.txt', "a", encoding='UTF-8', newline='\n') as f:
         if link.get("src") is None:
          continue     
         f.write(link.get("src") + "\n") 

fileGetLink('./www.hoge.com') 
```

## まとめ
以上のスクリプトを実行するとソース内のリンクがビャーっとテキストファイルにリンク群が書き出されていきます
webサイトの内部ファイル(画像やpdfなど)の存在チェックをしたい時などにオススメです
余談ですが、最初自分の手癖で書いて、あとから公式ドキュメントなどを調査してコードをブラッシュアップしていく方式がすごく良かったので、皆様も是非やってみて下さい
（誤り等あれば指摘コメント下さい）