アラカン"BOKU"のITな日常

文系システムエンジニアの”BOKU”が勉強したこと、経験したこと、日々思うこと。

pythonでWebスクレイピング(Requests)して、EXCELファイルに書き込み(openpyxl)資料化する

WEBで一覧になっているデータを、そのままEXCELの資料にできたら便利だなとおもうことがよくあります。

 

WEBスクレイピングで必要なデータだけ目的のページから抜き取って、そのままEXCELで一覧表にしたいな・・と。

 

こんな感じで資料に使えそうな表を提供してくれるサイトとかありますからね。

f:id:arakan_no_boku:20180110222920j:plain

 

ということで、やってみます。

 

まず、必要なモジュールをインストール

 

WebからHTMLファイルをダウンロードするモジュールがまず必要です。

 

pip install requests

 

次に、ダウンロードしたHTMLを解析して、必要なデータを抜き出す処理に使うモジュールです。

pip install beautifulsoup4 

 

 最後に、EXCELの読み書きをpythonからやるツールです。

pip install openpyxl

 

とりあえず、これでOKなはずです。

 

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

 

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

ecodb.net

 

このページのランキングの表をEXCELに取り込む対象にします。

 

HTMLを確認するのに、ソースの表示でベタのHTMLを見るのもいいですが、Google Chromeなら、もう少しスマートな方法があります。

 

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

f:id:arakan_no_boku:20180110224838j:plain

 

そうすると、デベロッパーツールが立ち上がってきて、クリックした場所のHTMLをスマートに確認できます。

f:id:arakan_no_boku:20180110225008j:plain

 

とりあえず、シンプルな<table>タグで構成されているみたいです。

 

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

 

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

 

pythonExcelファイルを作る

 

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

 

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

 

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

 

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

f:id:arakan_no_boku:20180111224915j:plain

 

なかなか良い感じです。

 

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

 

処理も速いですしね。

 

追加情報です。

 

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

 

今回は、一番シンプルなセレクタ(select)しか使ってませんが、他にもいろいろ機能はあります。

 

今のところ、日本語で一番情報が豊富だと自分が思っているサイトのリンクをのせておきます。

kondou.com - Beautiful Soup 4.2.0 Doc. 日本語訳 (2013-11-19最終更新)

 

EXCELブックの操作は、openpyxlです。

 

今回、使った機能だけでも結構なことができますが、他にも、たくさん機能はあるみたいですので、本家のリファレンスのリンクをのせておきます(英語です)

openpyxl - A Python library to read/write Excel 2010 xlsx/xlsm files — openpyxl 2.3.3 documentation

 

まあ、今回はこんな感じで。