「Pythonで自動化ツールを作れたのに、納品したら売上も終わった」
受託開発で起こりやすい問題です。しかし、顧客が本当に欲しいのはPythonコードではありません。
- 毎朝9時に競合価格レポートが届く
- 在庫切れを30分以内に検知できる
- 毎週3時間かかっていた集計が15分で終わる
- エラーが発生しても、翌営業日までに原因が分かる
こうした「業務が止まらず、成果が継続する状態」に対して企業はお金を払います。
そこで狙うのが、次の3段階です。
単発の自動化案件
↓
監視・修正・レポートを含む月額保守
↓
複数社へ提供できる自社サービス
この記事では、価格調査・在庫監視・レポート作成などのPython業務自動化を、単発副業で終わらせず、月額保守とSaaSへ育てる手順を解説します。
同日公開の「Python×Web操作×ポイ活」の記事とは異なり、ポイント獲得や個人利用の自動化は扱いません。対象は、企業から許可を得て実装する業務システムです。
なお、掲載する金額は設計を理解するためのモデルケースであり、売上や利益を保証するものではありません。
Python業務自動化で売りやすい3種類の案件
初心者が最初から「何でも自動化します」と営業すると、要件が膨らみます。まずは入力と出力が明確な業務に絞ってください。
1. 競合価格の調査
指定された公開ページや許可済みAPIから、商品名、価格、送料、在庫状態、確認日時を取得します。
納品物はスクレイピングコードではなく、次のように定義します。
毎朝8時までに50商品の価格を取得し、前日から5%以上変動した商品だけを担当者へ通知する。
「ページを取得する」ではなく、「担当者が確認すべき変化だけを届ける」のが商品です。
2. 在庫・掲載状態の監視
商品ページ、求人情報、物件情報、仕入先カタログなどを定期確認し、状態の変化を通知します。
ただし、取得先の利用規約、契約、robots.txt、アクセス頻度を事前に確認しなければなりません。
robots.txtは自動クライアントへの巡回ルールですが、アクセス許可そのものではありません。RFC 9309にも、robots.txtのルールはアクセス認可の仕組みではないと明記されています。
したがって、企業案件では次の優先順位にします。
- 公式API
- CSVやデータフィード
- 顧客が管理するシステムの画面・DB
- 取得許可を確認したWebページ
- 許可関係が不明なページは対象外
3. 定型レポートの作成
Excel、CSV、メール、社内システムからデータを集め、週報や月報を自動生成します。
この案件は「サイトの画面変更で突然壊れる」というリスクが比較的小さく、初心者でも成功条件を決めやすいのが利点です。
たとえば次の処理です。
売上CSVを読み込む
↓
商品別・支店別に集計
↓
前週比を計算
↓
異常値を抽出
↓
ExcelまたはPDFを出力
↓
担当者へ通知
最初の1件としては、外部サイトを大量巡回する案件より、顧客が所有するCSVやExcelの自動集計をおすすめします。
Hiro運営サイトの実行ログから分かる「保守が必要な理由」
この記事は、存在しない受託実績や売上を作って書いていません。
2026年7月18日、Hiroが運営するauto-ai-blogリポジトリを確認したところ、3媒体のcontent/postsには合計790本のMarkdown記事がありました。
| 媒体 | 確認した記事数 |
|---|---|
| AI・技術 | 304本 |
| ビジネス | 368本 |
| 不動産 | 118本 |
| 合計 | 790本 |
このシステムでは、Pythonが記事生成処理をまとめ、AI CLIで下書きとレビューを行い、Markdownを保存し、GitHub経由で公開工程へ渡します。
重要なのは、記事数よりも失敗時の記録です。同日のgenerator/logs/generate.logでは、次の事象を確認しました。
- Codex CLIによる下書き生成は成功
- Gemini CLIレビューはコマンドライン長の制限で失敗
- 代替のCodex CLIレビューは240秒でタイムアウト
- 別の生成結果は品質ガードが
7/8となり、基準未達で公開処理を停止 - 品質ガードと外部投稿処理に関するテスト5件はすべて成功
これは受託自動化の売上実績ではありません。しかし、「一つの処理が動いたこと」と「業務全体が正常終了したこと」は別だと示す、このサイト固有の一次情報です。
自動化には、必ず次の3種類の仕事が残ります。
- 外部サービスや画面変更への追従
- タイムアウト、認証切れ、データ欠損への対応
- 出力が業務上正しいかを確認する品質管理
この部分が、月額保守の根拠になります。
ステップ1:自動化する業務を1枚にまとめる
最初の商談でコードの話を始めてはいけません。現在の作業を観察し、業務の入口と出口を定義します。
最低限、次の項目を聞き取ります。
| 確認項目 | 質問例 |
|---|---|
| 現在の作業 | 誰が、何を、どの順番で処理しているか |
| 頻度 | 毎日、毎週、月末など、いつ発生するか |
| 入力 | Web、CSV、Excel、メール、APIのどれか |
| 出力 | Excel、PDF、メール、チャット通知のどれか |
| 作業時間 | 1回に何分かかっているか |
| 判断箇所 | 人間の判断が必要なのはどこか |
| 失敗時の影響 | 遅延、誤発注、機会損失など何が起こるか |
| 完了条件 | 何を確認したら業務完了といえるか |
作業時間は感覚で答えてもらうだけでなく、可能なら3回計測します。外れ値の影響を減らすため、3回の中央値を基準にします。
たとえば「毎週3時間」と聞いても、内訳が次のように分かれることがあります。
ファイルの回収:20分
データの整形:60分
集計:30分
異常値の確認:40分
レポート作成:30分
この場合、すべてを自動化する必要はありません。まずデータ整形と集計だけを対象にすれば、判断部分を人間に残したまま大きな時間削減を狙えます。
ステップ2:2週間以内で検証できるPoCに絞る
PoCは「小さい完成品」です。機能をたくさん見せるデモではありません。
初心者は、次の条件を満たす案件を選んでください。
- データの取得元が1種類
- 出力形式が1種類
- 対象件数が決まっている
- 顧客から取得許可を得られる
- 正解データを人間が確認できる
- 失敗しても発注や送金が自動実行されない
たとえば価格監視なら、最初から1万商品を監視しません。
10商品を1日1回確認し、価格変動をCSVへ記録する。1週間、人間の確認結果と比較する。
この範囲なら、取得精度、処理時間、ページ変更への弱さを確認できます。
PoCの合格条件も契約前に決めます。
対象10商品のうち、9商品以上を正常取得
価格の誤認識は0件
欠損時は空欄で保存し、異常通知を送る
同じ商品を重複登録しない
実行日時と参照URLをログに残す
取得できなかった値を0円として保存してはいけません。「価格がゼロ」と「取得失敗」を区別するため、Noneや取得失敗という状態を使います。
ステップ3:止まることを前提にPythonを実装する
最小構成は、次の5層に分けます。
取得
↓
検証
↓
保存
↓
通知
↓
監視ログ
一つの長いPythonファイルに全部を書くと、取得先が変わっただけで通知処理まで壊れます。処理の責任を分けることで、修正範囲を限定できます。
データには、最低限これだけの項目を持たせます。
record = {
"source_id": "supplier-a",
"item_id": "ABC-001",
"price": 12800,
"stock_status": "in_stock",
"source_url": "https://example.com/items/ABC-001",
"checked_at": "2026-07-18T08:00:00+09:00",
"status": "success",
"error_type": None,
}
Web画面の操作が必要で、かつ顧客と取得先から許可を得ている場合はPlaywrightを利用できます。
Playwrightは、クリック前に対象要素の表示、安定性、有効状態などを確認し、条件が整うまで自動で待機します。時間内に条件を満たせなければTimeoutErrorになります。Playwright公式のAuto-waiting
from playwright.sync_api import sync_playwright, expect
with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
page = browser.new_page()
page.goto("https://example.com/products")
heading = page.get_by_role("heading", name="商品一覧")
expect(heading).to_be_visible()
rows = page.get_by_role("row")
row_count = rows.count()
if row_count < 2:
raise ValueError("商品データが取得できません")
browser.close()
div:nth-child(5)のような位置依存の指定より、get_by_role()やget_by_label()を優先します。画面上での意味に近いLocatorは、単純なCSS階層より変更に耐えやすい設計です。Playwright公式Locatorガイド
ステップ4:「動いた」ではなく業務上の成功を判定する
ブラウザが起動しただけでは成功ではありません。ファイルを作成できても、中身が空なら失敗です。
成功判定を3段階に分けます。
技術的成功
- プログラムが終了コード0で完了した
- 例外が発生していない
- 出力ファイルが存在する
データ上の成功
- 取得件数が想定範囲内
- 必須項目に欠損がない
- 重複データがない
- 前回値と比較して異常な変化がない
業務上の成功
- 担当者が必要とする時刻までに届いた
- 人間の確認結果と一致した
- 判断に必要な情報がそろっている
- 次の業務が問題なく開始できた
ログには、パスワードやCookieを含めず、次の項目を残します。
run_id
開始・終了時刻
対象データ数
成功件数
失敗件数
処理段階
例外の種類
再試行回数
出力先
設定バージョン
Python標準ライブラリのloggingを使えば、自作モジュールと外部ライブラリのログを同じ流れにまとめられます。Python公式Logging HOWTO
ステップ5:単発料金を「初期構築」と「月額保守」に分ける
価格は、コードの行数ではなく、初期作業と継続作業を分けて計算します。
初期構築費に含めるもの
- 業務ヒアリング
- 取得可否と規約の確認
- PoC
- 本番実装
- テスト
- 操作説明
- 初期導入
- 引き継ぎ資料
月額保守に含めるもの
- 定期実行の監視
- 認証切れの確認
- 軽微な画面変更への対応
- 月次レポート
- バックアップ確認
- 障害の一次調査
- 小規模な設定変更
次は市場相場ではなく、採算確認のためのモデルケースです。
初期構築費:120,000円
月額保守費:30,000円
サーバー・外部API費:顧客実費
保守時間の上限:月3時間
上限を超える改修:別途見積もり
月額3万円に「どんな改修でも無制限」を含めると赤字になります。契約には、保守と追加開発の境界を明記してください。
| 月額保守に含む | 別途見積もり |
|---|---|
| セレクタ1か所の修正 | 取得先サイトの全面改修 |
| 通知先の変更 | 新しい取得先の追加 |
| 軽微な設定変更 | 新機能の開発 |
| 障害の原因調査 | CAPTCHAや多要素認証への新対応 |
| 月次稼働レポート | データベース構造の変更 |
顧客側のパスワード変更やAPI停止など、自分で制御できない原因もあります。対応時間を保証する場合は、「復旧時間」ではなく「一次回答までの時間」を定義する方が現実的です。
ステップ6:月額保守を感覚ではなくKPIで報告する
保守契約が続くかどうかは、「今月も動いていました」ではなく、価値を数字で説明できるかで決まります。
| KPI | 計算方法 | 見るべき問題 |
|---|---|---|
| 稼働成功率 | 正常終了回数÷予定実行回数 | 定期実行が止まっていないか |
| データ取得成功率 | 正常取得件数÷対象件数 | ページ変更やAPI障害がないか |
| 欠損率 | 必須項目の欠損数÷全項目数 | 空データを見逃していないか |
| 誤検知率 | 不要な通知数÷全通知数 | 条件が厳しすぎないか |
| 通知遅延 | 検知時刻から通知時刻まで | 業務上間に合っているか |
| 月間削減時間 | 導入前時間-導入後時間 | 顧客価値が出ているか |
| 月間保守時間 | 調査・修正の実測時間 | 自社側の採算が合うか |
| 障害再発率 | 同一原因の再発件数 | 恒久対策ができているか |
おすすめは、月次報告を1ページにまとめることです。
予定実行:31回
正常終了:30回
失敗:1回
取得成功率:99.2%
削減時間:推定11.5時間
障害原因:取得先の項目名変更
対策:項目検証と異常通知を追加
翌月の改善:取得件数の前週比較を導入
数字には必ず測定条件を付けます。「99.2%」だけを書かず、対象期間、分母、失敗の定義を残してください。
ステップ7:3社目を取る前に自社サービス化を判断する
1社目で作ったコードを、そのままSaaSにしてはいけません。個別仕様が多いまま販売すると、顧客数に比例して保守負担が増えます。
自社サービス化を検討できるのは、次の条件がそろったときです。
- 2〜3社が同じ課題を抱えている
- 入力データを共通形式に変換できる
- 出力の80%以上を共通化できる
- 顧客固有部分を設定ファイルで切り替えられる
- 1社増えても保守時間がほとんど増えない
- 顧客が毎月使う理由がある
- 解約につながる失敗条件を把握している
共通化するのは、処理そのものだけではありません。
顧客別設定
↓
共通の取得インターフェース
↓
共通データ形式
↓
検証ルール
↓
ダッシュボード・通知
顧客固有のURL、通知先、しきい値、実行時刻は設定として外へ出します。
customer_id: client-a
schedule: "08:00"
alert_threshold_percent: 5
notification_channel: email
targets:
- item_id: ABC-001
source_url: https://example.com/items/ABC-001
コードをコピーして顧客ごとに書き換える方式は、SaaSではありません。顧客が増えるほど修正箇所が増えるからです。
よくある失敗と対策
失敗1:作る前に月額保守を約束する
障害頻度が分からない段階で安い月額を提示すると、保守赤字になります。
対策: PoC後に4週間程度の試験運用を行い、障害回数と実測保守時間を確認してから月額を決めます。
失敗2:取得件数がゼロでも成功になる
処理が例外を出さなければ成功、という実装では空のレポートを配信します。
対策: 最小件数、必須項目、前回比を検証し、範囲外なら配信を止めます。
失敗3:固定の待機時間を増やし続ける
time.sleep(10)を追加しても、遅い日は失敗し、速い日は無駄に待ちます。
対策: 要素、URL、レスポンスなど、次へ進める条件を待ちます。固定待機は一時的なデバッグへ限定します。
失敗4:顧客のパスワードをコードへ書く
ソースコード、ログ、バックアップから認証情報が漏れる危険があります。
対策: 環境変数や秘密情報管理サービスを使い、ログやスクリーンショットを公開する前に個人情報をマスキングします。
失敗5:利用規約より技術的可能性を優先する
ログイン回避、CAPTCHA突破、アクセス制限の回避は、企業案件の差別化にはなりません。
対策: API、CSV、正式なデータ提供契約を優先し、許可を確認できない取得先は対象外にします。
失敗6:何でも月額内で修正する
顧客にとっては便利でも、自社側の利益が残りません。
対策: 対応範囲、月間工数上限、一次回答時間、追加開発の定義を契約書と見積書に残します。
「SaaSより受託は効率が悪い」という反論について
受託は顧客ごとの調整が必要で、最初からSaaSを作るより効率が悪いという意見があります。
確かに、個別開発だけを続けると労働集約型になります。ただし、顧客がいない段階でSaaSを作ると、需要のない機能へ時間を使う危険があります。
受託から始める利点は、実際の業務データを見ながら次を学べることです。
- 顧客が本当に困っている工程
- 毎月お金を払う機能
- 壊れやすい取得先
- 必要なサポート水準
- 共通化できる設定
- 解約につながる障害
つまり、受託は単なる売上ではなく、有料の顧客調査でもあります。
ただし、案件で扱ったデータ、コード、業務知識を無断で自社サービスへ転用してはいけません。成果物と知的財産の帰属、再利用可能な汎用部品の範囲を、契約時に明確にしてください。
自動化できない領域と限界
Pythonを使っても、次の問題は消えません。
- 取得元サイトの仕様変更
- APIの終了や料金改定
- CAPTCHAや多要素認証
- 担当者しか判断できない例外
- 元データ自体の誤り
- 規約、契約、個人情報の制約
- 顧客社内の承認遅延
- 売上につながるかという事業判断
そのため、「完全放置」「永久に壊れない」「確実に人件費を削減できる」とは提案しません。
専門家が販売するのは、壊れない魔法ではなく、次の仕組みです。
- 壊れたことを早く検知する
- 誤った出力を配信前に止める
- 原因をログから追跡する
- 人間へ安全に引き継ぐ
- 再発防止策を翌月の運用へ反映する
ここが、安価なスクリプト納品との差別化になります。
まず7日間で行うこと
記事を読んだだけでは案件になりません。今週中に、次の順番で1つの業務を形にしてください。
- 身近な企業業務から、週1回以上繰り返す作業を3つ書き出す
- 作業時間を3回計測する
- 入力、出力、人間の判断箇所を整理する
- 取得許可と利用条件を確認する
- 10件だけ処理できるPoCを作る
- 正解データと比較し、取得精度を測る
- 初期構築、月額保守、追加開発の境界を1枚にまとめる
最初の目標は、立派なSaaSを公開することではありません。
1社の、1つの反復業務を、安全に、測定可能な形で短縮する。
この実績ができれば、単発のPython副業を月額保守へ変えられます。さらに複数社で共通する部分が見えた段階で、初めて自社サービス化を検討します。
「コードを売る」のではなく、「止まらずに成果が届く運用」を売る。それが、受託案件を継続収益へ育てる最短ルートです。