﻿GeminiとはじめるPython仕事自動化プログラミング


掲載リスト


リスト1-1
import csv


# 1. ファイルを読み込む
data = []
with open('sales.csv', 'r') as f:
    reader = csv.reader(f)
    for row in reader:
        data.append(row)


# 2. 計算する
total = 0
for item in data:
    price = int(item[1])
    tax_included = price * 1.1  # 消費税10%
    total += tax_included


# 3. 結果を表示する
print(f"合計金額（税込）は {total} 円です。")


リスト1-2
import csv


def load_sales_data(file_path):
    """CSVファイルを読み込み、データのリストを返します。"""
    data = []
    try:
        with open(file_path, 'r') as f:
            reader = csv.reader(f)
            for row in reader:
                data.append(row)
        return data
    except FileNotFoundError:
        print("エラー：ファイルが見つかりません。")
        return []


def calculate_total_with_tax(data, tax_rate=0.1):
    """データを受け取り、指定された税率を加えて合計を計算します。"""
    total = 0
    for item in data:
        price = int(item[1])
        total += price * (1 + tax_rate)
    return total


def display_result(total):
    """計算結果をユーザーに見やすく表示します。"""
    print("-" * 20)
    print(f"【計算完了】")
    print(f"合計金額（税込）: {int(total):,} 円")
    print("-" * 20)


# --- メインの実行部分 ---
sales_list = load_sales_data('sales.csv')
if sales_list:
    result = calculate_total_with_tax(sales_list, 0.1)
    display_result(result)


リスト1-3
def check_user_permission(user):
    if user.is_active:
        if user.has_login_id:
            if user.role == "admin":
                return "管理者画面へ進めます"
            else:
                return "一般ユーザー画面へ進めます"
        else:
            return "IDがありません"
    else:
        return "アカウントが無効です"


リスト1-4
def check_user_permission(user):
    # ガード句：ダメな条件から先に処理して追い返す
    if not user.is_active:
        return "アカウントが無効です"
    
    if not user.has_login_id:
        return "IDがありません"
    
    # ここまで来れば「アクティブでIDがある」ことが確定している
    if user.role == "admin":
        return "管理者画面へ進めます"
    
    return "一般ユーザー画面へ進めます"


リスト1-5
while True: # 正解が出るまで繰り返す
    try:
        # 1. とりあえずやってみる（Try）
        input_value = input("数字を入力してください：")
        number = int(input_value)
        result = 100 / number
        print(f"100 ÷ {number} = {result} です！")
        break # 成功したら繰り返しを抜ける


    except ValueError:
        # 2. 数字以外の文字が入力された場合のエラー対処
        print(f"「{input_value}」は数字ではありません。半角数字で入力してください。")


    except ZeroDivisionError:
        # 3. 0で割り算しようとした場合のエラー対処
        print("0で割ることはできません。他の数字にしてください。")




リスト1-6
# お買い物計算プログラム（バグあり）
price = 1000
discount = 0.1 # 10%引きのつもり
# 本来は 1000 * (1 - 0.1) = 900 にしたい
final_price = price * discount 
print(f"割引後の価格は {final_price} 円です。") # 結果が100円になってしまう！


リスト2-1
【要件定義】
Pythonのpathlibライブラリを使用して、現在の場所に「新規ワークスペース」という名前の新しいフォルダを作成するプログラムを書いてください。
【構成案】
pathlibからPathを読み込む。
フォルダ名を定義し、Pathオブジェクトを作る。
mkdirを使ってフォルダを作成する。すでに存在してもエラーにならない設定にする。


リスト2-2
from pathlib import Path


# フォルダ名を定義
folder_name = "新規ワークスペース"


# Pathオブジェクトを作成
new_folder_path = Path(folder_name)


# フォルダを作成（すでに存在してもエラーにならないようにする）
new_folder_path.mkdir(exist_ok=True)


print(f"フォルダ '{new_folder_path.resolve()}' が作成されました。")


リスト2-3
【要件定義】
実行した日の日付（年-月-日）を取得し、その後に「_重要書類」と付いたフォルダを自動作成するスクリプトを作成してください。
【構成案】
datetimeライブラリで今日の日付を取得し、文字列に変換する。
フォルダ名を作成する。
そのフォルダが「すでに存在するか」をチェックしてから作成する。


リスト2-4
from pathlib import Path
from datetime import datetime


# 1. 今日の日付を取得して、フォルダ名に適した形（2026-03-27）に整えます
today_str = datetime.now().strftime("%Y-%m-%d")
new_folder_name = f"{today_str}_重要書類"


# 2. 作成する場所の情報を設定します
target_dir = Path(new_folder_name)


# 3. フォルダがまだ存在しない場合だけ作成処理を行います
if not target_dir.exists():
    target_dir.mkdir()
    print(f"新しく「{new_folder_name}」を作成しました。")
else:
    # すでにあった場合はメッセージだけ出します
    print(f"「{new_folder_name}」はすでに存在するため、作成をスキップしました。")


# 4. 最後に、そのフォルダの完全な住所（絶対パス）を表示して確認します
print(f"作成場所のフルパス: {target_dir.absolute()}")


リスト2-5
【要件定義】
新規プロジェクト用のフォルダ構成をワンクリックで作成するプログラムを書いてください。
親フォルダ名を「プロジェクトX」とし、その中に「管理」「技術資料」「納品データ」の3つを作り、さらに「納品データ」の中に「最終版」フォルダを作ってください。
【構成案】
作成したいフォルダのパスをリスト（一覧）で定義する。
forループを使って、リストの中身を順に作成する。
parents=Trueを使い、深い階層も一気に作成できるようにする。


リスト2-6
from pathlib import Path


# 1. 作成したいフォルダ構成をリストにしてまとめます
# 親フォルダ/子フォルダ の形式で記述します
folder_list = [
    "プロジェクトX/管理",
    "プロジェクトX/技術資料",
    "プロジェクトX/納品データ/最終版"
]


print("--- プロジェクト用フォルダの一括作成を開始します ---")


# 2. リストの中身を一つずつ取り出して処理します
for folder_path in folder_list:
    # 文字列をパス情報に変換
    target = Path(folder_path)
    
    # mkdirのオプションをフル活用します
    # parents=True: 親の「プロジェクトX」がなくても自動で作る
    # exist_ok=True: すでにあってもエラーにせず進める
    target.mkdir(parents=True, exist_ok=True)
    
    # どこまで作成できたか表示します
    print(f"チェック完了: {folder_path}")


print("--- すべてのフォルダ準備が整いました。お仕事頑張りましょう！ ---")


リスト2-7
【要件定義】
「old_sample.txt」というファイル名を「fixed_sample.txt」に変更するコードを書いてください。
pathlibのrenameを使用し、ファイル名だけをスマートに差し替える方法でお願いします。


リスト2-8
from pathlib import Path


# 1. 元になるファイルを開きます
original_file = Path("old_sample.txt")


# 2. 名前の部分だけを「fixed_sample.txt」に差し替えた新しい住所を作ります
new_file_path = original_file.with_name("fixed_sample.txt")


# 3. 実際に名前を書き換えます
# 注意：もし old_sample.txt が存在しないとエラーになります
original_file.rename(new_file_path)


print(f"名前を「{new_file_path.name}」に変更しました。")


リスト2-9
【要件定義】
今いるフォルダ内のすべての「.png」ファイルを探し、それらを「image_folder」という名前のフォルダに移動させるプログラムを作成してください。
【構成案】
移動先フォルダがない場合は作成する。
iterdirでファイルを走査し、拡張子が.pngのものを判定する。
renameを使って移動を実行する。


リスト2-10
from pathlib import Path


# 1. 移動先のフォルダを準備します
destination = Path("image_folder")
destination.mkdir(exist_ok=True)


print("画像ファイルの整理を開始します...")


# 2. 今いるフォルダ（Path(".")）の中身を一つずつ調べます
for item in Path(".").iterdir():
    
    # ファイルであり、かつ名前の最後（拡張子）が「.png」であるかチェック
    if item.is_file() and item.suffix == ".png":
        
        # 移動後の新しい住所を作ります（フォルダ名 / 元のファイル名）
        new_path = destination / item.name
        
        # 移動を実行
        item.rename(new_path)
        print(f"移動完了: {item.name} -> {destination}")


print("すべての整理が終了しました。")


リスト2-11
【要件定義】
フォルダ内をスキャンし、ファイル名の中に「temp」という文字列が含まれているファイルだけを自動削除するスクリプトを作成してください。
安全のため、削除する前にそのファイル名を画面に一覧表示し、削除した合計数を最後に報告してください。
【構成案】
カウンター変数を用意する。
iterdirでファイルをループ処理する。
if文で「ファイルであること」と「名前にtempを含むこと」を判定する。
unlinkで削除を実行し、カウントを増やす。


リスト2-12
from pathlib import Path


print("=== 不要ファイルのクリーニングを実行します ===")


# 1. 削除した数を数えるための変数を0で用意します
count = 0


# 2. 今いる場所（カレントディレクトリ）を調べます
current_folder = Path(".")


for target_file in current_folder.iterdir():
    # 判定：それはファイルか？ かつ、名前に「temp」が含まれているか？
    # .lower() を使うことで、「TEMP」や「Temp」も対象にします
    if target_file.is_file() and "temp" in target_file.name.lower():
        
        try:
            print(f"削除中... {target_file.name}")
            
            # 3. ファイルを削除します（ゴミ箱に入らないので注意！）
            target_file.unlink()
            
            # カウントを1つ増やします
            count += 1
            
        except Exception as e:
            # 万が一、使用中のファイルなどで消せなかった場合のエラー回避
            print(f"エラー: {target_file.name} は削除できませんでした。理由: {e}")


# 4. 最終的な結果を表示します
if count > 0:
    print(f"=== 完了：合計 {count} 個のファイルを削除しました。 ===")
else:
    print("削除対象のファイルは見つかりませんでした。")


リスト2-13
【要件定義】
Pythonで「memo.txt」という名前のファイルを作成し、「Pythonで自動化の学習中！」という一文を書き込むプログラムを作成してください。
【構成案】
with open を使用して書き込みモード（'w'）でファイルを開く。
utf-8 エンコーディングを指定する。
write メソッドで文字列を書き込む。


リスト2-14
# 1. 「memo.txt」を書き込みモード('w')で開きます
# encoding="utf-8" を指定することで文字化けを防ぎます
with open("memo.txt", "w", encoding="utf-8") as f:
    
    # 2. ファイルの中に文字を書き込みます
    f.write("Pythonで自動化の学習中！")


# 3. 完了を表示します（withを抜けると自動でファイルは閉じられています）
print("ファイル 'memo.txt' を作成し、メッセージを書き込みました。")


リスト2-15
Geminiへのプロンプト：
【要件定義】
既存の「daily_report.txt」というファイルに、現在の日時と実行メッセージを追記するプログラムを作成してください。
【構成案】
datetime で現在時刻を取得する。
追記モード（'a'）でファイルを開く。
改行コード（\n）を入れて、読みやすく追記する。


リスト2-16
from datetime import datetime


# 1. 現在の時刻を読みやすい形式（2026/03/27 20:40）で取得します
now = datetime.now().strftime("%Y/%m/%d %H:%M")


# 2. 追記モード('a')でファイルを開きます。ファイルがなければ新しく作られます。
with open("daily_report.txt", "a", encoding="utf-8") as f:
    
    # 3. 「時刻：メッセージ」の形式で書き込みます。
    # \n は「改行」を意味する特殊な記号です。
    f.write(f"{now}: プログラムによる自動記録を実行しました。\n")


print("日報に実行ログを追記しました。")


リスト2-17
【要件定義】
「member_list.txt」という名前の、1行に1人ずつ名前が書かれたファイルを読み込み、全員の名前に「様」をつけて「processed_list.txt」という新しいファイルに保存してください。
【構成案】
読み込みモード（'r'）でファイルを開き、readlines() でリスト化する。
空のリストを用意し、ループで各名前に「様」を付け足す。
結果を別のファイルに一括で書き出す。


リスト2-18
# 事前準備：読み込むファイルがないとエラーになるため、仮のリストを作ります
with open("member_list.txt", "w", encoding="utf-8") as f:
    f.write("田中\n佐藤\n鈴木\n")


# 1. 元のファイルを読み込みモード('r')で開きます
with open("member_list.txt", "r", encoding="utf-8") as f:
    # 2. 全ての行を読み込んでリスト（一覧）にします
    lines = f.readlines()


# 3. 新しく書き出すためのファイルを開きます
with open("processed_list.txt", "w", encoding="utf-8") as f:
    for line in lines:
        # strip() を使って、名前の後ろについている不要な改行を取り除きます
        name = line.strip()
        
        # 名前が空っぽでない場合のみ処理します
        if name:
            new_line = name + " 様\n"
            # 4. 「様」を付けた名前を新しいファイルに書き込みます
            f.write(new_line)
            print(f"加工中: {name} → {name} 様")


print("すべての加工が完了し、'processed_list.txt' に保存しました。")


リスト2-19
【要件定義】
顧客の名前、年齢、会員ランクを含む辞書形式のデータを、Pythonのjsonライブラリを使って「customer_data.json」というファイルに保存してください。
日本語が文字化けしないようにし、中身が読みやすいようにインデントを付けてください。
【構成案】
jsonライブラリをインポートする。
保存したい辞書データを作成する。
with open で書き込みモードでファイルを開き、json.dump で保存を実行する。


リスト2-20
import json


# 1. 保存したい顧客データを用意します（Pythonの辞書形式）
customer_info = {
    "ID": "C001",
    "名前": "山田 太郎",
    "年齢": 35,
    "ランク": "ゴールド",
    "興味のある分野": ["Python", "AI", "自動化"]
}


# 2. JSONファイルとして書き込みます
with open("customer_data.json", "w", encoding="utf-8") as f:
    # indent=4 で見やすくし、ensure_ascii=False で日本語をそのまま保存します
    json.dump(customer_info, f, indent=4, ensure_ascii=False)


print("顧客データを構造化して保存しました。")


リスト2-21
【要件定義】
すでに存在する「customer_data.json」を読み込み、新しい顧客（ID: C002）の情報を追加して、上書き保存してください。
もしファイルが存在しない場合は、新しいリストとして作成してください。
【構成案】
pathlib を使ってファイルの存在を確認する。
ファイルがあれば json.load で中身を読み出し、なければ空のリストを作る。
新しい顧客データを append（追加）する。
顧客データは、inputでユーザーから入力してもらう。
json.dump でファイル全体を書き直す。


リスト2-22
import json
from pathlib import Path


file_path = Path("customer_data.json")


print("--- 顧客情報登録システム ---")


# 1. ユーザーからの入力を受け取ります
input_id = input("IDを入力してください（例: C003）: ")
input_name = input("名前を入力してください: ")
input_age = input("年齢を入力してください: ")
input_rank = input("ランクを入力してください（ゴールド/シルバーなど）: ")


