python: webスクレイピングで検索結果をExcelファイルに書き込む

プログラミング
スポンサーリンク




こんにちは、おみです。

前回、検索結果をCSVに書き込むようにしましたが、CSVよりもExcelの方が使い勝手がいいので、Excelに書き込みを行うように修正します。

スポンサーリンク

機能の説明

検索欄に知りたいことを入力し、searchボタンを押すと

検索結果の上位のwebページが自動で表示され、お気に入りボタンが検索欄の下に作成されます。

お気に入りボタンをクリックするとExcelファイルが作成され、webページのタイトルとURLが書き込まれます。

ソースコード

Excelの操作を行う部分は、太字で示しています。

↓ファイル構造

・Main.py

import tkinter as tk
import os
from src.Model import Model
from src.View import View
from src.Controller import Controller


class Application(tk.Frame):
    def __init__(self, root):
        # スーパークラスのコンストラクタを呼び出し
        super().__init__(root)

        # モデルをインスタンス化
        self.model = Model(root)

        # ビューをインスタンス化
        self.view = View(root, self.model)

        # コントローラーをインスタンス化
        self.controller = Controller(root, self.model, self.view)

        # Viewにメソッドをセット
        # ボタンにメソッドをセット
        self.view.btn_search["command"] = lambda: self.controller.call_btn_clicked()

        # ボタンにカーソルが載っているときにenterキーを押すと、検索するようにする。
        self.view.btn_search.bind("<Return>", lambda event: self.controller.call_btn_clicked())

        # 画面の設定
        root.geometry(str(self.model.width) + "x" + str(self.model.height))
        root.title(self.model.title)


def main():
    root = tk.Tk()
    window = Application(root)
    window.mainloop()


if __name__ == "__main__":
    main()

・Model.py

import configparser as c
import tkinter as tk
import os

# ---------------------------------
# スクレイピング用のモジュールをインポート
# ---------------------------------
# ブラウザ表示用
import urllib
import webbrowser
# HTMLダウンロード用
import requests
# HTML解析用
import bs4

# ---------------------------------
# excel操作用のモジュールをインポート
# ---------------------------------
import openpyxl


class Model(object):
    def __init__(self, root):
        # ---------------------------------
        # 初期設定
        # ---------------------------------
        self.root = root

        # configファイルを読み込み
        self.config = c.ConfigParser()
        self.config.read("config.ini")

        # 画面タイトルを取得
        self.title = self.config["DISPLAY_INFO"]["title"]

        # 画面サイズを取得
        self.width = int(self.config["DISPLAY_INFO"]["width"])
        self.height = int(self.config["DISPLAY_INFO"]["height"])

        # 表示ページ数を取得
        self.pages = self.config["SETTING"]["pages"]

        # 画面パーツに入力した値を格納する変数を宣言
        self.ent_search_text = tk.StringVar()

        # そのた変数を生成
        self.quant = self.pages
        # 検索結果のタイトルとURLを格納するリストを生成する
        self.list_title = []
        self.list_url = []
        # EXCELファイルの情報を生成
        # ファイルパス
        self.result_path = "search_result.xlsx"
        # シート名
        self.sheet_name = "URL一覧"
        # ヘッダー
        self.column_names = ["title", "url"]

    # ボタンクリック時起動メソッド
    def btn_clicked(self):

        # 検索結果一覧のwebページのHTMLを取得する
        search_result = requests.get("https://www.google.com/search?q={}".format((self.ent_search_text.get()))).content

        # 取得したHTMLを使用してBeautifulSoupオブジェクトを生成する
        result_soup = bs4.BeautifulSoup(search_result, "html.parser")

        # 検索結果のtitleを含むdivタグのリストを取得
        title_elems = result_soup.select('div[class="kCrYT"] > a > .BNeawe.vvjwJb.AP7Wnd')

        # 検索結果のurlを含むaタグのリストを取得
        url_elems = result_soup.select('div[class="kCrYT"] > a')

        # 表示する件数を取得
        self.quant = min(int(self.pages), len(url_elems))

        # リストを初期化
        self.list_title = []
        self.list_url = []

        # ブラウザを生成
        browser = webbrowser.get()

        # 指定された件数分検索結果をリストに格納する
        for idx in range(0, self.quant):
            # divタグからタイトルを取得
            title = title_elems[idx].text

            # aタグからurlを取得(日本語はエンコーディングされているので、デコードする)
            url = urllib.parse.unquote(url_elems[idx].get('href').split('&sa=U&')[0].replace('/url?q=', ''))

            # リスト要素を追加
            self.list_title.append(title)
            self.list_url.append(url)

            # urlを指定してwebページを表示
            browser.open(url)

        # 画面のサイズを変更
        self.root.geometry(str(self.width) + "x" + str(self.height + 22 * self.quant))

    # お気に入りボタンクリック時起動メソッド
    def btn_favorite_callback(self, title, url):
        def add_search_result():
            # 検索結果ファイルが存在しない場合、作成する
            if not os.path.exists(self.result_path):
                wb = openpyxl.Workbook()
                sheet = wb.active
                sheet.title = self.sheet_name
                sheet.cell(1, 1).value = "タイトル"
                sheet.cell(1, 2).value = "URL"
                wb.save(self.result_path)

            # 検索位結果シートに新規行を書き込む
            wb = openpyxl.load_workbook(self.result_path)
            sheet = wb[self.sheet_name]
            row = sheet.max_row + 1
            sheet.cell(row, 1).value = title
            sheet.cell(row, 2).value = url
            wb.save(self.result_path)

        return add_search_result

