Pythonで検索キーワードと対象URLをいれたらスクレイピングするツールを作ってみた

## １．きっかけ
取引先の担当者の異動情報をネットから自動でチェックする機能が欲しいなぁという要望から作成に至った。
本当は、JavaScript等でそのままブラウザから選択してリンクに飛べるようしたいが、今回はまずPythonでリストを出力するイメージで作成。
今後、JavaScript等で作成予定。

## ２．おおまかな機能イメージ
異動情報を探す際の探し先のURLおよびキーワードを設定ファイル（JSON）に記載したら、それを基にスクレイピングして、キーワードを含むリンクを一覧ファイルに出力するイメージ。

## ３．おおまかな設計
①JSON取り込み
　→ JSONファイルに探し先のURLおよびキーワード（複数追加可能）を設定し、ツール実行時にそれぞれ設定内容を取得する。
 
②リンク先の取得
　→ 探し先のURLからリンク先を抽出し、検索キーワードを検索する先のURLを取得する。
 
③webページにキーワードが入っているか確認
　→ ②で取得したリンクに対し、htmlファイルを取得し、JSONファイルで指定したキーワードが含まれているか確認。
 
④キーワードが含まれているページと内容をCSVへ出力
　→ ③で取得したキーワードを含む部分とURLを一覧表として出力する。
 
## ４．コード説明
### 成果物リンク
[GitHub](https://github.com/k-tsuru/tool/commit/4760ac3b089ae06ffb33056eedb2de637468f616)
　・keyword.json　→　検索キーワード設定ファイル
 　・keyword_check_tool.py　→　検索用ツール
### ①JSON取り込み
~~~keyword_check_tool.py
{
    "Url":{
        "startUrl":"【スクレイピングスタートページURL】"
    } ,
    "element":{
        "1":"【検索キーワード１】",
	"2":"【検索キーワード２】",
	"3":"【検索キーワード３】",
	"4":"【検索キーワード４】"
    }
}
~~~~
"Url"ブロックでスクレイピングスタートページのURLを設定
また、"element"ブロックで検索キーワードを複数設定

~~~keyword_check_tool.py
# JSONファイルの取得
read_json_file = os.path.join(dir_path, input_file_name)

# JSONファイルの読み込み
json_open = open(read_json_file, 'r',encoding = 'utf-8')
json_load = json.load(json_open)

# スクレイピング開始URLの取得
start_url = json_load['Url']['startUrl']

# 検索キーワードの取得
json_load_keyword = json_load['element']
keyword = []

# 検索キーワードの格納
for keyword_value in json_load_keyword.values():
    keyword.append(keyword_value)
~~~~
JSONファイルからURLとキーワードを取得し、格納する。

### ②リンク先の取得
~~~keyword_check_tool.py
# HTMLを解析
soup = BeautifulSoup(html, 'html.parser')

# 解析したHTMLから任意の部分のみを抽出（ここではtitleとbody）
title = soup.find("title")
body = soup.find("body")
href = soup.find("href")

# リンクスタート先の設定
link_start = ""
start_item = soup.find("link", rel="start")
link_start = start_item.get('href')
# 最後の"/"を削除
link_start = link_start[:-1]

# リンク先取得
html_link = []

for link_item in soup.find_all("a", class_="idens-morelink"):
    link = link_item.get('href')
    # リンク先格納
    html_link.append(link_start + link)
~~~~
BeautifulSoupを使用し、取得したHTMLファイルの解析を実施。
解析した中でリンク先となっているURLを配列に格納していく。

### ③webページにキーワードが入っているか確認
④と合わせてコード記載
### ④キーワードが含まれているページと内容をCSVへ出力

~~~keyword_check_tool.py
# カウント変数の宣言
no = 0

# CSVファイル作成
output_file = open(output_file_path, mode='w')

while no < len(html_link):
    html_text = ""
    keyword_text = ""
    html_text = urlopen(html_link[no])
    html_soup = BeautifulSoup(html_text,'html.parser')
    keyword_text = html_soup.get_text()
    keyword_text = keyword_text.encode('cp932', "ignore")
    f = open(tmp_file_path, mode='wb')
    f.truncate
    f.write(keyword_text)
    f.close
    str_row = ''
    with open(tmp_file_path, mode='r') as f:
        # html1行毎に確認
        for line in f:
            keyword_count = 0
            # JSONで指定したキーワード分確認
            while keyword_count < len(keyword):
                if keyword[keyword_count] in line:
                    str_row += line[:-1]
                    str_row += ","
                    str_row += html_link[no]
                    str_row += '\n'  
                keyword_count += 1
        # CSVファイルに書き込み
        output_file.write(str_row)  
    f.close   
    no += 1

    # サーバ負荷対策
    time.sleep(0.1)
~~~~
検索先のサーバに負荷を与えぬように、0.1秒間を開けるようスリープ処理をhtml取得し、検索毎の間に入るよう記載

## ５．苦労した点
エンコード関係ですごくエラーが続いた為、".encode('cp932', "ignore")"で変換処理を実装。他によいやり方があるかと思うが暫定措置として記載。

## ６．今後について
今回、バッチ処理で取得するイメージにて作成したが、今後はブラウザ等に一覧形式で表示し、すぐにリンク先に飛んで確認できるようJS等で実装していきたい。

## ７．注意点
実際に、サイトを指定してスクレイピングする場合は事前に対象のサイトがスクレイピングを許可しているか確認する必要がある。（もしかしたら捕まる）

スクレイピングを許可しているかどうかは、対象のWebサイトのURLの末尾に「/robots.txt」と入力すると確認可能。（可能な場合は「Allow」不可の場合は「Disable」

参考サイト：[Webスクレイピングは違法？禁止サイトの確認手段や適切な方法を紹介](https://ai-kenkyujo.com/%E6%9C%AA%E5%88%86%E9%A1%9E/scraping-ihou/#:~:text=%E3%82%B9%E3%82%AF%E3%83%AC%E3%82%A4%E3%83%94%E3%83%B3%E3%82%B0%E3%82%92%E8%A8%B1%E5%8F%AF%E3%81%97%E3%81%A6%E3%81%84%E3%82%8B%E3%81%8B%E3%81%A9%E3%81%86%E3%81%8B%E3%81%AF%E3%80%81%E5%AF%BE%E8%B1%A1%E3%81%AE,%E3%82%AF%E3%83%AD%E3%83%BC%E3%83%A9%E3%83%BC%E3%81%8C%E5%AF%BE%E8%B1%A1%E3%81%A8%E3%81%AA%E3%82%8A%E3%81%BE%E3%81%99%E3%80%82)