# 2. 入力された値を辞書にまとめます
# 年齢は計算や集計に使えるよう、int() で整数に変換しておきます
new_customer = {
    "ID": input_id,
    "名前": input_name,
    "年齢": int(input_age),
    "ランク": input_rank,
    "興味のある分野": []  # 今回は空のリストとして作成
}


# 3. 既存データの読み込み（サンプル5と同様の処理）
if file_path.exists():
    with open(file_path, "r", encoding="utf-8") as f:
        data_list = json.load(f)
else:
    data_list = []


# データが単一の辞書だった場合のリスト化対応
if isinstance(data_list, dict):
    data_list = [data_list]


# 4. 新しいデータを追加して保存
data_list.append(new_customer)


with open(file_path, "w", encoding="utf-8") as f:
    json.dump(data_list, f, indent=4, ensure_ascii=False)


print(f"\n完了: {input_name}様のデータを「{file_path.name}」に登録しました。")


リスト2-23
【要件定義】
複数の顧客データが入ったJSONファイルを読み込み、ユーザーが入力した「顧客ID」に一致する人の「名前」と「ランク」を表示するプログラムを作成してください。
【構成案】
サンプル用のJSONデータ（顧客リスト）れは既に作成したcustomer_data.jsonを再利用する
json.load でファイルを読み込む。
ユーザーからの入力を受け取り、リスト内を検索して一致する情報を表示する。


リスト2-24
import json


# --- 検索ID入力 ---
search_id = input("名前: ")  # 検索したいID


# 1. JSONファイルを読み込んで、Pythonのリストに戻します
with open("customer_data.json", "r", encoding="utf-8") as f:
    data_list = json.load(f)


# 2. リストの中から、IDが一致する人を探します
found = False
for member in data_list:
    if search_id in member["名前"]:
        print(f"【検索結果】 [{member['ランク']}] 名前: {member['名前']}様 ({member['年齢']})")
        found = True
        break


if not found:
    print("指定されたIDの顧客は見つかりませんでした。")


リスト2-25
【要件定義】
顧客リストのJSONファイルを読み込み、特定の「ランク」の顧客だけを抽出して、ランク名 + "_only.json"という名前のファイルに保存するプログラムを作成してください。
また、抽出した人数を最後に表示してください。
【構成案】
抽出するランクはinputで入力する。
顧客データが含まれるJSONファイルを読み込む。
新しいリストを用意し、条件に合うデータだけを append で追加していく。
抽出後のリストを新しいファイルに保存する。


リスト2-26
import json


# 事前準備：ランクを入力
search_rank = input('ランク：')


# 1. 元のデータを読み込みます
with open("customer_data.json", "r", encoding="utf-8") as f:
    all_members = json.load(f)


# 2. VIP会員だけを入れるための空のリストを作ります
vip_list = []


print("条件に合うデータを抽出中...")


# 3. 全員を順番にチェックし、VIPランクの人だけをリストに入れます
for m in all_members:
    if search_rank in m["ランク"]:
        vip_list.append(m)
        print(f"追加: {m['名前']}様")


# 4. 抽出されたVIPリストを、新しいJSONファイルに保存します
with open(f"{search_rank}_only.json", "w", encoding="utf-8") as f:
    json.dump(vip_list, f, indent=4, ensure_ascii=False)


# 5. 結果報告
print("-" * 30)
print(f"完了！{search_rank}会員を {len(vip_list)} 名抽出して保存しました。")


リスト2-27
【要件定義】
指定したフォルダ内にある全てのファイルを対象に、それぞれの更新日時を確認してください。
その日付に基づき、「2026-03-01」のような年月の名前のフォルダを作成し、ファイルをその中へ移動させるプログラムを作成してください。
【構成案】
pathlib と shutil, datetime をインポートする。
iterdir() でファイル一覧を取得し、フォルダは除外する。
stat().st_mtime で更新日を取得し、strftime で「YYYY-MM-DD」形式の文字列にする。
保存先フォルダを作成し、shutil.move で移動させる。


リスト2-28
import shutil
from pathlib import Path
from datetime import datetime


# 1. 整理したいフォルダを指定します（今回は現在のフォルダを対象にします）
target_dir = Path(".")


print("--- 自動ファイル整理を開始します ---")


# 2. フォルダ内のアイテムを一つずつ確認します
for file_path in target_dir.iterdir():
    
    # フォルダ自体を移動させないよう、ファイルのみを対象にします
    if file_path.is_file():
        
        # 3. ファイルの更新日時（タイムスタンプ）を取得します
        mtime = file_path.stat().st_mtime
        
        # 4. コンピュータ用の数字を、人間が見やすい「2026-03」のような形式に変換します
        date_folder_name = datetime.fromtimestamp(mtime).strftime("%Y-%m-%d")
        
        # 5. 移動先のフォルダパスを作ります
        dest_dir = target_dir / date_folder_name
        
        # 6. その日付のフォルダがなければ作成します
        dest_dir.mkdir(exist_ok=True)
        
        # 7. ファイルを新しいフォルダの中へ移動させます
        # shutil.move(元の場所, 移動先)
        shutil.move(str(file_path), str(dest_dir / file_path.name))
        
        print(f"移動完了: {file_path.name} -> {date_folder_name}/")


print("--- すべての整理作業が完了しました！ ---")


リスト3-1
【要件定義】
現在のフォルダにある全ての「.txt」ファイルの中身を読み込み、それらを「merged_all.txt」という1つのファイルに結合するプログラムを作成してください。各ファイルの内容の間には、区切り線を入れてください。
【構成案】
pathlib の glob を使ってテキストファイル一覧を取得する。
with open を使って書き込み用のファイルを作る。
ループで各ファイルを開き、中身を順次書き込んでいく。


リスト3-2
from pathlib import Path


# 1. 保存先のファイルを作成します
with open("merged_all.txt", "w", encoding="utf-8") as outfile:
    # 2. 今のフォルダにある「.txt」ファイルをすべて探し、ループで回します
    for file_path in Path(".").glob("*.txt"):
        # 自分自身（merged_all.txt）を読み込まないように除外します
        if file_path.name == "merged_all.txt":
            continue
            
        # 3. 各ファイルを開いて中身を書き込みます
        outfile.write(f"--- File: {file_path.name} ---\n")
        outfile.write(file_path.read_text(encoding="utf-8") + "\n\n")


print("テキストファイルの統合が完了しました。")


リスト3-3
【要件定義】
フォルダ内にある「user_〇〇.json」という形式のファイルをすべて探し、それらの中身（辞書データ）を1つの大きなリストにまとめて「all_users.json」として保存してください。
【構成案】
json ライブラリと pathlib を使用する。
空のリスト combined_data を用意する。
各ファイルを json.load で読み込み、リストに append する。
最後に json.dump で保存する。


リスト3-4
import json
from pathlib import Path


# 1. 統合後のデータを入れるための空のリストを用意します
combined_data = []


# 2. 「user_」で始まるJSONファイルをすべて探します
for json_file in Path(".").glob("user_*.json"):
    with open(json_file, "r", encoding="utf-8") as f:
        # 3. JSONの中身（辞書）を読み込みます
        data = json.load(f)
        # 4. 用意しておいたリストに追加します
        combined_data.append(data)
        print(f"読み込み完了: {json_file.name}")


# 5. 全データが入ったリストを、新しいJSONファイルとして保存します
with open("all_users.json", "w", encoding="utf-8") as f:
    json.dump(combined_data, f, indent=4, ensure_ascii=False)


print(f"合計 {len(combined_data)} 件のデータを統合しました。")


リスト3-5
{
    "ID": "C001",
    "名前": "山田 太郎",
    "年齢": 35,
    "ランク": "ゴールド",
    "興味のある分野": [
        "Python",
        "AI",
        "自動化"
    ]
}


リスト3-6
【要件定義】
「data.csv」というファイルを読み込み、それを「data.json」という名前のJSONファイルに変換してください。
CSVの1行目はヘッダー（項目名）として扱ってください。


リスト3-7
ID,名前,メールアドレス,部署,役職,入社日,年齢,会員ランク,電話番号,備考
C001,山田 太郎,yamada.t@example.com,営業部,課長,2015/04/01,38,ゴールド,090-1111-2222,リーダーシップあり
C002,佐藤 花子,sato.h@example.com,総務部,係長,2018/10/15,29,シルバー,080-3333-4444,育休明け復帰
C003,鈴木 一郎,suzuki.i@example.com,開発部,主任,2020/02/01,45,ブロンズ,070-5555-6666,Pythonエキスパート
C004,田中 結衣,tanaka.y@example.com,人事部,一般,2022/04/01,24,シルバー,090-7777-8888,採用担当
C005,伊藤 健太,ito.k@example.com,マーケティング部,部長,2010/07/01,52,プラチナ,080-9999-0000,新規事業担当


リスト3-8
import csv
import json


# 1. 変換後のデータを入れるリスト
json_data = []


# 2. CSVファイルを辞書形式で読み込みます
with open("data.csv", "r", encoding="utf-8-sig") as f:
    # DictReaderを使うと、「名前: 田中」のようなペアで読み込めます
    reader = csv.DictReader(f)
    for row in reader:
        json_data.append(row)


# 3. JSONファイルとして保存します
with open("data.json", "w", encoding="utf-8") as f:
    json.dump(json_data, f, indent=4, ensure_ascii=False)


print("CSVからJSONへの変換が完了しました。")


リスト3-9
【要件定義】
JSON形式のリストデータを読み込み、それを「output.csv」という名前で保存してください。
CSVのヘッダー（1行目の項目名）は、JSONのキーから自動的に取得するようにしてください。


リスト3-10
import csv
import json


# 1. JSONデータを読み込みます
with open("data.json", "r", encoding="utf-8") as f:
    data = json.load(f)


# 2. もしデータが空でなければ、CSVへの書き込みを行います
if data:
    # 3. CSVの見出し（ヘッダー）を、最初のデータのキーから取得します
    # 例：{"名前": "田中", "年齢": 20} なら ["名前", "年齢"]
    header = data[0].keys()


    # 4. CSVファイルを作成して書き込みます
    with open("output.csv", "w", encoding="utf-8-sig", newline="") as f:
        # DictWriterを準備し、項目名を教えます
        writer = csv.DictWriter(f, fieldnames=header)
        
        # 見出しを書き込み、続いて全データを書き込みます
        writer.writeheader()
        writer.writerows(data)


print("JSONからCSVへの変換が完了しました。")


リスト3-11
【要件定義】
Shift-JIS（cp932）で保存されている「sjis_data.csv」を読み込み、UTF-8形式の「utf8_data.csv」として保存し直してください。
【構成案】
encoding="cp932" を指定してファイルを開く。
中身をすべて読み込む。
encoding="utf-8" を指定して新しいファイルに書き出す。


 意外と単純ですね。単にCSVファイルを開いて読み込み、文字コードを指定して保存するだけですから、このようにとても短いコードで済みます。
 では、生成されたコードを見てみましょう。


リスト3-12
# 1. 文字化けしやすいShift-JISのファイルを「cp932」を指定して開きます
with open("sjis_data.csv", "r", encoding="cp932") as f:
    content = f.read()


# 2. 読み込んだ内容を、現代の標準である「utf-8」で保存し直します
with open("utf8_data.csv", "w", encoding="utf-8") as f:
    f.write(content)


print("文字コードをShift-JISからUTF-8へ変換しました。")


リスト3-13
【要件定義】
顧客リストの「名前」と「電話番号」に含まれる全角文字を半角にし、前後の余計なスペースを削除してください。
【構成案】
unicodedata ライブラリをインポート。
normalize("NFKC", ...) で文字を正規化する。
strip() で空白を除去。


リスト3-14
 名前 , 電話番号
Ｐｙｔｈｏｎ 太郎,  ０９０ー１２３４ー５６７８
JavaScript ハナコ, 03-９９９－8888
Rubyｻﾁｺ,08-777-７７７


リスト3-15
import csv
import unicodedata


input_file = "input.csv"
output_file = "output.csv"


def clean_text(text):
    if text is None:
        return ""
    
    # 全角英数字・記号を半角/標準形に変換
    text = unicodedata.normalize("NFKC", text)
    
    # 前後の空白を削除
    text = text.strip()
    
    # 文字列中の全角文字を処理
    text = text.replace(" ", "").replace(" ", "").replace("：", ":") \
        .replace("ー","-").replace("＝","=").replace("＊","*") \
        .replace("＠", "@").replace("．", ".").replace("，", ",") \
        .replace("／", "/").replace("＼", "\\").replace("％", "%") \
        .replace("、", ",").replace("。", ".").replace("；", ";") \
        .replace("？", "?").replace("！", "!") 
    
    return text


with open(input_file,"r",encoding="utf-8-sig",newline="") as infile, \
     open(output_file, "w",encoding="utf-8-sig",newline="") as outfile:


    reader = csv.reader(infile)
    writer = csv.writer(outfile)


    for row in reader:
        cleaned_row = [clean_text(cell) for cell in row]
        writer.writerow(cleaned_row)


print(f"変換済みファイルを保存しました: {output_file}")


リスト3-16
【要件定義】
「dirty_members.csv」を読み込み、以下の処理をして「clean_members.csv」に出力してください。
全ての項目の全角英数字を半角にする。
全ての項目の前後の空白を消す。
空の行（データがない行）はスキップする。
ーや＠などの全角記号は半角にする。
【構成案】
csv ライブラリと unicodedata を併用。
for 文でCSVを1行ずつ処理。
内側のループで各セル（項目）に対して正規化と strip() を適用。


リスト3-17
 会員ID , 氏名 , 電話番号 , メールアドレス , 年齢 
 ００１ ,  山田 太郎  , ０９０ー１２３４ー５６７８ , yamada@example.com ,  ２８  
００２ ,佐藤 花子 ,０８０ー９８７６ー５４３２,sato@example.com , ３４


 ００３, 鈴木 一郎 ,  070-1111-2222 , suzuki@example.com,４１
００４ ,高橋 美咲,０９０-３３３３-４４４４ , takahashi@example.com , ２５
  
００５, 伊藤 健 , ０８０ー５５５５ー６６６６ , ito@example.com ,３１
 ００６ , Ｐｙｔｈｏｎ 太郎 ,  090-7777-8888  , python.taro@example.com , ２９ 


リスト3-18
import csv
import unicodedata


# 1. 読み込み元と書き出し先のファイルを準備
input_file = "dirty_members.csv"
output_file = "clean_members.csv"


with open(input_file, "r", encoding="cp932") as f_in, \
     open(output_file, "w", encoding="utf-8", newline="") as f_out:
    
    reader = csv.reader(f_in)
    writer = csv.writer(f_out)
    
    for row in reader:
        # 2. 空行をスキップ
        if not row:
            continue
            
        # 3. 1行の中にある各項目（セル）を順番にクリーニング
        clean_row = []
        for item in row:
            # 正規化して空白を消す
            clean_item = unicodedata.normalize("NFKC", item).strip()
            print(len(clean_item))
            clean_row.append(clean_item)
            
        if not clean_row or len(clean_item) == 0:
            continue


        # 4. 綺麗になった行を新しいファイルに書き込む
        writer.writerow(clean_row)


