フクカエン DXブログ

フクカエンのDXの取り組みに関する情報を発信しています。

GASとPythonを使ってマーケティングに活用するPDFを自動作成・送信するツールを作成

こんにちは、福花園のIT担当の小野です。

中小企業では、まだまだFAXが業務に欠かせない存在として活用されており、弊社でも受発注業務はFAXがベースとなっています。IT担当としては、FAXを廃止し、デジタル化を推進していきたいと考えていますが、現状では難しいのが実情です。

そんな中、営業部門から過去の購買履歴を分析し、今年まだ購入していないお客様にアプローチしたいという要望がありました。FAXを活用したマーケティングを行うために、IT担当としてできることを考えた結果、Google Apps Script(GAS)とPythonを使って、FAX送信用のPDFを自動生成・送信するツールを開発することにしました。

開発は約1日ほどで完了し、営業部門の業務効率化とお客様との絆を深めるために、非常に有意義な取り組みだったと感じています。同じような課題を抱えている方や、FAXを活用したマーケティングにご興味のある方は、ぜひこの記事を参考に取り組んでみてください。

それでは、このツールの開発プロセスを詳しく見ていきましょう。

課題

まずは今回のプロジェクトの課題を簡単に説明します。

福花園は種苗会社として、多種多様な種と苗を取り扱っています。お客様の中には、直接購入される方もいれば、代理店を通じて購入される方もいるなど、販売チャネルは多岐にわたります。現在使用している販売管理システムは、販売の管理には適していますが、CRMやSFAのようにマーケティングへの活用が困難であるという問題があります。

そこで、販売管理システムに蓄積された顧客データと売上データをエクスポートし、特定の品種を過去に購入したものの、今年は購入していないお客様を抽出する必要がありました。さらに、販売代理店経由の場合は、どのお客様が購入したのかを明確にし、過去の購買履歴とともにFAXシートに記載する必要がありました。しかし、膨大な顧客データと売上データを手作業で分析し、FAXシートを作成するのは非常に時間がかかる上に、ミスが発生するリスクもあります。

そこで、IT部門が中心となって、データの抽出からFAXシートの作成、そして送信までを自動化するツールの開発に着手しました。

制作物

実際に制作をして完成したものはこちらです。

解決策: GASとPythonを活用して、顧客データの抽出、FAX用のPDF自動生成、FAX送信の自動化を行いました。

この課題を解決するために、私たちは3つのステップに分けて取り組みました。

  1. 顧客データの抽出
  2. FAX用のPDF自動生成
  3. FAX送信の自動化

ステップ1と3ではPythonを利用し、ステップ2ではGoogle Apps Script(GAS)を活用しています。それぞれのステップにおける実際の取り組みについて、詳しく説明していきます。

顧客データの抽出

最初のステップは、顧客データの抽出です。過去に購入いただいたお客様がどの品種を購入しているのか、直接購入なのか代理店経由の購入なのか、そして何年に購入されたのかを、マーケティング用のPDFフォーマットに合わせて構造化する必要がありました。

この作業にはGoogle Colabを利用し、以下のようなPythonコードを実装しました。

import pandas as pd

# 販売管理システムからエクスポートした顧客データと売上データを読み込む
customer_data = pd.read_csv('customer_data.csv')
sales_data = pd.read_csv('sales_data.csv')

# 顧客データと売上データを結合
merged_data = pd.merge(customer_data, sales_data, on='customer_id')

# 特定の品種を過去に購入したが、今年は購入していない顧客を抽出
target_customers = merged_data[(merged_data['product'] == '品種A') & (merged_data['year'] < 2023) & (merged_data['year'] != 2022)]

FAX用のPDF自動生成

2つ目のステップは、抽出した顧客データを元に、FAX送信用のPDFを自動生成することです。この処理にはGoogle Apps Script(GAS)を活用しました。

Google Spreadsheetには、特定のシートをPDF化するための機能が備わっています。

GASを使うことで、この機能を自動化し、サイズや余白、縦横などを細かく設定してスプレッドシートをPDFに変換することができます。以下のようなURLを生成するだけで、簡単にPDFを作成できます。(下記はA4サイズで作成した例です)

const url = `https://docs.google.com/spreadsheets/d/${スプレッドシートのID}/export?exportFormat=pdf&format=pdf` +
            `&size=A4` +
            `&portrait=true` +
            `&fitw=true` +
            `&top_margin=0.75&bottom_margin=0.75&left_margin=0.7&right_margin=0.7` +
            `&sheetnames=false&printtitle=false` +
            `&pagenumbers=false&gridlines=false` +
            `&fzr=false` +
            `&gid=${出力対象シートのID}`;