・View.py

import tkinter as tk


class View(object):
    def __init__(self, root, model):
        self.root = root
        self.model = model

        # ---------------------------------
        # 画面の部品を生成
        # ---------------------------------
        # 検索欄ラベル
        self.lbl_search = tk.Label(
            root,
            text="word"
        )

        # 検索欄
        self.ent_search = tk.Entry(
            root,
            textvariable=model.ent_search_text,
            width=30
        )

        # 検索ボタン
        self.btn_search = tk.Button(
            root,
            text="search",
            command=lambda: model.btn_clicked()
        )

        # お気に入りボタン完了リスト
        self.list_favorite_btn = []

        # ---------------------------------
        # 画面の部品を配置
        # ---------------------------------
        self.lbl_search.grid(row=0, column=0)
        self.ent_search.grid(row=0, column=1)
        self.btn_search.grid(row=0, column=2)

・Controller.py

import tkinter as tk


class Controller(object):
    def __init__(self, root, model, view):
        self.root = root
        self.model = model
        self.view = view

    # 検索ボタンクリック時起動メソッドを定義
    def call_btn_clicked(self):
        # 検索結果を表示
        self.model.btn_clicked()

        # 既存のお気に入りボタンをリセット
        for f_btn in self.view.list_favorite_btn:
            f_btn.destroy()

        # お気に入りボタンリストをリセット
        self.view.list_favorite_btn = []

        # 新しいボタンを作成する処理
        for i in range(self.model.quant):
            # ボタンを作成
            btn_favorite = tk.Button(
                self.root,
                text=self.model.list_title[i],
                command=self.model.btn_favorite_callback(self.model.list_title[i], self.model.list_url[i]),
                width=40,
                anchor="w"
            )

            # リストにボタンを追加
            self.view.list_favorite_btn.append(btn_favorite)

            # 新しいボタンを表示
            btn_favorite.grid(row=i + 1, column=0, columnspan=3)

・config.ini

[DISPLAY_INFO]
title = "検索結果取得"
width = 380
height = 30

[SETTING]
pages = 3

Excelの操作を行っている部分の説明

pythonでExcelファイルの操作を行う際は、

 openpyxl

というライブラリを使用します。

・Excelファイルを新規作成する場合

# Workbookオブジェクトを生成する
wb = openpyxl.Workbook()

・既存のExcelファイルを読み込む場合

# Excelファイルを読み込み、Workbookオブジェクトを生成
wb = load_workbook("Excelファイルのパス")

・名前を指定してシートを選択する場合

# wbのシートを取得し、Sheetオブジェクトを生成
sheet = Workbookオブジェクト["シート名"]

・セルに値を書き込む場合

# シート中のセルを選択し、値を書き込む
Sheetオブジェクト.cell(行番号, 列番号).value = 値

行番号・列番号は、配列と違い1から始まります。

・保存を行う場合

# 名前をつけてExcelを保存
wb.save("Excelファイルのパス")

コメント

タイトルとURLをコピーしました