print(f"データのクリーニングが完了し、{output_file} に保存しました。")


リスト3-19
【要件定義】
顧客データのリスト（JSON形式）を読み込み、Markdownの「表（テーブル）」形式に変換して「report.md」として保存してください。
【構成案】
JSONデータを定義（または読み込み）。
表のヘッダー部分（|名前|年齢|...|）を文字列として作成。
for 文でデータを回し、各行を | で区切って追加していく。


リスト3-20
import json


# 1. 元データ（JSON形式のダミーリスト）
customers = [
    {"名前": "山田 太郎", "年齢": 35, "ランク": "ゴールド"},
    {"名前": "佐藤 花子", "年齢": 28, "ランク": "シルバー"},
    {"名前": "鈴木 一郎", "年齢": 42, "ランク": "ブロンズ"}
]


# 2. Markdownのヘッダーを作成
md_report = "# 顧客一覧レポート\n\n"
md_report += "| 名前 | 年齢 | ランク |\n"
md_report += "| :--- | :--- | :--- |\n" # 左揃えの仕切り線


# 3. データを1行ずつテーブルに追加
for c in customers:
    md_report += f"| {c['名前']} | {c['年齢']} | {c['ランク']} |\n"


# 4. 保存
with open("report.md", "w", encoding="utf-8") as f:
    f.write(md_report)


print("Markdownレポート「report.md」を作成しました。")


リスト3-21
【要件定義】
「todo.md」というファイルにある箇条書きリスト（- で始まる行）をすべて抽出し、Pythonのリスト形式にしてからJSONとして保存してください。
【構成案】
ファイルを1行ずつ読み込む。
startswithで冒頭が"-" あるいは "+", "*" かどうかでリスト行かどうか判定。
記号を除去して strip() で整え、リストに追加する。


リスト3-22
# 今日のやること


- 牛乳を買う
- メールを返信する
+ 会議資料を確認する
* Pythonの課題を進める


メモ:
これは説明文なので、JSONには入りません。


## 明日の予定
- クリーニングを受け取る
+ 本を返却する
* 部屋を掃除する


普通の文章
- 夕食の材料を注文する


リスト3-23
import json


# 1. Markdownファイルを読み込む
with open("todo.md", "r", encoding="utf-8") as f:
    lines = f.readlines()


todo_list = []


# 2. 1行ずつ解析
for line in lines:
    clean_line = line.strip()
    # 箇条書きの記号で始まる行を探す
    if clean_line.startswith(("- ", "+ ", "* ")):
        # 記号の部分（最初の2文字）を消して中身だけを取り出す
        task = clean_line[2:]
        todo_list.append(task)


# 3. JSONとして保存
with open("todo.json", "w", encoding="utf-8") as f:
    json.dump(todo_list, f, indent=4, ensure_ascii=False)


print(f"{len(todo_list)}件のタスクをJSONに変換しました。")


リスト3-24
【要件定義】
Markdown形式の表を読み込み、1行目を「キー（項目名）」とした辞書のリストに変換してください。
表の仕切り線（|---|）の行は無視するように処理してください。
【構成案】
文字列を split("|") で分解する。
最初の行からヘッダー（キー）を取得。
3行目以降の各行を、ヘッダーと組み合わせて辞書にする。


リスト3-25
# 4月1日 商品在庫  
| 商品ID | 単価 | 在庫状況 |  
| :--- | :--- | :--- |  
| P001 | 1500 | あり |  
| P002 | 2300 | 残りわずか |  
| P003 | 800 | なし |  


リスト3-26
import json


input_file = "table_data.md"
output_file = "table_data.json"


# 1. Markdownファイルを読み込む
with open(input_file, "r", encoding="utf-8") as f:
    lines = f.readlines()


table_lines = []


# 2. 表の行だけを取り出す
for line in lines:
    clean_line = line.strip()
    if clean_line.startswith("|"):
        table_lines.append(clean_line)


# 3. ヘッダー行を取得
headers = [h.strip() for h in table_lines[0].split("|") if h.strip()]


result_data = []


# 4. 3行目以降をデータとして処理
for line in table_lines[2:]:
    cols = [c.strip() for c in line.split("|") if c.strip()]
    if len(cols) == len(headers):
        item_dict = dict(zip(headers, cols))
        result_data.append(item_dict)


# 5. JSONファイルに保存
with open(output_file, "w", encoding="utf-8") as f:
    json.dump(result_data, f, indent=4, ensure_ascii=False)


print(f"{len(result_data)}件のデータを {output_file} に保存しました。")


リスト3-27
!pip install pdfplumber


リスト3-28
【要件定義】
「sample_report.pdf」というファイルを読み込み、全てのページのテキストを抽出して画面に表示するプログラムを作成してください。
【構成案】
pdfplumber をインポートする。
open でPDFを開く。
pdf.pages をループで回し、extract_text() で文字を取得する。


リスト3-29
import pdfplumber


# 1. PDFファイルを開きます
with pdfplumber.open("sample_report.pdf") as pdf:
    # 2. 1ページずつ順番に処理します
    for i, page in enumerate(pdf.pages):
        # 3. ページ内の文字をすべて抜き出します
        text = page.extract_text()
        
        print(f"--- {i+1} ページ目の内容 ---")
        print(text)
        print("\n")


リスト3-30
【要件定義】
PDFファイル内の1ページ目にある「表（テーブル）」を抽出し、それをJSON形式で保存するプログラムを作成してください。
【構成案】
extract_table() メソッドを使用する。
抽出されたデータ（リストのリスト）を、見出し付きの辞書形式に変換する。
json.dump で保存する。


リスト3-31
import pdfplumber
import json


# 1. PDFを開き、最初のページを選択します
with pdfplumber.open("report_table.pdf") as pdf:
    first_page = pdf.pages[0]
    
    # 2. ページ内の「表」を自動で見つけて抽出します
    # table は [ ["名前", "点数"], ["田中", "80"], ... ] という形式で取得されます
    table = first_page.extract_table()


    if table:
        # 3. 1行目を見出し、2行目以降をデータとして整理します
        header = table[0]
        rows = table[1:]
    
        structured_data = []
        for row in rows:
            # 項目名と値をセットにした辞書を作ります
            # zipを使うと [項目1, 項目2] と [値1, 値2] をペアにできます
            item = dict(zip(header, row))
            structured_data.append(item)
    
        # 4. JSONとして保存
        with open("table_data.json", "w", encoding="utf-8") as f:
           json.dump(structured_data, f, indent=4, ensure_ascii=False)
        
        print("PDF内の表を構造化データとして抽出しました。")


リスト4-1
!pip install openpyxl


リスト4-2
【要件定義】
Pythonのopenpyxlライブラリを使って、新しいExcelファイルを作成してください。
A1セルに「Hello Python!」、B1セルに「Excel自動化の第一歩」と書き込み、「はじめてのExcel.xlsx」という名前で保存してください。
【構成案】
openpyxlからWorkbookをインポートする。
Workbook()で新規ブックを作成。
activeで現在のシートを取得。
セル番地を指定して値を代入。
save()でファイルを保存。


リスト4-3
from openpyxl import Workbook


# 1. 新しいワークブック（Excelファイル）を作成します
wb = Workbook()


# 2. 現在開いているアクティブなシートを選択します
ws = wb.active


# 3. 指定したセルに文字を入力します
ws["A1"] = "Hello Python!"
ws["B1"] = "Excel自動化の第一歩"


# 4. ファイルに名前をつけて保存します
wb.save("はじめてのExcel.xlsx")


print("Excelファイル「はじめてのExcel.xlsx」を作成しました。")


リスト4-4
【要件定義】
3人分の「氏名」と「点数」のデータ（リスト形式）を、Excelシートに書き込むプログラムを作成してください。
1行目には「名前」「得点」という見出しを付け、2行目以降にデータを流し込んでください。
ファイル名は「成績表.xlsx」とします。
【構成案】
データのリスト [['田中', 80], ['佐藤', 95], ['鈴木', 70]] を用意。
ws.append() を使って、1行ずつまとめて書き込む。
for文を使ってデータを効率的に処理する。


リスト4-5
from openpyxl import Workbook


# 1. 書き込みたいデータのリスト（名簿）を用意します
data = [
    ["名前", "得点"],  # 1行目（ヘッダー）
    ["田中", 80],      # 2行目
    ["佐藤", 95],      # 3行目
    ["鈴木", 70]       # 4行目
]


# 2. 新規ブックとシートを準備します
wb = Workbook()
ws = wb.active
ws.title = "成績一覧" # シートの名前を「成績一覧」に変更します


# 3. appendメソッドを使って、1行ずつまとめて書き込みます
# dataの中身（各リスト）が、Excelの1行分として順番に追加されます
for row in data:
    ws.append(row)


# 4. 保存して終了です
wb.save("成績表.xlsx")


print("成績表.xlsx の作成が完了しました。")


リスト4-6
【要件定義】
「商品ID」「商品名」「単価」「在庫数」のデータ（リスト形式）を、Excelシートに書き込むプログラムを作成してください。
書き出す範囲のレンジを取得し、繰り返しを使って各セルに値を書き出してください。シート名は「商品データ」に変更してください。
【構成案】
データのリスト（二次元配列）を用意。
ws.title でシート名を変更。
レンジを取得し２重のfor文でリストを回し、各セルに値を設定。


リスト4-7
from openpyxl import Workbook


# 新しいExcelブックを作成
wb = Workbook()
ws = wb.active
ws.title = "商品データ"


# 書き込みたいデータ
data = [
    ["商品ID", "商品名", "単価", "在庫数"],
    ["P001", "ノート", 120, 50],
    ["P002", "ペン", 80, 100],
    ["P003", "消しゴム", 60, 70]
]


# レンジを使ってセルにデータを書き込む
for row_cells, row_data in zip(ws["A1:D4"], data):
    for cell, value in zip(row_cells, row_data):
        cell.value = value


# 保存
wb.save("商品データ.xlsx")


print("商品データ.xlsx を作成しました。")


リスト4-8
【要件定義】
以下の手順でExcelを編集してください。
A1からC3の範囲に九九のような計算結果を書き込む。
B2セルの値を「修正」という文字に変更する。
A1:C3のレンジ（3x3の塊）を、そのまま下に2行移動させ、空いた場所にタイトルを記入する。
【構成案】
二重ループと ws.cell() を使って初期レンジを作成。
ws.move_range() を使ってレンジをスライドさせる。
移動後の新しい場所にタイトルを書き込む。


リスト4-9
from openpyxl import Workbook


# 1. 準備
wb = Workbook()
ws = wb.active


# 2. 【レンジの作成】 1行目〜3行目、1列目〜3列目の範囲（A1:C3）に数値を入れます
for r in range(1, 4):
    for c in range(1, 4):
        # row(行)とcolumn(列)を数字で指定してセルに書き込みます
        ws.cell(row=r, column=c, value=r * c)


# 3. 【セルの更新】 レンジ内にある特定のセル（B2）だけを上書きします
ws["B2"] = "修正"


# 4. 【レンジの移動】 A1:C3の塊を、そのまま下に2行移動させます
# rows=2 は下に2行分、cols=0 は左右移動なしを意味します
ws.move_range("A1:C3", rows=2, cols=0)


# 5. 保存
wb.save("レンジ操作デモ.xlsx")


print("レンジの作成・更新・移動が完了しました。")


リスト4-10
【要件定義】
「data.csv」というファイルを読み込み、その内容をすべて保持した新しいExcelファイル「data_converted.xlsx」を作成してください。
【構成案】
csv ライブラリでファイルを開く（utf-8-sig指定）。
openpyxl の Workbook を作成。
csv.reader をループで回し、ws.append() でExcelに書き込む。
保存する。


リスト4-11
import csv
from openpyxl import Workbook


# 1. 新しいExcelブックを用意します
wb = Workbook()
ws = wb.active


# 2. CSVファイルを読み込みモードで開きます
with open("data.csv", "r", encoding="utf-8-sig") as f:
    reader = csv.reader(f)
    
    # 3. CSVの各行をループで取り出し、Excelシートにそのまま追加します
    for row in reader:
        ws.append(row)


# 4. 保存します
wb.save("data_converted.xlsx")


print("CSVからExcelへの基本変換が完了しました。")


リスト4-12
商品ID,商品名,単価,在庫数
P001,ノート,120,50
P002,ペン,80,100
P003,消しゴム,60,70
P004,定規,150,30
P005,付箋,200,45


リスト4-13
【要件定義】
「sales.csv」を読み込み、Excelファイルに変換してください。
その際、1行目（見出し）だけを「背景色：薄い青」「文字：太字」「中央揃え」に装飾してください。
【構成案】
openpyxl.styles から Font, PatternFill, Alignment を読み込む。
通常通り ws.append() でデータを流し込む。
流し込み後、1行目のレンジ（A1から最終列まで）に対してループを回し、書式を適用する。


リスト4-14
import csv
from openpyxl import Workbook
from openpyxl.styles import Font, PatternFill, Alignment


wb = Workbook()
ws = wb.active


# 1. CSVデータの流し込み
with open("sales.csv", "r", encoding="utf-8-sig") as f:
    for row in csv.reader(f):
        ws.append(row)


# 2. 1行目（見出しレンジ）の装飾設定
header_font = Font(bold=True, color="FFFFFF") # 白文字、太字
header_fill = PatternFill(start_color="4F81BD", end_color="4F81BD", fill_type="solid") # 青背景
header_alignment = Alignment(horizontal="center") # 中央揃え


# 3. 1行目の各セルに対して装飾を適用します
# max_column はデータが入っている最後の列番号を自動で返してくれます
for col_num in range(1, ws.max_column + 1):
    cell = ws.cell(row=1, column=col_num)
    cell.font = header_font
    cell.fill = header_fill
    cell.alignment = header_alignment


wb.save("見やすい売上表.xlsx")
print("装飾付きのExcelファイルを生成しました。")


リスト4-15
日付,商品名,担当者,販売数,単価,売上金額
2025-04-01,ノート,田中,10,120,1200
2025-04-01,ペン,佐藤,15,80,1200
2025-04-02,消しゴム,鈴木,8,60,480
2025-04-02,定規,高橋,5,150,750
2025-04-03,付箋,伊藤,12,200,2400
2025-04-03,ノート,田中,7,120,840
2025-04-04,ペン,佐藤,20,80,1600
2025-04-04,消しゴム,鈴木,10,60,600


リスト4-16
【要件定義】
「data_folder」内にあるすべてのCSVファイルを検索してください。
それらを1つのExcelファイル「統合レポート.xlsx」にまとめてください。
各CSVの内容は、ファイル名をシート名とした別々のシートに保存してください。
【構成案】
pathlib を使って .csv ファイルを一覧取得する。
最初のシートはデフォルトを使い、2つ目以降は wb.create_sheet() で作成する。
ファイル名から拡張子を除いたものをシート名にする。


リスト4-17        week1_sales.csv
日付,商品名,担当者,販売数,単価,売上金額
2025-04-01,ノート,田中,10,120,1200
2025-04-02,ペン,佐藤,15,80,1200
2025-04-03,消しゴム,鈴木,8,60,480
2025-04-04,定規,高橋,5,150,750
2025-04-05,付箋,伊藤,12,200,2400


