PYTHONでWEB検索(Beautiful Soup 4)

概要

 先回はエクセルVBAから、IE (インタネットエクスプローラー)を操作し、簡単なデータ検索を行いました。
 今回は、python と Beautiful Soup 4というライブラリを使って 先回行ったのと同じ英単語検索を試みました。 IEの開発は終了し、サポートも縮小しつつあるとのことですので、具体的利用も想定し、他の方法も調べてみようと思ったのが発端です。
 最近、少し python にも触れ、ライブラリが充実しているので面白いと感じていますが、他の人にプログラムを配布するのが課題だと感じていました。ところが、python プログラムの “EXE化” についての記事を見つけましたので確認した内容も報告します。

ライブラリインストール

 “requests”と“beautifulsoup4” というライブラリをインストールします。requests を使ってWebサイトのHTMLや画像などの情報を収集し、 beautifulsoup4 で欲しい部分を解析・抽出するという使い方と思います。

(1) requests インストール

python -m pip install requests

(2) beautifulsoup4 インストール

python -m pip install beautifulsoup4
  

Python WEB検索 テストプログラム

 はじめに、 requests , Beautiful Soup 4 の使い方が判りませんので、下記プログラムを作成しながら使い方を学びました。
  “requests” でWEBページのHTMLを取得し、Beautiful Soup 4 を使って、タグ,クラス,ID等から、必要情報を収集します。

import os
import urllib.error
import urllib.request
import requests
from bs4 import BeautifulSoup
import tkinter as tk
from tkinter import messagebox

# 画像ファイルダウンロード
def download_file( url , dst_path ):
    try:
        with urllib.request.urlopen(url) as web_file:
            data = web_file.read()

            with open(dst_path , mode="wb") as local_file:
                local_file.write(data)
                
    except urllib.error.URLError as e:
        print(e)


        

root = tk.Tk()
root.withdraw()

s_word = "apprentice"                                   # 検索単語

html_text = requests.get("https://[省略]/content/" +s_word).text
soup = BeautifulSoup(html_text, 'html.parser')          # BeautifulSoup初期化

# print(soup.prettify())                                # インデント処理                  

# タイトル取得
title_text = soup.find('title').get_text()              # タイトル
print("【TITLE】" + title_text)
print("")

# 単語・意味取得
chk_way="find"                                          # 検索方法選択
if chk_way=="find" :
    w_find = soup.find("span", id="[省略]").text
    w_mean = soup.find("td", class_="[省略]").text    
else: 
    w_find = soup.select_one("[省略]").text
    w_mean = soup.select_one("[class='[省略]']").text

print("【"+ w_find +"】" + w_mean)
print("")


# 音声ファイルURL取得
SND_URL = soup.find("audio", class_="[省略]").find("source")['src']
print("【AUDIO FILE】" , end = "")
print(SND_URL)
print("")

root , ext = os.path.splitext(SND_URL)                  # 拡張子取得
DST_F = os.path.join(os.getcwd() ,"snd" , s_word+ext)   # 保存ファイル名取得

#print(DST_F)                                           # 保存ファイル名
#print(os.getcwd())                                     # プログラムフォルダ
#print(__file__)                                        # ファイルパス

try:
    download_file( SND_URL , DST_F )
    jdg_dl = "〇"
except:
    jdg_dl = "×"

#print("【DOWNLOAD】  " + jdg_dl )
    
messagebox.showinfo( w_find , w_mean )

 次の図の通り、WEBページタイトル,単語の意味,音声ファイルURLを取得し出力しています。


  

VBA対応の改造(連続処理)

 先回VBAからのIE操作による英単語検索同様にエクセルシート上の単語を連続して検索できる様に改造します。下図の通りシート外観は先回とほとんど同じです。
 方法はエクセルVBAから、WshShell オブジェクトを利用し、シートの単語を1語づつ引数渡ししプログラム起動します。

 先回に比べ、今回はブラウザー起動しないこともあり、下表の通り検索時間を大きく短縮することが出来ました。但し、VBA-IE操作 の場合でもブラウザーを非表示にして検索時間を短縮することも可能なのかもしれません。

方法検索時間
(秒/19語)
検索時間
(秒/語)
VBA-IE操作 1719
Python +
BeautifulSoup4
271.42

■ WEB検索 Python プログラム改造

 検索を行うPython側プログラムは、VBAから外部起動された時に引数として英単語を受け取り、テストプログラム同様にWEB検索後、結果をテキストファイル保存します。

import os
import sys
import urllib.error
import urllib.request
import requests
from bs4 import BeautifulSoup
import tkinter as tk
from tkinter import messagebox



def download_file( url , dst_path ):
    try:
        with urllib.request.urlopen(url) as web_file:
            data = web_file.read()

            with open(dst_path , mode="wb") as local_file:
                local_file.write(data)
                
    except urllib.error.URLError as e:
        print(e)


