WEBスクレイピングで必要なデータだけ目的のページから抜き取って、そのままEXCELで一覧表にするPythonプログラムを作ってみます。
やりたいこと
例えば下記のサイトみたいな使えそうな表を提供してくれるサイトから、一覧表の部分(ランキングの表とか)だけを抜き取ってEXCELの表に自動的に変換したい。
そう思っているわけです。
必要なモジュール
手順としては。
- WebサイトからHTMLファイルをダウンロードする。
- HTMLファイルを解析して必要な部分のデータだけ抜き出す。
- 抜き出したデータを編集してEXCEL表形式で保存する。
みたいになります。
幸い、便利なpythonのモジュールがあります。
まず、それをインストールします。
WebからHTMLファイルをダウンロードするモジュール
pip install requests
HTMLを解析して、必要なデータを抜き出すモジュール
pip install beautifulsoup4
EXCELの読み書きをpythonからやる。
pip install openpyxl
とりあえず、これで道具としてはそろいます。
対象のWEBページを決めてHTMLを確認する
今回は「報道の自由度ランキング」を対象にします。
このページのランキングの表をEXCELに取り込む対象にします。
そのために、HTMLを確認します。
今回は、Google Chromeの「検証」機能を使います。
ソースの検証
確認したい表にマウスをあてて、右クリックメニューから「検証」を選びます。
そうすると、デベロッパーツールが立ち上がってきます。
クリックした場所のHTMLをスマートに確認できます。
このページのHTMLの解析
HTMLを見て、一覧表部分のHTMLタグを確認します。
シンプルな<table>タグで構成されています。
ポイントは、ranking_tableというクラス名のDIVタグの内側に、取得したいテーブルコンテンツがすべて収まっている。
だから、ranking_tableというクラス名のDIVタグの内側を、すっぽり抜き取ってしまえば良いということがわかります。
それが確認できたので次にいきます。
pythonでExcelファイルを作る
これは、あれこれ説明するよりもソースを見た方がはやいような気がします。
コメントもつけてますし。
import requests as web import bs4 import openpyxl as excel from openpyxl.styles import Font from openpyxl.styles import PatternFill from openpyxl.styles import Border from openpyxl.styles import Side from openpyxl.styles import Alignment # B1などのrange指定文字列に変換する def cell(col,row): col_ar = ['B','C','D','E','F'] return col_ar[col] + str(row) # 列番号を列を示す文字に変換する def col(col): col_ar = ['B','C','D','E','F'] return col_ar[col] # 新規ワークブックオブジェクトを生成する wb = excel.Workbook() # アクティブシートを得る sheet = wb.active # シート名を変更する sheet.title = "報道の自由度ランキング" # B2セルにタイトルを書く。フォントサイズを24にして、センタリングする sheet['B2'] = "報道の自由度ランキング" sheet['B2'].font = Font(size=24) sheet['B2'].alignment = Alignment(wrap_text=False, # 折り返し改行 horizontal='center', # 水平位置 vertical='center' # 上下位置 ) # セルを結合する sheet.merge_cells('B2:F2') # WEBページにアクセスして、HTMLを取得する res = web.get('http://ecodb.net/ranking/pfi.html') if(res.status_code == web.codes.ok): # パースしてDOMを取得する soup = bs4.BeautifulSoup(res.text,"html.parser") # ranking_tableクラスのDIVの内側にあるthタグをすべて取得する th = soup.select('div[class=ranking_table] th') # thタグをヘダーとして書き込み、背景色とボーダーをつける for h in range(len(th)): sheet[cell(h,4)] = th[h].getText() sheet.row_dimensions[4].height = 20 sheet.column_dimensions[col(h)].width = 17 sheet[cell(h,4)].fill = PatternFill(patternType='solid', fgColor='E0FFFF00') sheet[cell(h,4)].border = Border(outline=True, left=Side(style='thin', color='FF000000'), right=Side(style='thin', color='FF000000'), top=Side(style='thin', color='FF000000'), bottom=Side(style='thin', color='FF000000') ) sheet[cell(h,4)].alignment = Alignment(wrap_text=False, # 折り返し改行 horizontal='general', # 水平位置 vertical='center' # 上下位置 ) # ranking_tableクラスのDIVの内側にあるtdタグをすべて取得する td = soup.select('div[class=ranking_table] td') for i in range(len(td)): # 1行5項目なので5で割ったり、5の余りをとったりしている c = i % 5 r = (i//5)+5 # セルに値をセットする sheet[cell(c,r)] = td[i].getText() # セルの高さを20にする if(c == 0): sheet.row_dimensions[r].height = 20 # 罫線を引く sheet[cell(c,r)].border = Border(outline=True, left=Side(style='thin', color='FF000000'), right=Side(style='thin', color='FF000000'), top=Side(style='thin', color='FF000000'), bottom=Side(style='thin', color='FF000000') ) # 横方向は標準、縦方向は中央にする sheet[cell(c,r)].alignment = Alignment(wrap_text=False, # 折り返し改行 horizontal='general', # 水平位置 vertical='center' # 上下位置 ) else: res.raise_for_status() # EXCELブックを保存する wb.save('test02.xlsx')
ポイントです。
ソースのこの部分です。
soup.select('div[class=ranking_table] th')
HTMLの解析には「Beautifulsoup」を使ってます。
さきほど確認したように「ranking_tableというクラス名のDIVタグの内側に、取得したいテーブルコンテンツがすべて収まっている」という構造です。
上記の処理では、BeautifulsoupのSelectを使い、クラス名をキーにして、ずぼっとデータを抜いてます。
後続のコードは、そこから行のデータを順次取り出して、EXCELファイルに加工しているだけです。
EXCELの操作は「openpyxl」というpythonのライブラリを使ってやってます。
ソースを読むにあたっては、以下の記事とかの基本的な使い方を参照してもらえると、そんなに難しいことはやってないのでわかると思います。
実行結果
これを実行して、生成されたEXCELシートはこんな感じです。
なかなか良い感じです。
いちいち、EXCELが立ち上がったりせずに、バックグラウンドで静かにEXCELファイルを作ってくれます。
処理も速いですしね。
追加情報です。
Beautifulsoupのドキュメントの日本語訳サイトです。
ちょっとバージョンは古いですが。
EXCELブックの操作の「openpyxl」について、さらに詳しく知りたい場合にそなえて本家のリファレンスのリンクをのせておきます。
(残念ながら英語ですけど)
今回はこんな感じで。
ではでは。