リスト4-18        week2_sales.csv
日付,商品名,担当者,販売数,単価,売上金額
2025-04-08,ノート,田中,9,120,1080
2025-04-09,ペン,佐藤,18,80,1440
2025-04-10,消しゴム,鈴木,10,60,600
2025-04-11,定規,高橋,6,150,900
2025-04-12,付箋,伊藤,11,200,2200


リスト4-19        week3_sales.csv
日付,商品名,担当者,販売数,単価,売上金額
2025-04-15,ノート,田中,11,120,1320
2025-04-16,ペン,佐藤,14,80,1120
2025-04-17,消しゴム,鈴木,9,60,540
2025-04-18,定規,高橋,7,150,1050
2025-04-19,付箋,伊藤,13,200,2600


リスト4-20
import csv
from pathlib import Path
from openpyxl import Workbook


# 1. 保存用のブックを作成（最初のシートを準備）
wb = Workbook()
# 最初からあるシートを削除するために一時的に保持
first_sheet = wb.active


print("CSVの統合を開始します...")


# 2. フォルダ内のCSVファイルを1つずつ処理します
csv_files = list(Path("./data_folder").glob("*.csv"))


for i, csv_path in enumerate(csv_files):
    # 3. シート名を作成（ファイル名から .csv を取る）
    sheet_name = csv_path.stem
    
    # 最初の一回目だけは既存のシートを使い、それ以外は新しくシートを作ります
    if i == 0:
        ws = first_sheet
        ws.title = sheet_name
    else:
        ws = wb.create_sheet(title=sheet_name)
    
    # 4. CSVの中身を現在のシートに書き込みます
    with open(csv_path, "r", encoding="utf-8-sig") as f:
        reader = csv.reader(f)
        for row in reader:
            ws.append(row)
    
    print(f"シート「{sheet_name}」を追加しました。")


# 5. 保存して完了
wb.save("統合レポート.xlsx")
print(f"--- 完了：{len(csv_files)} 個のCSVを統合しました ---")


リスト4-21
【要件定義】
「reports」フォルダ内にあるすべてのExcelファイルを読み込み、その内容を1つの新しいExcelファイル「all_data.xlsx」にまとめてください。
各ファイルの1行目は見出しなので、最初のファイル以外は2行目以降（データ部分）だけをコピーしてください。
【構成案】
pathlib でファイル一覧を取得。
load_workbook で各ファイルを開く。
iter_rows(min_row=2) を使い、2行目以降のセルデータを取得して、マスターのシートに append する。


リスト4-22
from pathlib import Path
from openpyxl import load_workbook, Workbook


# 1. 統合先の新しいブックを用意します
new_wb = Workbook()
new_ws = new_wb.active


# 2. reportsフォルダ内の全Excelファイルをループで処理します
for i, file_path in enumerate(Path("./reports").glob("*.xlsx")):
    # 3. ファイルを読み取り専用、データのみ取得モードで開きます
    wb = load_workbook(file_path, data_only=True, read_only=True)
    ws = wb.active
    
    # 4. 1つ目のファイルなら見出し(1行目)から、2つ目以降は2行目から読み込みます
    start_row = 1 if i == 0 else 2
    
    # 5. 指定した行から最終行までを1行ずつ取り出して追加します
    for row in ws.iter_rows(min_row=start_row, values_only=True):
        new_ws.append(row)


# 6. 保存します
new_wb.save("all_data.xlsx")
print("すべてのExcelを統合しました。")


リスト4-23
【要件定義】
各Excelシート内を検索し、「請求金額」という文字が入っているセルを探してください。そのセルの「右隣」にある数値を抽出してください。
また、シート内に「請求金額」が見つからなかった場合は、エラーにせず「未検出」として記録してください。
【構成案】
iter_rows() で全セルをループして「請求金額」という文字列を検索。
見つかったら、cell.offset(row=0, column=1) を使って右隣のセルを取得。
見つかった時点でそのファイルの検索を終了（break）する。


リスト4-24
from pathlib import Path
from openpyxl import load_workbook, Workbook


# 1. 集計用ブックの準備
summary_wb = Workbook()
summary_ws = summary_wb.active
summary_ws.append(["ファイル名", "抽出結果"])


# 2. 各ファイルをスキャン
for file_path in Path("./data_folder").glob("*.xlsx"):
    wb = load_workbook(file_path, data_only=True)
    ws = wb.active
    extracted_value = "未検出" # 初期値


    # 3. シート内の全セルを1つずつチェックします
    for row in ws.iter_rows():
        for cell in row:
            # もしセルの値が「請求金額」だったら
            if cell.value == "請求金額":
                # 4. offsetを使って「0行下、1列右」のセルを取得します
                extracted_value = cell.offset(row=0, column=1).value
                break # 行のループを抜ける
        if extracted_value != "未検出":
            break # 外側のループも抜ける


    # 5. 結果をリストに追加
    summary_ws.append([file_path.name, extracted_value])


# 6. 保存
summary_wb.save("advanced_summary.xlsx")
print("高度な集計が完了しました。")


リスト4-25
【要件定義】
A列に商品名、B列に売上金額が入った表を作成し、それを元にした「棒グラフ」を同じシートに作成してください。
グラフのタイトルは「商品別売上比較」とし、E2セル付近に配置してください。
【構成案】
サンプルデータを ws.append() で書き込む。
Reference でB列の数値範囲を指定する。
BarChart インスタンスを作成し、タイトルを設定。
add_data でデータを追加し、ws.add_chart で貼り付ける。


リスト4-26
from openpyxl import Workbook
from openpyxl.chart import BarChart, Reference


wb = Workbook()
ws = wb.active


# 1. データの準備
rows = [
    ["商品名", "売上"],
    ["リンゴ", 50],
    ["バナナ", 30],
    ["メロン", 80],
    ["イチゴ", 40],
]
for row in rows:
    ws.append(row)


# 2. グラフにする数値データの範囲を指定（B2〜B5）
# titles_from_data=True にすると、範囲の1行目を見出しとして扱います
data = Reference(ws, min_col=2, min_row=1, max_col=2, max_row=5)


# 3. 棒グラフを作成し、タイトルを設定
chart = BarChart()
chart.title = "商品別売上比較"
chart.y_axis.title = "金額（万円）"
chart.x_axis.title = "商品名"


# 4. データを追加してシートに貼り付け
chart.add_data(data, titles_from_data=True)
ws.add_chart(chart, "E2")


wb.save("棒グラフ作成.xlsx")
print("棒グラフを作成しました。")


リスト4-27
【要件定義】
1月から6月までの売上推移を示す折れ線グラフを作成してください。
データは2系列（「A支店」と「B支店」）用意し、比較できるようにしてください。
【構成案】
月、A支店、B支店の3列データを作成。
LineChart を使用。
set_categories を使って、X軸に「月（1月, 2月...）」を表示させる。


リスト4-28
from openpyxl import Workbook
from openpyxl.chart import LineChart, Reference


wb = Workbook()
ws = wb.active


# 1. 2系列の時系列データを用意
data_list = [
    ["月", "A支店", "B支店"],
    ["1月", 100, 120],
    ["2月", 150, 140],
    ["3月", 130, 160],
    ["4月", 180, 150],
    ["5月", 210, 170],
    ["6月", 190, 200],
]
for r in data_list:
    ws.append(r)


# 2. 数値データ（B列〜C列）の範囲を指定
values = Reference(ws, min_col=2, min_row=1, max_col=3, max_row=7)
# 3. X軸のラベル（A列：月）の範囲を指定
cats = Reference(ws, min_col=1, min_row=2, max_row=7)


# 4. 折れ線グラフの作成
chart = LineChart()
chart.title = "支店別売上推移"
chart.style = 13 # グラフのデザインスタイルを番号で指定可能
chart.x_axis.delete = False  # Trueにすると軸（ラベル含む）が消える
chart.y_axis.delete = False
chart.add_data(values, titles_from_data=True)
chart.set_categories(cats) # X軸に月を適用


ws.add_chart(chart, "E2")
wb.save("折れ線グラフ作成.xlsx")
print("折れ線グラフを作成しました。")


リスト4-29
【要件定義】
市場シェアのデータを使って円グラフを作成してください。
各セクションにパーセンテージが表示されるように設定してください。
【構成案】
PieChart を使用。
DataLabelList を使って、グラフ内に値を表示させる設定を加える。


リスト4-30
from openpyxl import Workbook
from openpyxl.chart import PieChart, Reference
from openpyxl.chart.label import DataLabelList


wb = Workbook()
ws = wb.active


# 1. シェアデータ
data = [
    ["会社名", "シェア"],
    ["A社", 40],
    ["B社", 30],
    ["C社", 20],
    ["その他", 10],
]
for row in data:
    ws.append(row)


# 2. 範囲指定
pie_data = Reference(ws, min_col=2, min_row=1, max_row=5)
labels = Reference(ws, min_col=1, min_row=2, max_row=5)


# 3. 円グラフの作成
chart = PieChart()
chart.title = "市場占有率"
chart.add_data(pie_data, titles_from_data=True)
chart.set_categories(labels)


# 4. データラベル（％表示）の追加
chart.dataLabels = DataLabelList()
chart.dataLabels.showPercent = True # パーセントを表示


ws.add_chart(chart, "E2")
wb.save("円グラフ作成.xlsx")
print("円グラフを作成しました。")


リスト4-31
【要件定義】
1から100までの範囲で、ランダムな数値（ダミーデータ）を100個生成してください。 そのデータの分布を示すヒストグラムを作成してください。 グラフのタイトルは「データ分布分析」とし、ビンの設定（階級の幅）が自動で調整されるようにします。
【構成案】
0から100までのランダムな数値を100個生成する。
そのデータを「10点刻み」で集計し、度数分布表を作成する。
集計したデータをもとに、棒グラフ（BarChart）を作成してヒストグラムとして表示する。
棒同士の隙間をなくし、ヒストグラムらしい見た目にする。


リスト4-32
import random
from openpyxl import Workbook
from openpyxl.chart import BarChart, Reference


wb = Workbook()
ws = wb.active
ws.title = "HistogramData"


# 1. 100個のランダムデータを生成（内部で集計するためにリストに保持）
raw_data = [random.randint(0, 100) for _ in range(100)]