def search_e_word(e_wrd):
    
    s_word = e_wrd
    dirPth = "C:/Users/[省略]/snd/"
    html_text = requests.get("https://[省略]/content/" +s_word).text
    soup = BeautifulSoup(html_text, 'html.parser')                              # BeautifulSoup初期化

    w_mean = soup.find("td", class_="[省略]").text              # 単語意味取得

    try:
        SND_URL = soup.find("audio", class_="[省略]").find("source")['src']   # 音声ファイルURL取得

        root , ext = os.path.splitext(SND_URL)                                      # 拡張子取得
        DST_F = dirPth + s_word + ext                    # 音声ファイル保存名取得

        # 音声ファイルダウンロード
        download_file( SND_URL , DST_F )
        jdg_dl = "1"
    except:
        jdg_dl = "0"    

    rslt = w_mean + "###" + jdg_dl

    DST_T = dirPth + s_word + ".txt"  

    fileobj = open(DST_T , "w")
    fileobj.write(rslt)
    fileobj.close()

    return rslt



if __name__ == "__main__" :

    argv = sys.argv
    
    try:
        eng_wrd = argv[1]
    except:
        eng_wrd = "gastrointestine"
        
    root = tk.Tk()
    root.withdraw()
   
    rslt = search_e_word(eng_wrd)

    print(rslt)

■ VBAプログラム作成

 VBA側は WshShell オブジェクト RunメソッドでPythonプログラムを終了待ちし、プログラム終了後テキストファイルの中身をエクセルシート上に表示します。

Option Explicit

'参照設定
'Windows Script Host Object Model

Private Sub CommandButton1_Click()
    Dim wsh As WshShell
    Dim cmd_str As String
    Dim ret

    Dim sht, wrd
    Dim cnt
    Dim rtn_m As Variant
    
    
    Set wsh = CreateObject("WScript.Shell")
    sht = ActiveSheet.Name
    cnt = 0
    
     Worksheets(sht).Cells(1, 1).Value = Now
    
    Do
        wrd = Trim(Worksheets(sht).Cells(5 + cnt, 1).Value)
        If wrd = "" Then Exit Do
        
        wrd = StrConv(StrConv(wrd, 8), 2)
        
        cmd_str = "python C:\Users\[省略]\bs4_03.py " + wrd
        
        ret = wsh.Run(cmd_str, 0, True) 'パス,ウィンドウスタイル,終了待ち

        rtn_m = Split(text_Open(wrd), "###")
        
        Worksheets(sht).Cells(5 + cnt, 2).Value = Replace(rtn_m(0), vbCrLf, "")
        Worksheets(sht).Cells(5 + cnt, 3).Value = rtn_m(1)
        
        DoEvents
        cnt = cnt + 1
    Loop
    
    Worksheets(sht).Cells(2, 1).Value = Now
End Sub


’ファイルを開く
Public Function text_Open(wrd)
 
    Dim FileName As String
    Dim FileNum As Integer
    Dim buf, str
    
    FileName = "C:\Users\pana-win10\kーdata\20200910_python_beutifulsoup_01\snd\" + wrd + ".txt"
    FileNum = FreeFile  'ファイル番号を取得
    
    'ファイルをシーケンシャル入力モードで開く
    Open FileName For Input As #FileNum
    
        'ファイルの末尾まで繰り返す
        Do Until EOF(FileNum)
                        
            'テキストファイル 1 行分を変数 buf に格納する
            Line Input #FileNum, buf
            str = str & vbCrLf & buf
        
        Loop
        
    'ファイルを閉じる
    Close #FileNum
    
    text_Open = str
 
End Function

 尚、 WshShell オブジェクト 利用の為、下図の“Windows Script Host Object Model” を参照設定しています。

  
  

pythonプログラムの EXE 化

 pyinstaller をインストールします。
 [ python -m pip install pyinstaller ]

python -m pip install pyinstaller
  

 コマンドプロントで、変換対象 python プログラムがあるフォルダーに移動し、下記コマンドで exe ファイルに変換します。
 [ pyinstaller bs4_02.py –onefile ]
 オプションの ‘–onefile’ は関連ファイルを1つにまとめてexeファイルを作成し、‘–noconsole’ はコマンドプロンプトを表示しない様にする様です。。

pyinstaller bs4_02.py –onefile

  下図 元の ‘bs4_02.py’ ファイル以外のフォルダ,ファイルは変換処理によって生成されたものです。フォルダ [ dist ] の中にexe ファイルが生成されます。

 下記の通り動作確認出来ましたが、少し、遅くなった様な気がします。  他環境での検証は別途必要でしょう。 ‘–noconsole’ オプションを指定していないので、メッセージボックス背景にコマンドプロンプトが表示されています。

  
 

まとめ

 python プログラムを exe ファイルに変換出来ることを知ったのは大きな収穫です。利用範囲も拡がると思います。
 他にも “xlwings” ,” OpenPyXL ” などの仕組もある様ですので、機会があれば確認してみたいと思います。


コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です