"BOKU"のITな日常

興味のむくまま気の向くままに調べたり・まとめたりしてます。

WEBページの表データをEXCELファイルに取り込む/PythonでWebスクレイピング

f:id:arakan_no_boku:20190223210405j:plain

 WEBスクレイピングで必要なデータだけ目的のページから抜き取って、そのままEXCELで一覧表にするPythonプログラムを作ってみます。

目次

今回の取り込み対象について 

下記のサイトみたいな使えそうな表を提供してくれるサイトから、一覧表の部分(ランキングの表とか)だけを抜き取ってEXCELの表に自動的に変換します。

ecodb.net

 資料にするのが楽ですからね。 

対象のWEBページを決めてHTMLを確認する

今回は「報道の自由度ランキング」を対象にします。

ecodb.net

このページのランキングの表をEXCELに取り込むため、HTMLを確認します。

以下はGoogle Chrome前提の操作になります。

確認したい表にマウスをあてて、右クリックメニューから「検証」を選びます。

f:id:arakan_no_boku:20180110224838j:plain

そうすると、デベロッパーツールが立ち上がってきます。

クリックした場所のHTMLをスマートに確認できます。

f:id:arakan_no_boku:20180110225008j:plain

 

HTMLを見て、一覧表部分のHTMLタグを確認します。

シンプルな<table>タグで構成されています。 

ポイントは、ranking_tableというクラス名のDIVタグの内側に、取得したいテーブルコンテンツがすべて収まっている。

 だから、ranking_tableというクラス名のDIVタグの内側を、すっぽり抜き取ってしまえば良いということがわかります。

それが確認できたので次にいきます。 

必要なモジュールのインストール

手順としては。

  • WebサイトからHTMLファイルをダウンロードする。
  • HTMLファイルを解析して必要な部分のデータだけ抜き出す。
  • 抜き出したデータを編集してEXCEL表形式で保存する。

みたいになります。

それに、便利なpythonのモジュールで、まだインストールされていないものについて、インストールしていきます。 

WebからHTMLファイルをダウンロードするモジュール

pip install requests

 HTMLを解析して、必要なデータを抜き出すモジュール

pip install bs4 

EXCELの読み書きをpythonからやる。

pip install openpyxl

スクレイピングpythonプログラム

あれこれ説明するよりもソースを見た方がはやいような気がします。 

コメントもつけてますし。 

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')

 

プログラムのポイント:HTMLから情報とりだす

ソースのこの部分です。

soup.select('div[class=ranking_table] th')

HTMLの解析には「Beautifulsoup」を使ってます。

www.crummy.com

さきほど確認したように「ranking_tableというクラス名のDIVタグの内側に、取得したいテーブルコンテンツがすべて収まっている」という構造です。

上記の処理では、BeautifulsoupのSelectを使い、クラス名をキーにして、ずぼっとデータを抜いてます。

後続のコードは、そこから行のデータを順次取り出して、EXCELファイルに加工しているだけです。

プログラムのポイント:EXCELを操作する

EXCELの操作は「openpyxl」というpythonのライブラリを使ってやってます。

ソースを読むにあたっては、以下の記事とかの基本的な使い方を参照してもらえると、そんなに難しいことはやってないのでわかると思います。

note.nkmk.me

qiita.com

qiita.com

実行結果イメージ

これを実行して、生成されたEXCELシートはこんな感じです。

f:id:arakan_no_boku:20180111224915j:plain

なかなか良い感じです。 

いちいち、EXCELが立ち上がったりせずに、バックグラウンドで静かにEXCELファイルを作ってくれます。 

処理も速いですしね。 

追加情報:参考になりそうなサイトなど

ちょっとバージョンは古いですが。

kondou.com

EXCELブックの操作の「openpyxl」について、さらに詳しく知りたい場合にそなえて本家のリファレンスのリンクをのせておきます。

(残念ながら英語ですけど)

openpyxl.readthedocs.io

今回はこんな感じで。

ではでは。

#python