また、PDFの生成リクエストを送る際には、認証トークンが必要になります。このトークンは以下のように生成することができます。

const token = ScriptApp.getOAuthToken();
const options = {
  headers: { 'Authorization': `Bearer ${token}` },
  muteHttpExceptions: true
};

これらのURLとオプションを使ってUrlFetchApp.fetch()を呼び出すことで、PDFをレスポンスとして受け取ることができます。

const response = UrlFetchApp.fetch(url, options);

最後に、受け取ったデータをblobとしてGoogleドライブのフォルダに保存します。

const blob = response.getBlob().setName(`${fileName}.pdf`);
folder.createFile(blob);

これらの一連の処理により、抽出した顧客データを自動的にPDF化し、指定したフォルダに保存することができます。生成されたPDFファイルは、次のステップであるFAX送信の自動化で使用されます。

GASのexportFormat機能を活用することで、スプレッドシートのデータを柔軟にPDFに変換できるようになり、FAX送信用の資料作成が大幅に効率化されました。

工夫した点

PDFの自動生成処理を実装する上で、いくつかの工夫を行いました。

まず、シートにデータを挿入した直後にPDFを生成する際に、前のデータがリフレッシュされないという問題に直面しました。これを解決するために、SpreadsheetApp.flush()を使用してスプレッドシートの変更を即座に反映させるようにしました。さらに、Utilities.sleep(1000)を使って1秒(1000ミリ秒)待機することで、データが確実に反映されるようにしました。

SpreadsheetApp.flush();
Utilities.sleep(1000);

また、大量のPDF生成リクエストを送信する場合、一部のリクエストが失敗することがありました。これに対処するために、リトライ機能を実装しました。リトライ回数を設定し、レスポンスコードが200(成功)でない場合は、一定時間(ここでは5秒)待機してからリクエストを再送信するようにしました。

const retries = 3;
let response;

for (let i = 0; i < retries; i++) {
  response = UrlFetchApp.fetch(url, options);
  
  if (response.getResponseCode() == 200) {
    const blob = response.getBlob().setName(`${fileName}.pdf`);
    folder.createFile(blob);
    break;
  } else {
    Utilities.sleep(5000); // 5秒待つ
  }
}

このリトライ処理により、一時的なネットワークエラーや他の要因によるPDF生成の失敗を回避し、安定したPDF自動生成を実現することができました。

FAX送信の自動化

まず、必要なライブラリをインポートします。データ操作にはpandas、GUI自動化にはpyautogui、ファイル操作にはos、そしてシステムコマンドを実行するためにsubprocessを使用しています。

import pandas as pd
import time
import pyautogui as pgui
import os
import subprocess

次に、スクリプトが配置されているディレクトリの絶対パスを取得し、これを基に他の必要なファイルやディレクトリへのパスを構築します。

base_dir = os.path.abspath(os.path.dirname(__file__))

主要な機能:pyauto 関数

この関数は、CSVファイルfax_customer_list.csvからデータを読み込み、各行を処理してPDFファイルを開き、それに基づいてFAX送信と印刷を自動化します。pandasでファイルを読み込み、得意先コードをキーワードとしてPDFを検索し、それを開いて処理を進めます。

def pyauto(self):
    inve_file_path = os.path.join(base_dir, 'fax_customer_list.csv')
    csv_input_Inve = pd.read_csv(inve_file_path, encoding='cp932', dtype=object)
    directory_path = os.path.join(base_dir, 'pdf')
    for index, row in csv_input_Inve.iterrows():
        file_keyword = str(row['fax送付先コード'])
        print(f"Processing keyword: {file_keyword}")
        self.open_pdf_files(directory_path, file_keyword)

以下のコードブロックは、pyautogui ライブラリを使用してPDFファイルの印刷ダイアログを操作し、FAX番号を入力して文書をFAX送信するプロセスを自動化しています。具体的な手順は次の通りです。
# 印刷ダイアログの操作
pgui.hotkey(‘ctrl’, ‘p’)
time.sleep(0.5)
pgui.hotkey(‘ctrl’, ‘shift’, ‘p’)
time.sleep(0.5)
pgui.press(‘enter’)
time.sleep(1)
# FAX番号を入力
fax_number = row[‘fax番号’] # この部分を必要に応じて変更、またはCSVから取得する
pgui.write(fax_number)
time.sleep(1)
# 送信
pgui.hotkey(‘alt’, ‘i’)
pgui.press(‘enter’)
time.sleep(1) # 送信後少し待つ

  1. 印刷ダイアログ操作: 最初にCtrl + P を押して印刷ダイアログを開きます。次にCtrl + Shift + Pを使って、より詳細なプリンタ設定にアクセスします。Enterを押すことで設定を確認し、印刷ダイアログを進めます。
  2. FAX番号入力: CSVファイルから読み取ったFAX番号を入力します。これにより、文書を送信するFAX番号が指定されます。
  3. 文書送信: Alt + IEnter を使って送信コマンドを実行します。これにより、設定したFAX番号へ文書が送信されます。