# 2. 10点刻みで度数（カウント）を計算
# bins: 0-10, 11-20, ..., 91-100
counts = [0] * 10
for score in raw_data:
    index = min(score // 10, 9) # 
    counts[index] += 1


# 3. 集計データをシートに書き込み
ws.append(["範囲", "頻度"])
labels = ["0-10", "11-20", "21-30", "31-40", "41-50", "51-60", "61-70", "71-80", "81-90", "91-100"]
for label, count in zip(labels, counts):
    ws.append([label, count])


# 4. 棒グラフを作成してヒストグラム風に加工
chart = BarChart()
chart.title = "データ分布（ヒストグラム）"
chart.y_axis.title = "頻度"
chart.x_axis.title = "スコア範囲"


data = Reference(ws, min_col=2, min_row=1, max_row=11)
cats = Reference(ws, min_col=1, min_row=2, max_row=11)
chart.add_data(data, titles_from_data=True)
chart.set_categories(cats)


# 5. ヒストグラムらしく見せるための重要設定：棒の隙間をなくす
chart.gapWidth = 0 


ws.add_chart(chart, "E2")
wb.save("集計ヒストグラム.xlsx")
print("ヒストグラムを作成しました。")


リスト5-1
【要件定義】
文書のタイトルとして「業務自動化のお知らせ」と入れる。
その下に「Pythonを活用して業務を効率化しましょう。」という段落を追加する。
ファイル名を「サンプル通知書.docx」として保存する。
初心者向けに、構造がわかるようなシンプルなコードを作成してください。
【構成案】
Documentオブジェクトの生成: docx.Document()で空の文書を作成する。
タイトルの追加: add_heading()メソッドを使って、見出しレベル0（タイトル）を追加する。
段落の追加: add_paragraph()メソッドを使って、本文となる段落を追加する。
保存: save()メソッドでファイルとして書き出す。


リスト 5-2
import docx


# 1. 新しいドキュメント（Wordファイル）を作成
doc = docx.Document()


# 2. タイトルを追加（レベル0は最も大きなタイトル）
doc.add_heading('業務自動化のお知らせ', 0)


# 3. 段落を追加
doc.add_paragraph('Pythonを活用して業務を効率化しましょう。')


# 4. ファイルを保存
doc.save('サンプル通知書.docx')


print("Wordファイルが作成されました。")


リスト5-3
【要件定義】
先ほどのコードを修正し、段落の一部だけスタイルを装飾したコードを作成してください。
【構成案】
新しい段落として「今月の目標は 集中力向上 です。」という文章を追加する。
そのうち「集中力向上」の部分だけを【太字】にして、さらに【赤色】に変更したい。
python-docxのRun（ラン）という概念を使った書き方を教えてください。


リスト 5-4
import docx
from docx.shared import RGBColor # 色を指定するための道具


doc = docx.Document()


# 段落を作成し、最初のテキストを入れる
p = doc.add_paragraph('今月の目標は ')


# 段落に「ラン（Run）」を追加する
run = p.add_run('集中力向上')


# 追加したランに対して書式を設定する
run.bold = True  # 太字にする
run.font.color.rgb = RGBColor(255, 0, 0) # 赤色にする


# さらに続きのテキストを同じ段落に追加する
p.add_run(' です。')


doc.save('装飾サンプル.docx')
print("装飾されたWordファイルが作成されました。")


リスト5-5
【要件定義】
先ほどのレポート作成コードを拡張して、構成を整えてください。
【構成案】
タイトルは「AI導入検討案」とする。
「1. 目的」という見出し（レベル1）を追加し、その下に説明文を入れる。
「2. 期待される効果」という見出し（レベル1）を追加し、その下に3つの箇条書き（業務効率化、コスト削減、品質向上）を入れる。
最後に「改ページ」を挿入して、2ページ目を作成する。
ファイル名は「導入検討案.docx」とする。


リスト 5-6
import docx


doc = docx.Document()


# 文書全体のタイトル
doc.add_heading('AI導入検討案', 0)


# 第1セクション：目的
doc.add_heading('1. 目的', 1) # レベル1の見出し追加
doc.add_paragraph('本案は、定型業務の自動化により生産性を高めることを目的とします。')


# 第2セクション：期待される効果
doc.add_heading('2. 期待される効果', 1) # レベル1の見出し追加
doc.add_paragraph('導入により、以下の3点の効果を期待しています。')


# 箇条書きの追加
doc.add_paragraph('業務効率の大幅な向上', style='List Bullet')
doc.add_paragraph('人的ミスの削減とコストカット', style='List Bullet')
doc.add_paragraph('ナレッジ共有による品質の均一化', style='List Bullet')


# 改ページの挿入
doc.add_page_break() # 次のページへと改行する


# 2ページ目の書き込み
doc.add_heading('今後のスケジュール', 1)
doc.add_paragraph('次週よりベンダー選定を開始します。')


doc.save('導入検討案.docx')
print("構成済みのファイルを作成しました。")


リスト5-7
【要件定義】
実務で使える「社内研修のお知らせ」をWordで作成するPythonプログラムを書いてください。
【構成案】
冒頭に「202X年10月1日」と記述し、右寄せにする。
次に「社員各位」と左寄せ（標準）で入れる。
文書の中央に大きく「生成AI活用研修の開催について」というタイトル（レベル0）を入れる。
「標記の件について、以下の通り実施いたします。」という挨拶文を入れる。
「記」という文字を中央揃えにする。
研修の日時、場所、講師の3点を箇条書きにする。
最後に「以上」を右寄せにする。
ファイル名は「研修開催通知.docx」とする。


リスト 5-8
import docx
from docx.enum.text import WD_ALIGN_PARAGRAPH # 配置設定用の機能をインポート


doc = docx.Document()


# 1. 日付を右寄せで追加
p_date = doc.add_paragraph('202X年10月1日') # 段落を作成
p_date.alignment = WD_ALIGN_PARAGRAPH.RIGHT # 右寄せに設定


# 2. 宛名
doc.add_paragraph('社員各位')


# 3. タイトルを中央揃えにする
title = doc.add_heading('生成AI活用研修の開催について', 0) # タイトルを作成
title.alignment = WD_ALIGN_PARAGRAPH.CENTER # 中央揃えに設定


# 4. 挨拶文
doc.add_paragraph('標記の件について、以下の通り実施いたします。ご多忙の折とは存じますが、万障お繰り合わせの上、ご参加ください。')


# 5. 「記」を中央揃え
p_ki = doc.add_paragraph('記')
p_ki.alignment = WD_ALIGN_PARAGRAPH.CENTER


# 6. 詳細情報を箇条書きで追加
doc.add_paragraph('日時：202X年10月15日 14:00〜16:00', style='List Bullet')
doc.add_paragraph('場所：第1会議室 および Zoomオンライン', style='List Bullet')
doc.add_paragraph('講師：DX推進部 担当者', style='List Bullet')


# 7. 最後に「以上」を右寄せ
p_end = doc.add_paragraph('以上')
p_end.alignment = WD_ALIGN_PARAGRAPH.RIGHT


# ファイルの保存
doc.save('研修開催通知.docx')
print("実務的な通知書を作成しました。")


リスト5-9
【要件定義】
Pythonのpython-docxを使って、既存のWordファイルを読み込み、文字を置換してドキュメントを完成させてください。
【構成案】
「テンプレート.docx」を読み込む。
文書内の各段落をチェックし、もし「{{name}}」という文字列があれば「山田 太郎」に置換する。
置換後の結果を「返信メール_山田様.docx」として保存する。


リスト 5-10
import docx


# 1. 既存のテンプレートファイルを読み込む
doc = docx.Document('template.docx')


# 2. 全ての段落を一つずつ確認するループ
for p in doc.paragraphs:
    # もし段落の中に「{{name}}」という文字が含まれていたら
    if '{{name}}' in p.text:
        # 段落全体のテキストを、置換後の文字に書き換える
        p.text = p.text.replace('{{name}}', '山田 太郎')


# 3. 別名で保存する
doc.save('返信メール_山田様.docx')
print("置換が完了しました。")


リスト5-11
【要件定義】
Wordのテンプレートとなるファイルを読み込み、検索文字を置換してください。Wordのテンプレートを置換する際、太字やフォントサイズなどの「書式」を崩さないように注意してください。
【構成案】
段落（paragraph）ではなく、ラン（run）をループで回して置換する方法を考えてください。
「{{company}}」を「株式会社デジタル推進」に、「{{date}}」を「202X年12月1日」に置換する。
各Runの装飾を維持したまま、テキストだけを書き換えるコードにしてください。


リスト5-12
契約書 
会社名：{{company}} 
契約日：{{date}} 
このたび、{{company}} と乙は、{{date}} 付で契約を締結する。 


リスト5-13
import docx


doc = docx.Document('contract_template.docx')


# 段落をループ
for p in doc.paragraphs:
    # さらにその段落内の「ラン（Run）」をループ
    for run in p.runs:
        # ランのテキストにキーワードが含まれているかチェック
        if '{{company}}' in run.text:
            run.text = run.text.replace('{{company}}', '株式会社デジタル推進')
        
        if '{{date}}' in run.text:
            run.text = run.text.replace('{{date}}', '202X年12月1日')


doc.save('作成済契約書.docx')
print("書式を維持したまま置換が完了しました。")


リスト5-14
【要件定義】
「application_template.docx」ファイルを読み込み、{{}}で囲われた複数の置換項目を効率よく置換処理してください。
【構成案】
置換したいキーワード（{{key}}）と、新しい値（value）を「辞書形式」で定義する。
辞書には「氏名」「住所」「電話番号」「有効期限」の4つを入れる。
プログラムは、文書内のすべての段落をスキャンし、辞書にあるキーワードをすべて置換する。
最後に「個人情報設定済_書類.docx」として保存する。


リスト5-15
各種情報変更申請書 


申請日：2026年5月15日 


下記のとおり、登録情報の申請を行います。 


【申請者情報】  
氏名：{{氏名}}  
住所：{{住所}}  
電話番号：{{電話番号}} 


【申請情報】 有効期限：{{有効期限}} 


私は、上記内容に相違ないことを確認し、必要な申請手続きを依頼します。 


署名：____________________ 


リスト 5-16
import docx


# 1. 置換したいデータのリスト（辞書）を作成
replacements = {
    '{{氏名}}': '佐藤 一郎',
    '{{住所}}': '東京都千代田区1-1-1',
    '{{電話番号}}': '03-1234-5678',
    '{{有効期限}}': '2028年3月末日'
}


doc = docx.Document('application_template.docx')


# 2. 全段落をループ
for p in doc.paragraphs:
    # 3. 辞書の項目を一つずつ取り出して置換処理を行う
    for key, value in replacements.items():
        if key in p.text:
            # 段落内のキーワードを値に書き換える
            p.text = p.text.replace(key, value)


# 4. 表（Table）の中も置換したい場合の処理（応用）
for table in doc.tables:
    for row in table.rows:
        for cell in row.cells:
            for key, value in replacements.items():
                if key in cell.text:
                    cell.text = cell.text.replace(key, value)


doc.save('個人情報設定済_書類.docx')
print("すべての項目の置換が完了しました。")


リスト5-17
【要件定義】
既存のWordファイルを読み込み、ヘッダーとフッターの内容を書き換えるPythonプログラムを教えてください。
【構成案】
「業務マニュアル.docx」を読み込む。
ヘッダーの最初の段落を「株式会社AIソリューション（新社名）」に書き換える。
フッターの最初の段落を「機密情報 - 複製禁止」に書き換える。
「更新済_マニュアル.docx」として保存する。


リスト5-18
import docx


doc = docx.Document('業務マニュアル.docx')


# 1. 最初のセクションを取得
section = doc.sections[0]


# 2. ヘッダーの書き換え
header = section.header
if header.paragraphs:
    header.paragraphs[0].text = '株式会社AIソリューション（新社名）'


# 3. フッターの書き換え
footer = section.footer
if footer.paragraphs:
    footer.paragraphs[0].text = '機密情報 - 複製禁止'


# 4. 保存
doc.save('更新済_マニュアル.docx')
print("ヘッダーとフッターの更新が完了しました。")


リスト5-19
【要件定義】
Word文書の中にある「表（テーブル）」を探して、特定のセルの値を修正したいです。
【構成案】
文書内の最初の表（テーブル）を対象にする。
表の全行をループで回し、1列目が「旧単価」という文字だったら、その右隣（2列目）の値を「3,000円」に書き換える。
ファイルを保存する。


リスト5-20
import docx


doc = docx.Document('見積テンプレート.docx')


# 1. 文書内の最初の表を取得
if doc.tables:
    table = doc.tables[0]
    
    # 2. 表の全行をチェック
    for row in table.rows:
        # 1列目(index 0)のセルを取得
        first_cell_text = row.cells[0].text
        
        # 3. 特定のキーワードが見つかったら、隣のセルを修正
        if '旧単価' in first_cell_text:
            row.cells[1].text = '3,000円'
            print("値を修正しました。")
doc.save('修正済見積書.docx')


リスト5-21
【要件定義】
既存のWordファイルの表に、データを新しい行として追加するプログラムを作成してください。
【構成案】
表の末尾に、新しい行を3行追加する。
各行に「追加項目1」「追加項目2」……とデータを入れる。
追加するセルの文字サイズを10ptに設定する。
Excelから持ってきたリストのデータを元に行を増やす想定で考えてください。


リスト5-22
import docx
from docx.shared import Pt


doc = docx.Document('project_list.docx')
table = doc.tables[0]


# 追加したいデータのリスト（本来はExcelなどから取得する想定）
new_items = ['プロジェクトA', 'プロジェクトB', 'プロジェクトC']


# 1. リストの数だけ行を追加する
for item_name in new_items:
    # 新しい行を一番下に追加
    new_row = table.add_row()
    
    # 2. 追加した行のセルに値を入れ、書式を整える
    cell = new_row.cells[0]
    cell.text = item_name
    
    # セルの中の段落・ランにアクセスしてフォントサイズを調整
    run = cell.paragraphs[0].runs[0]
    run.font.size = Pt(10)


# 3. 保存
doc.save('更新済_プロジェクト一覧.docx')
print(f"{len(new_items)}行のデータを追加しました。")


リスト5-23
【要件定義】
Pythonのopenpyxlとpython-docxを組み合わせて、大量のWordファイルを一括生成したいです。
【構成案】
「顧客リスト.xlsx」のA列（氏名）を読み込む。
各顧客に対して、新しいWord文書を作成する。
文書内に「{{氏名}} 様」という見出しを入れる。
ファイル名を「案内状_{{氏名}}.docx」として保存する。
実行前に「output」というフォルダを作成し、その中に保存するようにしてください。


リスト 5-24
import os
import openpyxl
import docx


# 1. 保存用のフォルダを作成（すでにあってもOK）
os.makedirs('output', exist_ok=True)


# 2. Excelファイルを読み込む
wb = openpyxl.load_workbook('顧客リスト.xlsx')
ws = wb.active


# 3. Excelのデータを1行ずつ処理する
for row in ws.iter_rows(min_row=2, values_only=True):
    name = row[0] # A列の氏名を取得
    
    # 4. 各顧客用のWordドキュメントを作成
    doc = docx.Document()
    doc.add_heading(f'{name} 様', 0)
    doc.add_paragraph('いつもご利用いただき、誠にありがとうございます。')
    
    # 5. outputフォルダ内に、名前を付けて保存
    save_path = os.path.join('output', f'案内状_{name}.docx')
    doc.save(save_path)


print(f"全件の作成が完了しました。outputフォルダを確認してください。")


リスト5-25
【要件定義】
先ほどのプログラムを改良して、Excelの「会員ランク」に応じたメッセージをWordに追加するコードを考えてください。
【構成案】
B列（会員ランク）が「ゴールド」の場合だけ、Wordに「特別クーポン進呈中！」という太字の赤い一文を追加する。
それ以外のランクの場合は、通常の挨拶文だけを入れる。
条件分岐を使って、特定のラン（Run）を装飾するコードにしてください。


リスト5-26
import os
import openpyxl
import docx
from docx.shared import RGBColor


os.makedirs('output_special', exist_ok=True)
wb = openpyxl.load_workbook('顧客リスト.xlsx')
ws = wb.active


for row in ws.iter_rows(min_row=2, values_only=True):
    name, rank = row[0], row[1] # A列とB列を取得
    
    doc = docx.Document()
    doc.add_heading(f'{name} 様', 0)
    p = doc.add_paragraph(f'現在のあなたのランクは「{rank}」です。')
    
    # 会員ランクに応じた条件分岐
    if rank == 'ゴールド':
        # 特別なメッセージを太字・赤色で追加
        run = p.add_run('\n★特別クーポン進呈中！★')
        run.bold = True
        run.font.color.rgb = RGBColor(255, 0, 0)
    
    save_path = os.path.join('output_special', f'案内状_{name}.docx')
    doc.save(save_path)


print("ランク別案内状の作成が完了しました。")


リスト5-27
【要件定義】
Excelのヘッダー名と、Word内の置換タグ（{{...}}）を連動させて、100枚の書類を一括作成する汎用的なスクリプトを書いてください。もっとも効率の良い方法を考えて作ってください。
【構成案】
「テンプレート.docx」というテンプレートを読み込む。
Excelの1行目（ヘッダー）を見て、自動的に置換キーワードのリストを作る。
各行のデータを読み込み、キーワードに合致する箇所をすべて置換する。
置換した結果を、顧客名のファイル名で保存する。


リスト5-28
import os
import openpyxl
import docx


os.makedirs('bulk_result', exist_ok=True)
wb = openpyxl.load_workbook('データ一覧.xlsx')
ws = wb.active


# 1. Excelのヘッダー（1行目）から置換キーワードのリストを作る
headers = [cell.value for cell in ws[1]] # 例: ['氏名', '住所', '期限']


# 2. データ行を1行ずつループ
for row_idx, row in enumerate(ws.iter_rows(min_row=2, values_only=True)):
    # テンプレートを毎回読み込む（初期状態から始めるため）
    doc = docx.Document('テンプレート.docx')
    
    # 3. 列ごとに置換処理を実行
    for col_idx, value in enumerate(row):
        keyword = f'{{{{{headers[col_idx]}}}}}' # 例: {{氏名}} を作成
        
        # 文書内の全段落をスキャンして置換
        for p in doc.paragraphs:
            if keyword in p.text:
                p.text = p.text.replace(keyword, str(value))
                
    # ファイル名として使うための「氏名」を取得（0番目の列と想定）
    file_name = row[0]
    doc.save(os.path.join('bulk_result', f'書類_{file_name}.docx'))


print("テンプレートに基づいた一括生成が完了しました！")


リスト5-29
【要件定義】
Pythonで、右上に会社のロゴ画像が入った「感謝状」を作成するコードを作ってください。
【構成案】
文書の冒頭（右上）に 'logo.png' という画像を、幅3センチで挿入する。
その下に中央揃えで「感謝状」と大きく書く。
文末に 'stamp.png' （印影）を幅2センチで挿入し、右寄せにする。
画像挿入には add_picture と Cm を使ってください。


リスト5-30
import docx
from docx.shared import Cm
from docx.enum.text import WD_ALIGN_PARAGRAPH


doc = docx.Document()


# 1. ロゴ画像を右寄せで配置
p_logo = doc.add_paragraph()
p_logo.alignment = WD_ALIGN_PARAGRAPH.RIGHT
run_logo = p_logo.add_run()
run_logo.add_picture('logo.png', width=Cm(3)) # 幅3cmでロゴ挿入


# 2. メインタイトル
title = doc.add_heading('感 謝 状', 1)
title.alignment = WD_ALIGN_PARAGRAPH.CENTER


# 3. 本文
doc.add_paragraph('\n貴殿の多大なる貢献に対し、深く感謝の意を表します。')


# 4. 印影の配置
p_stamp = doc.add_paragraph()
p_stamp.alignment = WD_ALIGN_PARAGRAPH.RIGHT
run_stamp = p_stamp.add_run()
run_stamp.add_picture('stamp.png', width=Cm(2)) # 幅2cmで印影挿入


doc.save('画像入り感謝状.docx')
print("画像入りの書類を作成しました。")


リスト6-1
!pip install requests beautifulsoup4


リスト6-2
【要件定義】
Pythonの requests と BeautifulSoup を使って、Wikipediaの「Python」のページからタイトルを取得するプログラムを作成してください。
【構成案】
対象URLを https://ja.wikipedia.org/wiki/Python に設定する。
requests.get でHTMLを取得する。
BeautifulSoup でHTMLを解析する。
find メソッドを使い、IDが firstHeading である要素を特定する。
その要素のテキスト部分のみをプリントする。


リスト6-3
import requests
from bs4 import BeautifulSoup


# 1. URLを指定してHTMLを取得
url = "https://ja.wikipedia.org/wiki/Python"


# User-Agentヘッダーを追加 (Wikipediaの要件)
headers = {
    "User-Agent": "API Client/1.0 (your_email@example.com)" #★
}


# headersパラメータを追加してリクエストを送信
response = requests.get(url, headers=headers)


# 2. BeautifulSoupで解析
soup = BeautifulSoup(response.text, "html.parser")


# 3. IDを指定してタイトル要素を検索
title_element = soup.find("h1", id="firstHeading")


# 4. テキストを表示
# title_elementが見つかった場合のみ、.textにアクセスする
if title_element:
    print(f"ページタイトル: {title_element.text}")
else:
    print("エラー: ページタイトルが見つかりませんでした。ウェブサイトの構造が変わったか、ページの読み込みに失敗しました。")
    print("デバッグ情報: レスポンスの最初の500文字\n", response.text[:500])


リスト6-4
【要件定義】
Wikipediaのページから、冒頭の概要文（最初の段落）を抽出してください。
【構成案】
input で検索ワードを入力し、そのページのURLにアクセスする。
requests でページを取得し、BeautifulSoup で解析する。
本文全体を包んでいる div タグ（ID: mw-content-text）を探す。
その div の中にある最初の p タグを見つける。
テキストに含まれる余計な空白を .strip() で除去して表示する。
サーバーへの配慮として、インポート文に time を追加し、実行前に1秒待機を入れる。


リスト6-5
import requests
from bs4 import BeautifulSoup


word = input("検索ワード: ")
url = "https://ja.wikipedia.org/wiki/" + word


# User-Agentヘッダーを追加 (Wikipediaの要件)
headers = {
    "User-Agent": "Python Wikipedia API Client/1.0 (your_email@example.com)"
}


# headersパラメータを追加してリクエストを送信
response = requests.get(url, headers=headers)


soup = BeautifulSoup(response.text, "html.parser")


# 本文エリアを特定
content_div = soup.find("div", id="mw-content-text")


# そのエリア内にある最初の段落(p)を探す
# ※Wikipediaの仕様上、空のpタグや非表示のpタグがある場合を考慮
# content_div が None でないことを確認してから find を呼び出す
if content_div:
    first_p = content_div.find("p")


    if first_p:
        # テキストを取り出し、前後の不要な改行や空白を消す
        summary = first_p.text.strip()
        print("【概要の抽出結果】")
        print(summary)
    else:
        print("段落が見つかりませんでした。")
else:
    print("本文エリアが見つかりませんでした。ウェブサイトの構造が変わったか、ページの読み込みに失敗しました。")
    print("デバッグ情報: レスポンスの最初の500文字\n", response.text[:500])


リスト6-6
【要件定義】
Wikipediaの「Python」ページにある「目次（Table of Contents）」の項目名をすべて取得し、Pythonのリストに格納して表示してください。
【構成案】
time.sleep(1) を入れてアクセスし、BeautifulSoup で解析。
目次の各項目を表すクラス名（ vector-toc-text ）を検証機能で特定する。
find_all メソッドを使い、そのクラスを持つすべての要素を取得する。
空のリスト toc_list を作成する。
for 文でループを回し、各要素からテキストを抽出し、1行にまとめてリストに追加する。
最後に、見やすく番号付きで一覧表示する。


リスト6-7
import requests
from bs4 import BeautifulSoup


word = input("検索ワード: ")
url = "https://ja.wikipedia.org/wiki/" + word


# User-Agentヘッダーを追加 (Wikipediaの要件)
headers = {
    "User-Agent": "Python Wikipedia API Client/1.0 (your_email@example.com)"
}


# headersパラメータを追加してリクエストを送信
response = requests.get(url, headers=headers)


# BeautifulSoupで解析
soup = BeautifulSoup(response.text, "html.parser")


# 1. 目次のテキストが含まれるクラスを指定して全取得
# ※Wikipediaの新しいデザインに対応したクラス名を使用
toc_elements = soup.find_all("div", class_="vector-toc-text")


toc_list = [] # データを溜めるための空のリスト


# 2. 取得した要素を一つずつループで処理
for element in toc_elements:
    # 各項目からテキストを取得
    item_text = element.get_text().replace('\n', '').strip()
    
    # 3. テキストが空でなければリストに追加
    if item_text:
        toc_list.append(item_text)


# 4. 結果の表示
print(f"---「{url}」の目次一覧 ---")
for i, item in enumerate(toc_list, 1):
    print(f"{i}: {item}")


# 5. (応用) リストの総数を表示
print(f"\n合計 {len(toc_list)} 個の項目を取得しました。")


リスト6-8
【要件定義】
Wikipedia APIを使い、「Python」のページ概要をJSON形式で取得し、表示してください。
【構成案】
エンドポイントURLを https://ja.wikipedia.org/w/api.php に設定。
辞書形式でパラメータ（action, prop, titles, format等）を用意。
requests.get の params 引数に辞書を渡して実行。
返ってきたJSONから、記事本文のテキストを抽出して表示。


リスト6-9
import requests


word = input("検索ワード: ")


# 1. APIの窓口とパラメータの設定
api_url = "https://ja.wikipedia.org/w/api.php"
params = {
    "action": "query",
    "format": "json",
    "prop": "extracts",
    "titles": word,   # 検索ワード
    "exintro": True,      # 概要のみ
    "explaintext": True,  # テキスト形式で取得
    "redirects": 1        # リダイレクトがあれば従う
}


# User-Agentヘッダーを追加 (Wikipedia APIの要件)
headers = {
    "User-Agent": "Python Wikipedia API Client/1.0 (your_email@example.com)"
}


# 2. リクエスト送信
# headersパラメータを追加
response = requests.get(api_url, params=params, headers=headers)


# エラー診断のために、ステータスコードとレスポンス内容を確認
print(f"HTTP ステータスコード: {response.status_code}")
print(f"レスポンステキストの先頭100文字: {response.text[:100]}")


# レスポンスが成功（200 OK）であり、かつJSONとして解析可能か確認
if response.status_code == 200:
    try:
        data = response.json()


        # 3. JSON構造を掘り進めて本文を取り出す
        # ページのデータは pages > {ページID} > extract の中にある
        # data が 'query' キーを持つことを確認
        if 'query' in data and 'pages' in data['query']:
            pages = data["query"]["pages"]
            # ページが見つからない場合、'-1'というキーが返されることがあるためチェック
            page_id = list(pages.keys())[0]
            if page_id != '-1':
                content = pages[page_id]["extract"]
                print(f"--- Wikipedia API 抽出結果 ---\n{content}")
            else:
                print(f"エラー: 指定されたタイトル '{params['titles']}' のページが見つかりませんでした。")
        else:
            print("エラー: 予期せぬJSON構造です。'query'または'pages'キーが見つかりません。")
            print(f"完全なレスポンスデータ: {data}")


    except requests.exceptions.JSONDecodeError as e:
        print(f"JSONの解析に失敗しました: {e}")
        print("レスポンス内容が有効なJSONではありませんでした。")
        print(f"レスポンステキスト: {response.text}")
else:
    print(f"APIリクエストが失敗しました。ステータスコード: {response.status_code}")
    print(f"レスポンステキスト: {response.text}")


リスト6-10
【要件定義】
Pythonの feedparser を使い、NHKニュースのRSSから最新5件の記事タイトルとURLを取得して表示してください。
【構成案】
feedparser をインポートする。
RSSのURLを https://www.nhk.or.jp/rss/news/cat0.xml に設定する。
feedparser.parse でデータを取得する。
entries リストの最初の5件分を for 文でループする。
各記事の title と link を出力する。


リスト6-11
import feedparser


# 1. NHKニュースの主要ニュースRSS
rss_url = "https://www.nhk.or.jp/rss/news/cat0.xml"


# 2. RSSを解析してデータを取得
feed = feedparser.parse(rss_url)


# 3. 最新5件の記事をループして表示
for entry in feed.entries[:5]:
    print(f"タイトル: {entry.title}")
    print(f"リンク  : {entry.link}")
    print("-" * 30)


リスト6-12
【要件定義】
最新ニュース1件の内容をGeminiに渡し、3つの箇条書きで要約させるプログラムを作成してください。
【構成案】
google.generativeai を設定し、APIキーを適用する。
RSSから最新1件の記事（タイトル、概要、詳細）を取得する。
Geminiへの指示文（プロンプト）を「以下のニュースを3つの箇条書きで短く要約してください」という形式で作る。
model.generate_content で結果を取得し、表示する。


リスト6-13
import feedparser
import google.generativeai as genai
from google.colab import userdata


# 1. APIキーの設定
genai.configure(api_key=userdata.get('GEMINI_API_KEY'))
# 必要に応じて、genai.list_models() で利用可能なモデルを確認できます。
model = genai.GenerativeModel('gemini-2.5-flash')


# 2. ニュース1件を取得
feed = feedparser.parse("https://www.nhk.or.jp/rss/news/cat0.xml")
top_news = feed.entries[0]


# 3. Geminiへのプロンプト作成
prompt = f"""
以下のニュースを3つの箇条書きで短く短く要約してください。


タイトル: {top_news.title}
概要: {top_news.summary}
詳細: {top_news.description}
"""


# 4. AIによる要約実行
response = model.generate_content(prompt)
print(f"元タイトル: {top_news.title}\n")
print(f"【AI要約結果】\n{response.text}")


リスト6-14
【要件定義】
最新のニュース3件を取得し、それぞれを要約した結果を一つのMarkdownファイルとして保存するプログラムを作成してください。
【構成案】
feedparser で最新3件の記事を取得。
各記事に対して「要約」と「ビジネスへの影響度（1-5）」をGeminiに判定させるプロンプトを作る。
結果を溜めるための変数 report_content を用意する。
report_content にMarkdown形式の見出し、要約、リンクを追記していく。
最後に daily_news_report.md という名前で保存する。


リスト6-15
import feedparser
import google.generativeai as genai
from google.colab import userdata
import time


genai.configure(api_key=userdata.get('GEMINI_API_KEY'))


# 利用可能なモデルリストから 'gemini-flash-latest' を選択
model = genai.GenerativeModel('models/gemini-flash-latest')


# 1. ニュース取得（最新3件）
feed = feedparser.parse("https://www.nhk.or.jp/rss/news/cat0.xml")
news_items = feed.entries[:3]


# 2. レポートのヘッダー部分を作成
report_md = "# 本日のAIニュース要約レポート\n\n"


for i, item in enumerate(news_items, 1):
    print(f"{i}件目を処理中...")


    # 3. AIに要約とスコアリングを依頼
    prompt = f"""
以下のニュースを1行で要約し、ビジネスへの影響度を5段階で評価して。
出力は『要約：... / 影響度：...』の形式で。
タイトル:{item.title}
概要:{item.summary}
"""
    response = model.generate_content(prompt)


    # 4. Markdown形式で内容を組み立て
    report_md += f"## {i}. {item.title}\n"
    report_md += f"- **AI分析**: {response.text}\n"
    report_md += f"- [記事を読む]({item.link})\n\n"


    time.sleep(2) # APIの負荷軽減


# 5. Markdownファイルとして保存
with open("daily_news_report.md", "w", encoding="utf-8") as f:
    f.write(report_md)


print("レポートの生成が完了しました：daily_news_report.md")


リスト6-16
【要件定義】
指定されたPDFのURLからファイルをダウンロードし、ローカルに保存するプログラムを作成してください。
【構成案】
保存したいPDFのURL（https://www.soumu.go.jp/main_content/001063943.pdf）を設定する。
requests.get でデータを取得する。
ファイル名を downloaded_sample.pdf とする。
with open(..., "wb") を使い、f.write(response.content) で保存する。


リスト6-17
# 1. ダウンロードしたいファイルのURL
url = "https://www.soumu.go.jp/main_content/001063943.pdf" # 総務省の公開資料


# 2. データをバイナリ形式で取得
response = requests.get(url)


# 3. フォルダの中に「バイナリ書き込みモード」で保存
with open("令和8年版地方財政白書.pdf", "wb") as f:
    f.write(response.content)


print("PDFファイルの保存が完了しました。")


リスト6-18
【要件定義】
指定したWebページ（例：Wikimedia commonsのページ）に含まれるすべての画像を、自動的に作成した "downloaded_images_api_検索ワード" フォルダに保存するプログラムを作成してください。
【構成案】
Wikimedia commonsのAPI（https://commons.wikimedia.org/w/api.php）にアクセスして検索する。
os モジュールでフォルダ作成を行う。
結果をJSONデータとして受け取る。
繰り返しを使い、JSONから順にデータを取り出し処理する。
取得したURLが .jpg や .png で終わるかチェックし、イメージファイルのみをダウンロードし保存する。


リスト6-19
import requests
import os
from pathlib import Path
from urllib.parse import unquote # 追加


word = input("検索ワード: ")


# 1. Wikimedia APIのエンドポイントとパラメータを設定
API_ENDPOINT = "https://commons.wikimedia.org/w/api.php"
params = {
    "action": "query",
    "format": "json",
    "generator": "search",
    "gsrsearch": word,  # 検索ワード
    "gsrnamespace": 6,  # File名前空間 (画像ファイル)
    "gsrlimit": 10,     # 取得する画像の数
    "prop": "imageinfo",
    "iiprop": "url",    # 画像の直接URLを取得
    "redirects": 1        # リダイレクトがあれば従う
}


# User-Agentヘッダーを追加 (API利用の推奨事項)
headers = {
    "User-Agent": "Python Wikimedia API Client/1.0 (example@mail.com)" # メールアドレスを指定
}


save_dir = f"downloaded_images_api_{word}"
os.makedirs(save_dir, exist_ok=True)


print(f"--- Wikimedia APIで '{word}' の画像を検索・ダウンロードします ---")


try:
    # APIリクエストを送信
    response = requests.get(API_ENDPOINT, params=params, headers=headers)
    response.raise_for_status() # HTTPエラーがあれば例外を発生させる
    data = response.json()


    if "query" in data and "pages" in data["query"]:
        pages = data["query"]["pages"]
        download_count = 0
        for page_id, page_info in pages.items():
            if "imageinfo" in page_info and page_info["imageinfo"]:
                image_url = page_info["imageinfo"][0]["url"]
                file_name_encoded = Path(image_url).name # エンコードされたファイル名
                file_name = unquote(file_name_encoded) # デコードする
                file_path = os.path.join(save_dir, file_name)


                # 画像ファイル拡張子でフィルタリング
                if file_name.lower().endswith(('.png', '.jpg', '.jpeg', '.gif')):
                    print(f"  画像URL: {image_url}")
                    print(f"  ファイル名: {file_name}")


                    # 画像ファイルをダウンロード
                    img_response = requests.get(image_url, headers=headers, stream=True)
                    img_response.raise_for_status() # ダウンロード中のエラーもチェック


                    with open(file_path, "wb") as f:
                        for chunk in img_response.iter_content(chunk_size=8192):
                            f.write(chunk)
                    print(f"  保存完了: {file_path}\n")
                    download_count += 1


        print(f"--- 合計 {download_count} 個の画像をダウンロードしました ---\n")
    else:
        print("画像が見つかりませんでした。別のキーワードでお試しください。")


except requests.exceptions.RequestException as e:
    print(f"APIリクエストエラーが発生しました: {e}")
except Exception as e:
    print(f"予期せぬエラーが発生しました: {e}")


print("全ての処理が終了しました。")


リスト6-20
【要件定義】
Pythonで、arXivを検索して論文候補を取得し、タイトル・概要・PDF URLを抽出してください。その候補をGemini APIに渡して重要な論文を3本選ばせ、Markdownレポートとして保存するコードを作成してください。
【構成案】
Gemini APIを設定し、モデルは gemini-2.5-flash を使う。
ユーザー入力の検索ワードで arXiv の検索ページにアクセスする。
arXivの検索は、https://arxiv.org/search/?query=検索ワード というURLで行う。
検索結果HTMLから各論文のタイトル・概要・PDF URLを抽出し、最大10件まで候補として保持する。
候補論文一覧をGeminiに渡し、「重要な論文を3本、PDF URLのみ箇条書きで返す」よう指示する。
Geminiの返答からURLだけを抽出する。
選ばれた論文について、タイトル・概要・PDF URLを含むMarkdownレポートを生成して保存する。
そのレポート全体をGeminiで日本語に翻訳し、Markdown形式を保ったまま別ファイルで保存する。


リスト6-21
import requests
from bs4 import BeautifulSoup
import google.generativeai as genai
from google.colab import userdata
import time


genai.configure(api_key=userdata.get('GEMINI_API_KEY'))
model = genai.GenerativeModel('gemini-2.5-flash')


headers = {
    "User-Agent": "Python arXiv API Client/1.0 (tu.noda@gmail.com)"
}


query = input("検索ワード (例: AI Agent): ")
search_url = f"https://arxiv.org/search/?query={query}&searchtype=all&source=header"
print(f"arXivで「{query}」を検索中: {search_url}")


try:
    res = requests.get(search_url, headers=headers, timeout=15)
    res.raise_for_status()
    soup = BeautifulSoup(res.text, "html.parser")


    print("\n--- 取得したHTMLの主要な要素 --- ")
    if soup.title:
        print(f"HTML Title: {soup.title.string.strip()}")
    else:
        print("HTML Title: N/A")


    if soup.body and 'class' in soup.body.attrs:
        print(f"Body Class: {soup.body['class']}")
    else:
        print("Body Class: N/A")


    first_arxiv_result = soup.find("li", class_="arxiv-result")
    all_arxiv_results = soup.find_all("li", class_="arxiv-result")
    print(f"Found {len(all_arxiv_results)} elements with class 'arxiv-result'")
    if first_arxiv_result and 'class' in first_arxiv_result.attrs:
        print(f"First 'arxiv-result' Class: {first_arxiv_result['class']}")
    else:
        print("First 'arxiv-result' Class: N/A")


    print("-------------------------------------\n")


except requests.exceptions.RequestException as e:
    print(f"arXivへのアクセス中にエラーが発生しました: {e}")
    print("処理を終了します。")
    exit()


paper_list = []
print("--- 各論文候補の抽出状況 ---")
for i, result in enumerate(soup.find_all("li", class_="arxiv-result")):
    print(f"アイテム {i+1}:")


    title_element = result.find("p", class_="title is-5 mathjax")
    abstract_element = result.find("span", class_="abstract-short")
    pdf_link_element = result.find("a", href=lambda href: href and "/pdf/" in href)


    title = title_element.get_text(strip=True) if title_element else "N/A"
    abstract_text_content = abstract_element.get_text(strip=True).replace('Abstract :', '') if abstract_element else "No abstract available."
    abstract = abstract_text_content.strip()


    pdf_relative_url = pdf_link_element['href'] if pdf_link_element else None


    print(f"  タイトル要素が見つかったか: {title_element is not None}")
    print(f"  概要要素が見つかったか: {abstract_element is not None}")
    print(f"  PDFリンク要素が見つかったか: {pdf_link_element is not None}")
    if pdf_link_element:
        print(f"  PDFリンクのhref属性: {pdf_link_element['href']}")


    if pdf_relative_url:
        pdf_full_url = requests.compat.urljoin("https://arxiv.org", pdf_relative_url)
        paper_list.append({
            'title': title,
            'abstract': abstract,
            'pdf_url': pdf_full_url
        })
    if len(paper_list) >= 10:
        break


print("----------------------------\n")


if not paper_list:
    print("指定された検索ワードで論文が見つかりませんでした。")
else:
    # Removed the per-paper translation step
    # print("--- 論文のタイトルと概要を日本語に翻訳中 ---")
    # translated_paper_list = []
    # for i, paper in enumerate(paper_list):
    #    ...
    # print("--- 翻訳完了 ---\n")


    selection_prompt_parts = []
    selection_prompt_parts.append("以下の論文リストから、最も重要だと思われる論文を3つ選んで、それぞれのPDFのURLだけを箇条書きで出力してください。重要度が高い順に並べてください。選定の理由やその他のコメントは一切含めないでください。出力形式は「- URL」としてください。")
    selection_prompt_parts.append("\n--- 論文リスト ---\n")


    for i, paper in enumerate(paper_list): # Use original paper_list for selection prompt
        selection_prompt_parts.append(f"論文 {i+1}:")
        selection_prompt_parts.append(f"タイトル: {paper['title']}")
        selection_prompt_parts.append(f"概要: {paper['abstract']}")
        selection_prompt_parts.append(f"PDF URL: {paper['pdf_url']}\n")


    selection_prompt = "\n".join(selection_prompt_parts)
    print("\n--- Geminiに重要論文の選定を依頼中 ---")
    print("\n--- Geminiへのプロンプト内容 ---")
    print(selection_prompt)
    print("-------------------------------------\n")


    try:
        selection_response = model.generate_content(selection_prompt)
        print("\n--- Geminiからの生レスポンス ---")
        print(repr(selection_response.text))
        print("-------------------------------------\n")


        print("--- Debugging Gemini response parsing --- ")
        temp_parsed_lines = []
        for line in selection_response.text.strip().split("\n"):
            stripped_line = line.strip()
            stripped_bullet_line = stripped_line.strip("- ")
            starts_with_http = stripped_bullet_line.startswith("http")
            starts_with_https = stripped_bullet_line.startswith("https")
            print(f"  Original: {repr(line)}")
            print(f"  Stripped: {repr(stripped_line)}")
            print(f"  Stripped bullet: {repr(stripped_bullet_line)}")
            print(f"  Starts with http: {starts_with_http}, Starts with https: {starts_with_https}")
            if starts_with_http or starts_with_https:
                temp_parsed_lines.append(stripped_bullet_line)
        selected_pdf_urls = temp_parsed_lines
        print(f"Final selected_pdf_urls (debug): {selected_pdf_urls}")
        print("----------------------------------------\n")


    except genai.types.BlockedPromptException as e:
        print(f"Geminiによる論文選定がブロックされました: {e}")
        print("入力テキストがモデルの安全ポリシーに違反した可能性があります。")
        selected_pdf_urls = []
    except Exception as e:
        print(f"Geminiによる論文選定中にエラーが発生しました: {e}")
        selected_pdf_urls = []


    if not selected_pdf_urls:
        print("Geminiが重要な論文のURLを特定できませんでした。")
    else:
        markdown_report = f"# Important Paper Report - {query}\n\n" # Report starts in English
        print(f"\n--- Gemini selected {len(selected_pdf_urls)} papers. Organizing info into Markdown file (English) ---")


        for i, pdf_url_selected in enumerate(selected_pdf_urls[:3]):
            found_paper = None
            for paper in paper_list: # Search in original paper_list
                if paper['pdf_url'] == pdf_url_selected:
                    found_paper = paper
                    break


            if found_paper:
                markdown_report += f"## {i+1}. {found_paper['title']}\n"
                markdown_report += f"- **Abstract**: {found_paper['abstract']}\n"
                markdown_report += f"- **PDF URL**: [{found_paper['pdf_url']}]({found_paper['pdf_url']})\n\n"
                print(f"  Organized: {found_paper['title']}")
            else:
                markdown_report += f"## {i+1}. Title Unknown (URL: {pdf_url_selected})\n"
                markdown_report += "- Abstract: Details not found.\n"
                markdown_report += f"- PDF URL: [{pdf_url_selected}]({pdf_url_selected})\n\n"
                print(f"  Skipped organization (Paper details not found): {pdf_url_selected}")


        report_filename = f"selected_papers_summary_{query}.md"
        with open(report_filename, "w", encoding="utf-8") as f:
            f.write(markdown_report)
        print(f"\nAll paper information saved to '{report_filename}' (English report).")


        # --- NEW STEP: Translate the entire Markdown report to Japanese ---
        print(f"\n--- Translating the report to Japanese ---")
        try:
            with open(report_filename, "r", encoding="utf-8") as f:
                english_report_content = f.read()


            translation_prompt = f"以下のMarkdown形式のレポートを全て日本語に翻訳してください。Markdownの書式は保持してください。\n\n{english_report_content}"
            translated_report_response = model.generate_content(translation_prompt)
            translated_report_content = translated_report_response.text.strip()


            japanese_report_filename = f"selected_papers_summary_{query}_ja.md"
            with open(japanese_report_filename, "w", encoding="utf-8") as f:
                f.write(translated_report_content)
            print(f"Japanese report saved to '{japanese_report_filename}'.")
        except Exception as e:
            print(f"Error during Japanese report translation: {e}")


print("\n全ての処理が終了しました。")


リスト7-1
【要件定義】
CSVファイルをアップロードすると、その内容を読み取ってブラウザ上の表形式で表示するGUIツールを作成してください。
【構成案】
ライブラリ：gradio, pandasを使用。
関数：display_csvを作成。引数としてファイルを受け取り、Pandasで読み込んでデータフレーム（表形式）を返す。
UI構成：gr.Interfaceを使用。
入力（inputs）：gr.File（ラベルは「CSVファイルをアップロード」）。
出力（outputs）：gr.Dataframe（読み込んだデータを表示）。


リスト7-2
import gradio as gr
import pandas as pd


def display_csv(file):
    """
    アップロードされたファイルをPandasで読み込み、中身を返す関数
    """
    if file is None:
        return None
    
    # CSVファイルを読み込む
    try:
        # file.name に保存先のパスが入っている
        df = pd.read_csv(file.name)
        return df
    except Exception as e:
        return f"エラーが発生しました: {e}"


# Gradioのインターフェース設定
demo = gr.Interface(
    fn=display_csv,
    inputs=gr.File(label="CSVファイルをアップロード"),
    outputs=gr.Dataframe(label="読み込み結果"),
    title="CSVビューアー",
    description="CSVファイルをアップロードして中身を確認しましょう。"
)


# 実行
if __name__ == "__main__":
    demo.launch()


リスト7-3
ID,名前,年齢,部署,入社日,給与,勤務地
1,田中太郎,28,営業,2021-04-01,350000,東京
2,佐藤花子,34,人事,2019-07-15,420000,大阪
3,鈴木一郎,25,開発,2023-01-10,300000,名古屋
4,高橋美咲,31,経理,2020-10-01,390000,福岡
5,伊藤健太,29,開発,2022-06-20,370000,東京
6,渡辺彩,27,営業,2024-02-01,320000,札幌
7,山本大輔,36,管理,2018-03-12,500000,大阪
8,中村優子,30,人事,2021-11-05,410000,東京


リスト7-4
【要件定義】
CSVファイルを読み込み、ユーザーが「X軸（横軸）」と「Y軸（縦軸）」にする列名を選択して、棒グラフを表示するツールを作成してください。
【構成案】
ライブラリ：gradio, pandas, matplotlibを使用。
関数：create_bar_chartを作成。ファイル、X軸の列名、Y軸の列名を引数にとる。
処理：
        CSVを読み込む。
        Matplotlibを使用して棒グラフを作成。
        日本語フォントの問題を避けるため、シンプルな設定でグラフ画像を出力。
UI構成：gr.Blocksを使用して、少し高度なレイアウトにする。
        入力：ファイルアップロード、X軸選択用ドロップダウン、Y軸選択用ドロップダウン。
        出力：グラフ画像（gr.Plot）。


リスト7-5
!sudo apt update
!sudo apt install -y fonts-noto-cjk


リスト7-6
import gradio as gr
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib
import matplotlib.font_manager as fm


def create_bar_chart(file, x_axis, y_axis):
    if file is None or x_axis == "" or y_axis == "":
        return None
    
    # データの読み込み
    df = pd.read_csv(file.name)
    
    # フォントファイルのパスとプロパティの設定
    font_path = "/usr/share/fonts/opentype/noto/NotoSerifCJK-Regular.ttc"
    font_prop = fm.FontProperties(fname=font_path)


    # グラフの作成
    fig, ax = plt.subplots(figsize=(10, 6))
    ax.bar(df[x_axis], df[y_axis]) # 棒グラフ作成
    # タイトルを設定
    ax.set_title(f"{x_axis} vs {y_axis} の棒グラフ",fontproperties=font_prop)
    # X軸Y軸のラベルを設定
    ax.set_xlabel(x_axis,fontproperties=font_prop)
    ax.set_ylabel(y_axis,fontproperties=font_prop)
    # X軸の目盛りのラベルを設定
    ax.set_xticklabels(df[x_axis], fontproperties=font_prop)


    # レイアウトの調整
    plt.xticks(rotation=45)
    plt.tight_layout()
    
    return fig


# UIの構築（少し複雑な配置ができるBlocksを使用）
with gr.Blocks() as demo:
    gr.Markdown("# 簡易グラフ作成ツール")
    
    with gr.Row():
        file_input = gr.File(label="1. CSVをアップロード")
    
    with gr.Row():
        # 選択肢は直接入力か、読み込み後に手動指定します。
        x_col = gr.Textbox(label="2. X軸にする列名を入力してください")
        y_col = gr.Textbox(label="3. Y軸にする列名を入力してください")
    
    btn = gr.Button("グラフを生成")
    plot_output = gr.Plot(label="生成されたグラフ")
    
    # ボタンを押した時の動き
    btn.click(
        fn=create_bar_chart,
        inputs=[file_input, x_col, y_col],
        outputs=plot_output
    )


if __name__ == "__main__":
    demo.launch()


リスト7-7
【要件定義】
PDFファイルをアップロードすると、その中身をテキストとして抽出し、Gemini APIを使用して内容を簡潔に要約するツールを作成してください。
【構成案】
ライブラリ：gradio, pdfplumber, google-generativeaiを使用。
関数：
        extract_pdf_text：PDFから全テキストを抜き出す。
        summarize_document：抜き出したテキストをプロンプトに組み込み、Geminiに要約を依頼する。
UI構成：
        入力：gr.File（PDFのみ受け付け）。
        出力：gr.Textbox（要約結果を表示）。


リスト7-8
import gradio as gr
import pdfplumber
import google.generativeai as genai
from google.colab import userdata


# Geminiの設定（事前にAPIキーの設定が必要です）
genai.configure(api_key=userdata.get('GEMINI_API_KEY'))


def summarize_pdf(file):
    if file is None:
        return "ファイルがアップロードされていません。"


    # 1. PDFからテキストを抽出
    full_text = ""
    try:
        with pdfplumber.open(file.name) as pdf:
            for page in pdf.pages:
                text = page.extract_text()
                if text:
                    full_text += text + "\n"
    except Exception as e:
        return f"PDFの読み取りに失敗しました: {e}"


    if not full_text.strip():
        return "PDFから文字を検出できませんでした（画像形式の可能性があります）。"


    # 2. Geminiで要約
    model = genai.GenerativeModel("gemini-2.5-flash")
    prompt = f"""
    以下の資料の内容を読み取り、重要なポイントを3点に絞って、
    専門用語を避けて初心者にもわかりやすく要約してください。


    【資料内容】
    {full_text[:5000]}  # 念のため冒頭5000文字に制限
    """
    
    response = model.generate_content(prompt)
    return response.text


# Gradio UI
demo = gr.Interface(
    fn=summarize_pdf,
    inputs=gr.File(label="PDFをアップロード", file_types=[".pdf"]),
    outputs=gr.Textbox(label="AIによる3行要約", lines=10),
    title="爆速！PDF要約くん",
    description="長いPDFも、Geminiがサクッと要約してくれます。"
)


if __name__ == "__main__":
    demo.launch()


リスト7-9
【要件定義】
アップロードされたPDFの内容を「前提知識」として保持し、ユーザーからの具体的な質問（例：「交通費の申請期限は？」など）に対して、PDFの記述に基づいた正確な回答を返すツールを作成してください。
【構成案】
ライブラリ：gradio, pdfplumber, google-generativeai。
状態保持（State）：Gradioのgr.Stateを使用して、一度アップロードしたPDFのテキストをメモリに保存しておく。これにより、何度もアップロードし直さずに連続で質問できる。
関数：
        process_file：ファイルを読み込み、テキストを保持する。
        answer_question：保持したテキストと質問を組み合わせ、Geminiに「この資料に基づいて答えて」と命令する。
UI構成：
        左側：ファイルアップロード。
        右側：質問入力欄と回答表示欄。


リスト7-10
import gradio as gr
import pdfplumber
import google.generativeai as genai
from google.colab import userdata


# Geminiの設定（事前にAPIキーの設定が必要です）
genai.configure(api_key=userdata.get('GEMINI_API_KEY'))


# Geminiモデルの準備
model = genai.GenerativeModel("gemini-2.5-flash")


def load_pdf(file):
    """PDFを読み込んでテキストを抽出する"""
    if file is None:
        return ""
    text_data = ""
    with pdfplumber.open(file.name) as pdf:
        for page in pdf.pages:
            extracted = page.extract_text()
            if extracted:
                text_data += extracted + "\n"
    return text_data


def chat_with_pdf(pdf_content, question):
    """資料の内容をもとに質問に回答する"""
    if not pdf_content:
        return "先にPDFをアップロードしてください。"
    if not question:
        return "質問を入力してください。"


    prompt = f"""
    あなたは優秀な社内アシスタントです。
    提供された【資料】の内容だけに基づいて、ユーザーの【質問】に誠実に答えてください。
    資料に書いていない場合は「資料には記載がありません」と答えてください。


    【資料】
    {pdf_content[:10000]}


    【質問】
    {question}
    """
    
    response = model.generate_content(prompt)
    return response.text


# 画面のデザイン
with gr.Blocks() as demo:
    gr.Markdown("# 社内規定 Q&Aボット")
    
    # 読み込んだテキストを保存しておく「隠し場所」
    doc_state = gr.State("")


    with gr.Row():
        with gr.Column(scale=1):
            pdf_file = gr.File(label="1. 資料(PDF)をアップロード", file_types=[".pdf"])
            upload_btn = gr.Button("資料を読み込む")
        
        with gr.Column(scale=2):
            question_input = gr.Textbox(label="2. 聞きたいことを入力してください", placeholder="例：有給休暇は何日ありますか？")
            answer_output = gr.Textbox(label="回答", lines=10)
            ask_btn = gr.Button("質問する", variant="primary")


    # ボタンを押した時の動き
    upload_btn.click(fn=load_pdf, inputs=pdf_file, outputs=doc_state)
    ask_btn.click(fn=chat_with_pdf, inputs=[doc_state, question_input], outputs=answer_output)


if __name__ == "__main__":
    demo.launch(debug=True)


リスト7-11
【要件定義】
PDFの各ページを個別に認識し、ユーザーの質問に答えつつ、「資料の〇ページ目を参考にしました」という引用元情報を付与して回答する、信頼重視のQ&Aツールを作成してください。
【構成案】
ライブラリ：gradio, pdfplumber, google-generativeai。
データ構造：資料にページの区切りとなる情報を追加し、必要な情報があるページが分かるようにする。
関数：
        process_pdf_pages：ページごとのテキストをリスト化する。
        find_and_answer：全ページの内容をGeminiに渡し、回答と併せて「どのページを参照したか」も答えるよう指示する。
UI構成：回答エリアの下に「参照ページ」を表示する欄を設ける。


リスト7-12
import gradio as gr
import pdfplumber
import google.generativeai as genai
from google.colab import userdata


genai.configure(api_key=userdata.get('GEMINI_API_KEY'))


model = genai.GenerativeModel("gemini-2.5-flash")


def process_pdf_pages(file):
    if file is None:
        return []
    
    pages_content = []
    with pdfplumber.open(file.name) as pdf:
        for i, page in enumerate(pdf.pages):
            text = page.extract_text()
            if text:
                # ページ番号(1始まり)とテキストのセットを保存
                pages_content.append(f"--- ページ {i+1} ---\n{text}")
    
    # 全ページを一つの長いテキストにする（ページ区切りを明確にする）
    return "\n".join(pages_content)


def answer_with_citation(full_content, question):
    if not full_content:
        return "資料がありません。"
    
    prompt = f"""
    以下の【社内資料】に基づいて【質問】に答えてください。
    
    【ルール】
    1. 必ず資料内の言葉を使って回答すること。
    2. 回答の最後に、根拠としたページ番号を「参照ページ：〇ページ」という形式で必ず記載すること。
    
    【社内資料】
    {full_content[:15000]}  # 容量制限のため調整
    
    【質問】
    {question}
    """
    
    response = model.generate_content(prompt)
    return response.text


with gr.Blocks() as demo:
    gr.Markdown("## 引用元表示付き・社内資料Q&Aボット")
    
    storage = gr.State("")
    
    with gr.Row():
        pdf_in = gr.File(label="PDF資料アップロード")
        load_btn = gr.Button("解析開始")
    
    with gr.Row():
        q_in = gr.Textbox(label="質問内容", placeholder="例：慶弔休暇の規定を教えて")
        ans_out = gr.Textbox(label="AIの回答（ページ引用付き）", lines=12)
        
    load_btn.click(fn=process_pdf_pages, inputs=pdf_in, outputs=storage)
    q_in.submit(fn=answer_with_citation, inputs=[storage, q_in], outputs=ans_out)


if __name__ == "__main__":
    demo.launch(debug=True)


リスト7-13
【要件定義】
画像をアップロードすると、Geminiがその内容を分析し、関連するキーワード（タグ）を5つ程度生成して表示するツールを作成してください。
【構成案】
ライブラリ：gradio, google-generativeai, PIL（画像処理用）を使用。
処理：
        ユーザーが画像をアップロードする。
        Geminiに「この画像に写っているものを分析し、カンマ区切りのキーワードで出力して」と依頼する。
        結果を画面に表示する。
UI構成：
        入力：gr.Image（画像アップロード）。
        出力：gr.Textbox（生成されたタグを表示）。


リスト7-14
import gradio as gr
import google.generativeai as genai
from PIL import Image
from google.colab import userdata


genai.configure(api_key=userdata.get('GEMINI_API_KEY'))


# Geminiのモデル設定（2.5 Flashは画像処理が高速で安価です）
model = genai.GenerativeModel("gemini-2.5-flash")


def generate_tags(input_image):
    if input_image is None:
        return "画像をアップロードしてください。"
    
    # PIL（画像ライブラリ）形式からGeminiが扱える形式（PIL）へ確認
    # gr.Imageはnumpy形式なのでPILに変換して扱う
    img = Image.fromarray(input_image)
    
    prompt = """
    この画像に写っている主なオブジェクトや場所、雰囲気を分析してください。
    出力は、検索に役立つような短いキーワードを5つ、
    「、」で区切って回答してください。余計な説明は不要です。
    例：パソコン、オフィス、仕事、カフェ、集中
    """
    
    # 画像とプロンプトを同時に渡す（マルチモーダル実行）
    response = model.generate_content([prompt, img])
    
    return response.text


# UIのデザイン
with gr.Blocks() as demo:
    gr.Markdown("# AI自動タグ付けツール")
    gr.Markdown("画像をアップロードするだけで、AIがキーワードを自動生成します。")
    
    with gr.Row():
        image_input = gr.Image(label="画像をアップロード")
        tag_output = gr.Textbox(label="生成されたタグ")
    
    btn = gr.Button("分析を実行", variant="primary")
    btn.click(fn=generate_tags, inputs=image_input, outputs=tag_output)


if __name__ == "__main__":
    demo.launch(debug=True)


リスト7-15
【要件定義】
名刺や領収書の画像から、必要な情報（氏名、社名、金額、日付など）を抽出して、整理されたテキスト形式で表示するツールを作成してください。
【構成案】
ライブラリ：gradio, google-generativeai, PIL。
処理：
        画像が「名刺」か「領収書」かをAIに自動判断させる。
        種類に合わせて、適切な情報を抽出する（名刺なら連絡先、領収書なら金額）。
UI構成：
        入力：gr.Image。
        出力：gr.Textbox（整理された結果）。


リスト7-16
import gradio as gr
import google.generativeai as genai
from PIL import Image
from google.colab import userdata


genai.configure(api_key=userdata.get('GEMINI_API_KEY'))


model = genai.GenerativeModel("gemini-2.5-flash")


def ocr_and_organize(input_image):
    if input_image is None:
        return "画像を選択してください。"


    img = Image.fromarray(input_image)


    prompt = """
    この画像を確認し、以下の手順で情報を整理してください。


    1. まず、画像が「名刺」か「領収書」か、あるいは「その他」かを判断してください。
    2. 名刺の場合：【氏名】【会社名】【電話番号】【メールアドレス】を抽出してください。
    3. 領収書の場合：【購入日】【店名】【合計金額】を抽出してください。
    4. その他：画像の内容を1行で説明してください。


    出力は見やすく箇条書きにしてください。
    """


    response = model.generate_content([prompt, img])
    return response.text


with gr.Blocks() as demo:
    gr.Markdown("# 事務作業時短ツール：名刺・領収書スキャナー")


    with gr.Row():
        with gr.Column():
            img_in = gr.Image(label="画像を撮影またはアップロード")
            process_btn = gr.Button("情報を抽出する", variant="primary")


        with gr.Column():
            text_out = gr.Textbox(label="抽出結果", lines=10)


    process_btn.click(fn=ocr_and_organize, inputs=img_in, outputs=text_out)


if __name__ == "__main__":
    demo.launch(debug=True)


リスト7-17
【要件定義】
複数のタスクを一覧表で管理（追加・編集）でき、その全体状況をGeminiが分析して「次に何をすべきか」のアドバイスを表示するダッシュボードを作成してください。
【構成案】
ライブラリ：gradio, pandas, json, google-generativeai
データ管理：
        リスト形式のデータをJSONで永続化。
        gr.Dataframe を使い、ブラウザ上で直接表を編集できるようにする。
AI機能：
        表の内容をGeminiに渡し、遅れているタスクの指摘や応援メッセージを生成させる。


リスト7-18
import gradio as gr
import pandas as pd
import json
import os
import google.generativeai as genai
from google.colab import userdata


genai.configure(api_key=userdata.get('GEMINI_API_KEY'))


# Geminiの設定（APIキーは設定済みとします）
model = genai.GenerativeModel("gemini-2.5-flash")
DB_FILE = "team_tasks.json"


def load_all_tasks():
    if os.path.exists(DB_FILE):
        with open(DB_FILE, "r", encoding="utf-8") as f:
            return pd.DataFrame(json.load(f))
    # 初回起動時のサンプルデータ
    return pd.DataFrame([
        {"担当者": "田中", "タスク": "企画書作成", "進捗": 50},
        {"担当者": "佐藤", "タスク": "市場調査", "進捗": 20}
    ])


def analyze_and_save(df):
    """データを保存し、AIのアドバイスを貰う"""
    # JSONで保存
    tasks_list = df.to_dict(orient="records")
    with open(DB_FILE, "w", encoding="utf-8") as f:
        json.dump(tasks_list, f, ensure_ascii=False, indent=4)
    
    # Geminiに分析を依頼
    prompt = f"""
    以下のチームの進捗状況を見て、短いアドバイスをください。
    {df.to_string()}
    特に進捗が低い人へのフォロー方法を1つ提案してください。
    """
    response = model.generate_content(prompt)
    return response.text


# UI構築
with gr.Blocks() as demo:
    gr.Markdown("## AIチームリーダー・ダッシュボード")
    
    with gr.Row():
        # interactive=True で、画面上で表を書き換え可能にする
        table = gr.Dataframe(
            value=load_all_tasks(),
            headers=["担当者", "タスク", "進捗"],
            datatype=["str", "str", "number"],
            interactive=True,
            label="進捗一覧（直接編集して保存ボタンを押してください）"
        )
    
    with gr.Row():
        btn = gr.Button("データを保存してAI分析を実行", variant="primary")
    
    with gr.Row():
        advice_out = gr.Textbox(label="Geminiからのアドバイス", lines=5)


    btn.click(fn=analyze_and_save, inputs=table, outputs=advice_out)


if __name__ == "__main__":
    demo.launch(debug=True)