PDFファイルの開き方:open_pdf_files 関数

キーワードに完全に一致するPDFファイルをディレクトリから検索し、デフォルトのPDFビューアで開きます。このプロセスは、os.listdirでディレクトリ内を検索し、subprocess.runを使用してファイルを開く方法で行われます。

def open_pdf_files(self, directory, keyword):
    target_filename = f"{keyword}.pdf"
    for filename in os.listdir(directory):
        if filename == target_filename:
            file_path = os.path.join(directory, filename)
            print(f"Opening file: {file_path}")
            subprocess.run(['start', file_path], shell=True, check=True)

工夫した点

このスクリプトでは、pyautoguiを使ってPDFファイルの印刷とFAX送信を自動化していますが、特に工夫した点は各操作間に設定された待ち時間です。GUI操作において、操作間の適切な待ち時間は非常に重要です。これにより、処理の遅延やプログラムの応答性によって生じる潜在的なエラーを防ぐことができます。

待ち時間の役割

  1. プログラムの安定性確保: GUI操作では、一つのアクションが完全に終了してから次のアクションを開始する必要があります。time.sleep()を挿入することで、前の操作がシステムによって完全に処理されるのを待ちます。これにより、ダイアログが開かれるのを待つ、入力が完了するのを待つなど、操作が順序正しく進行します。
  2. エラーの回避: システムやアプリケーションによっては、操作が迅速すぎると正しく処理されない場合があります。特に印刷やFAX送信のようなネットワークやハードウェアを経由する操作では、適切な待ち時間が不具合を防ぎます。
  3. ユーザー介入の最小化: 自動化の目的は手動操作を減らすことです。待ち時間を適切に設定することで、スクリプトが滑らかに実行され、ユーザーがエラーに介入して修正する必要が減ります。

具体的な設定例

  • time.sleep(1)time.sleep(0.5)を使って、印刷ダイアログの開き、設定の適用、FAX番号の入力、最終的な送信コマンドの実行に至るまでの間に短い休止を設けています。これにより、各ステップが確実に完了するのを保証し、次のステップへと安全に進むことができます。

このように、待ち時間を適切に設定することは、pyautoguiを用いた自動化プロセスの信頼性と効率性を向上させるための重要な工夫です。これにより、自動化スクリプトがより堅牢で、使用中に発生する問題を最小限に抑えることが可能となります。

pyautoguiの使用における欠点

pyautoguiは非常に強力なGUI自動化ツールですが、いくつかの欠点も存在します。最も大きな欠点は、自動化スクリプトが実行されている間、そのコンピューターでは他の作業が行えなくなることです。pyautoguiは画面上の要素を直接操作するため、自動化処理中にマウスやキーボードを使用するとスクリプトの動作に影響を与える可能性があります。これにより、自動化タスクを実行している間、ユーザーは他の作業ができないか、非常に制限された操作しかできなくなります。

この問題に対処するためには、自動化処理を夜間や休憩時間など、PCを使用していない時間帯にスケジュールするという方法が考えられます。また、バックグラウンドで動作する他の自動化ツールを検討することも一つの解決策ですが、pyautoguiのように直感的で簡単に設定できる利点は失われる可能性があります。

以上が、このスクリプトで工夫した点とpyautoguiの使用における欠点です。読者の皆さんが自動化プロジェクトを計画する際に、これらの情報が役立つことを願っています。

反響・まとめ

FAX送信用のPDF自動生成・送信ツールを開発・運用した結果、FAXを受け取ったお客様から早速注文が入るなど、ポジティブな反響がありました。とても嬉しく思います。また、社内の他部門からもオンライン化の要望が寄せられるなど、ツールの有用性が認識されました。

しかし、現状のツールはIT部門しか触ることができず、営業部門から都度相談を受ける体制になっているという課題があります。今後は、ツールのデザイン性や使いやすさを向上させ、誰もがマーケティングに活用できるようなツールへと進化させたいと考えています。

IT部門では、今回のプロジェクトで得られた知見とノウハウを活かし、各部門と連携しながら、福花園全体のデジタルトランスフォーメーションを推進していく方針です。