21
✨ 飛躍編 Chapter 21

Pythonで自動化

繰り返し作業をスクリプトで一掃する

約55分
Python · intro Scripting · intro Automation · intro
目次(31セクション)
🎬 Story — Introduction

ShimaLinkが100店舗を超え、チームは成長の喜びを感じていた。しかし、同時にある問題が深刻化していた。

毎朝、同じ作業の繰り返し。データの集計、レポートの作成、画像のリサイズ、メール通知の確認——。手作業で回していた業務が、もう限界に達していた。


あなた: 「昨日も夜中の2時まで、100店舗分のアクセスレポートをExcelにまとめてたんだけど…これ毎週やるの無理じゃない?」

Mika: 「私もお店の画像を一枚一枚リサイズして、メールで確認送って…気づいたら3時間経ってた。」

あなた: 「みんな同じこと感じてたんだ。これ、自動化できないのかな?」

Yuki: 「待ってました、その一言。実はね、こういう『退屈な仕事』を片付けるのに最適な言語があるの。」

あなた: 「JavaScript?」

Yuki: 「ううん。Python。シンプルな文法で、ファイル操作もデータ処理もWeb連携も、驚くほど少ないコードでできる。“退屈なことはPythonにやらせよう”って本があるくらいだよ。」


Yukiはホワイトボードに大きく書いた。

「プログラマーの美徳は怠惰である。同じことを2回やるなら、自動化を考えろ。」

あなた: 「Pythonって、JavaScriptとどう違うんですか?」

Yuki: 「JavaScriptはWebブラウザの言語。Pythonは”万能ナイフ”。データ分析、AI、自動化、なんでもこなせる。ShimaLinkの運用を効率化するには、Pythonを覚えるのが最短ルートだよ。」


こうして、チームのPython修行が始まった。目標は明確だ——退屈な繰り返し作業を、すべてスクリプトに置き換えること。

Python入門 — 変数・関数・リスト

Yukiが最初に見せてくれたのは、Pythonの驚くほどシンプルな文法だった。

「Pythonは”読みやすさ”を哲学にした言語。コードが英語のように読めるのが最大の特徴だよ。」

Pythonのインストール確認

# バージョン確認
python3 --version
# → Python 3.11.x

# 対話モードで試す
python3
>>> print("こんにちは、ShimaLink!")
こんにちは、ShimaLink!
>>> exit()

変数とデータ型

Pythonでは変数の型宣言が不要です。値を代入するだけで型が決まります。

# 文字列
shop_name = "海風テラス"
owner = "Mika"

# 数値
monthly_visitors = 1500
rating = 4.8

# 真偽値
is_open = True

# 表示
print(f"{shop_name}の月間訪問者: {monthly_visitors}人")
# → 海風テラスの月間訪問者: 1500人
データ型説明
str"ShimaLink"文字列
int42整数
float4.8小数
boolTrue / False真偽値
list[1, 2, 3]リスト(配列)
dict{"key": "value"}辞書(オブジェクト)

リスト — データの集まり

# ShimaLinkに登録されたお店のリスト
shops = ["海風テラス", "島そば屋", "首里城カフェ", "美ら海ダイニング"]

# アクセス
print(shops[0])      # → 海風テラス(0から数える)
print(len(shops))    # → 4(要素数)

# 追加・削除
shops.append("琉球ベーカリー")
shops.remove("島そば屋")

# ループ処理
for shop in shops:
    print(f"✓ {shop}")

辞書 — キーと値のペア

# お店の情報を辞書で管理
shop_info = {
    "name": "海風テラス",
    "category": "カフェ",
    "rating": 4.8,
    "monthly_visitors": 1500
}

# アクセス
print(shop_info["name"])        # → 海風テラス
print(shop_info.get("phone"))   # → None(キーがなくてもエラーにならない)

# 更新
shop_info["rating"] = 4.9

関数 — 処理の再利用

def generate_report(shop_name, visitors, revenue):
    """お店のレポートを生成する"""
    avg_per_visitor = revenue / visitors if visitors > 0 else 0
    return f"""
    === {shop_name} レポート ===
    訪問者数: {visitors}
    売上: ¥{revenue:,}
    客単価: ¥{avg_per_visitor:,.0f}
    """

# 使う
report = generate_report("海風テラス", 1500, 450000)
print(report)

条件分岐

def evaluate_shop(rating, visitors):
    """お店の評価を判定する"""
    if rating >= 4.5 and visitors >= 1000:
        return "★★★ トップパフォーマー"
    elif rating >= 4.0:
        return "★★ 好調"
    elif rating >= 3.0:
        return "★ 改善の余地あり"
    else:
        return "要注意"

print(evaluate_shop(4.8, 1500))  # → ★★★ トップパフォーマー

JavaScript経験者向け比較

概念JavaScriptPython
変数let x = 10x = 10
関数function f() {}def f():
配列/リスト[1, 2, 3][1, 2, 3]
オブジェクト/辞書{key: "value"}{"key": "value"}
ループfor (let x of arr)for x in arr:
出力console.log()print()
ブロック{ } 中括弧インデント(スペース4つ)

Yuki: 「Pythonで一番大事なのはインデント。中括弧の代わりにスペースでブロックを表すから、インデントがずれるとエラーになるよ。」

ポイント

  • Pythonはシンプルで読みやすい言語。型宣言不要
  • リスト([])と辞書({})がデータ管理の基本
  • def で関数を定義して処理を再利用
  • インデント(スペース4つ)がコードの構造を決める
  • f文字列(f"...{変数}...")で文字列に変数を埋め込める

ファイル操作 — データの読み書き

自動化の第一歩は、ファイルの読み書きだ。ShimaLinkの店舗データはCSVファイルで管理されている。

Yuki: 「プログラマーの世界では、手でExcelを開いてコピペするのは”罪”だよ。Pythonならファイルの読み書きが数行で書ける。」

テキストファイルの読み書き

# ファイルに書き込む
with open("report.txt", "w", encoding="utf-8") as f:
    f.write("ShimaLink 週次レポート\n")
    f.write("========================\n")
    f.write(f"日付: 2025-03-21\n")
    f.write(f"登録店舗数: 102\n")

# ファイルを読み込む
with open("report.txt", "r", encoding="utf-8") as f:
    content = f.read()
    print(content)

ポイント: with 文を使うと、ファイルが自動的に閉じられます。閉じ忘れによるバグを防げます。

ファイルモード一覧

モード意味説明
"r"Read読み取り専用(デフォルト)
"w"Write書き込み(上書き)
"a"Append追記(末尾に追加)
"x"eXclusive新規作成のみ(既存なら失敗)

CSVファイルの処理

ShimaLinkの店舗データを処理してみよう。

import csv

# CSVを読み込む
def read_shops(filepath):
    """CSVから店舗データを読み込む"""
    shops = []
    with open(filepath, "r", encoding="utf-8") as f:
        reader = csv.DictReader(f)
        for row in reader:
            shops.append({
                "name": row["name"],
                "category": row["category"],
                "rating": float(row["rating"]),
                "visitors": int(row["visitors"])
            })
    return shops

# CSVに書き込む
def write_report(shops, output_path):
    """集計結果をCSVに書き出す"""
    with open(output_path, "w", encoding="utf-8", newline="") as f:
        writer = csv.writer(f)
        writer.writerow(["店舗名", "カテゴリ", "評価", "訪問者数"])
        for shop in shops:
            writer.writerow([
                shop["name"],
                shop["category"],
                shop["rating"],
                shop["visitors"]
            ])

JSONファイルの操作

API連携でよく使うJSON形式も簡単に扱えます。

import json

# JSONを読み込む
with open("config.json", "r", encoding="utf-8") as f:
    config = json.load(f)
    print(config["database"]["host"])

# JSONに書き出す
shop_data = {
    "shops": [
        {"name": "海風テラス", "rating": 4.8},
        {"name": "首里城カフェ", "rating": 4.5}
    ],
    "total": 2
}

with open("shops.json", "w", encoding="utf-8") as f:
    json.dump(shop_data, f, ensure_ascii=False, indent=2)

ensure_ascii=False を指定すると、日本語がそのまま書き出されます(指定しないと \u6d77\u98a8 のようにエスケープされる)。

ディレクトリ操作

import os
from pathlib import Path

# ディレクトリ内のファイル一覧
for filepath in Path("./data").glob("*.csv"):
    print(f"Found: {filepath.name}")

# ディレクトリ作成
os.makedirs("output/reports", exist_ok=True)

# ファイルの存在確認
if Path("config.json").exists():
    print("設定ファイルが見つかりました")

実践: ShimaLinkの月次集計スクリプト

import csv
import json
from pathlib import Path
from datetime import datetime

def monthly_aggregate():
    """全店舗の月次データを集計する"""
    shops = []
    data_dir = Path("data/shops")

    # 全CSVファイルを読み込む
    for csv_file in data_dir.glob("*.csv"):
        with open(csv_file, "r", encoding="utf-8") as f:
            reader = csv.DictReader(f)
            for row in reader:
                shops.append(row)

    # 集計
    total_visitors = sum(int(s["visitors"]) for s in shops)
    avg_rating = sum(float(s["rating"]) for s in shops) / len(shops)

    # レポート生成
    report = {
        "date": datetime.now().strftime("%Y-%m-%d"),
        "total_shops": len(shops),
        "total_visitors": total_visitors,
        "average_rating": round(avg_rating, 2)
    }

    # 出力
    output_dir = Path("output")
    output_dir.mkdir(exist_ok=True)

    with open(output_dir / "monthly_report.json", "w", encoding="utf-8") as f:
        json.dump(report, f, ensure_ascii=False, indent=2)

    print(f"集計完了: {report['total_shops']}店舗")
    return report

if __name__ == "__main__":
    monthly_aggregate()

ポイント

  • with open() でファイルの開閉を安全に管理
  • csv モジュールでCSVの読み書き、json モジュールでJSON操作
  • pathlib.Path でファイルパスをオブジェクトとして扱える
  • encoding="utf-8" を忘れると日本語で文字化けする
  • if __name__ == "__main__": はスクリプトとして直接実行されたときだけ動くコード

Webスクレイピング — データを自動収集

ShimaLinkに登録されたお店の口コミや競合情報を自動で収集したい。そんな時に使うのがWebスクレイピングだ。

Yuki: 「Webページも結局はHTMLテキスト。Pythonならそれを解析してデータだけ抜き出せるよ。ただし、ルールは守ること。」

スクレイピングの倫理とルール

必ず守るべきこと:

ルール理由
robots.txt を確認するサイトが許可している範囲で収集する
利用規約を確認するスクレイピング禁止のサイトもある
アクセス間隔を空けるサーバーに負荷をかけない(1秒以上)
個人情報を収集しないプライバシーの保護
商用利用の可否を確認データの利用目的に注意

requestsライブラリ — HTTPリクエスト

# インストール
pip install requests
import requests

# GETリクエスト
response = requests.get("https://api.example.com/shops")
print(response.status_code)  # → 200
print(response.json())       # JSONレスポンスを辞書に変換

# ヘッダー付きリクエスト
headers = {"User-Agent": "ShimaLink-Bot/1.0"}
response = requests.get("https://example.com", headers=headers)

BeautifulSoup — HTML解析

pip install beautifulsoup4
from bs4 import BeautifulSoup
import requests

# ページを取得
url = "https://example.com/okinawa-shops"
response = requests.get(url)
soup = BeautifulSoup(response.text, "html.parser")

# 要素を検索
title = soup.find("h1").text
print(f"ページタイトル: {title}")

# 複数要素を検索
shop_cards = soup.find_all("div", class_="shop-card")
for card in shop_cards:
    name = card.find("h2").text
    rating = card.find("span", class_="rating").text
    print(f"{name}: {rating}")

BeautifulSoupの主なメソッド

メソッド説明
find()最初の一致要素soup.find("h1")
find_all()すべての一致要素soup.find_all("a")
select()CSSセレクタで検索soup.select(".shop-card h2")
.textテキスト内容を取得element.text
.get()属性値を取得a_tag.get("href")

APIからデータを取得

スクレイピングよりもAPIがあればAPIを使う方がベターです。

import requests
import json

def fetch_weather(city="Naha"):
    """天気予報APIからデータを取得"""
    api_url = f"https://api.example.com/weather?city={city}"
    response = requests.get(api_url)

    if response.status_code == 200:
        data = response.json()
        return {
            "city": data["name"],
            "temp": data["main"]["temp"],
            "description": data["weather"][0]["description"]
        }
    else:
        print(f"Error: {response.status_code}")
        return None

weather = fetch_weather("Naha")
if weather:
    print(f"{weather['city']}: {weather['temp']}°C - {weather['description']}")

実践: 沖縄のイベント情報収集

import requests
from bs4 import BeautifulSoup
import csv
import time

def scrape_events(url):
    """イベント情報をスクレイピングする"""
    response = requests.get(url, headers={
        "User-Agent": "ShimaLink-Bot/1.0 (educational)"
    })
    soup = BeautifulSoup(response.text, "html.parser")

    events = []
    for item in soup.find_all("div", class_="event-item"):
        event = {
            "title": item.find("h3").text.strip(),
            "date": item.find("time").get("datetime", ""),
            "location": item.find("span", class_="location").text.strip(),
        }
        events.append(event)

    return events

def save_events_csv(events, filepath):
    """イベント一覧をCSVに保存"""
    with open(filepath, "w", encoding="utf-8", newline="") as f:
        writer = csv.DictWriter(f, fieldnames=["title", "date", "location"])
        writer.writeheader()
        writer.writerows(events)

# メイン処理
if __name__ == "__main__":
    pages = [
        "https://example.com/events?page=1",
        "https://example.com/events?page=2",
    ]

    all_events = []
    for page_url in pages:
        events = scrape_events(page_url)
        all_events.extend(events)
        time.sleep(1)  # サーバーへの配慮

    save_events_csv(all_events, "okinawa_events.csv")
    print(f"{len(all_events)}件のイベントを保存しました")

ポイント

  • requests でHTTPリクエスト、BeautifulSoup でHTML解析
  • APIがあればスクレイピングよりAPIを優先する
  • time.sleep() でアクセス間隔を空け、サーバーに配慮する
  • robots.txt と利用規約を必ず確認する
  • データは構造化して(CSV/JSON)保存する

自動化スクリプト — 退屈な作業をPythonに任せる

基礎を覚えたら、いよいよ実務の自動化に挑戦だ。

Yuki: 「最高の自動化スクリプトは、存在を忘れられるスクリプト。静かに正確に、毎日仕事をこなしてくれる。」

画像の一括リサイズ

ShimaLinkでは店舗画像を統一サイズで表示する必要がある。

pip install Pillow
from PIL import Image
from pathlib import Path

def resize_images(input_dir, output_dir, max_width=800):
    """画像を指定幅にリサイズする"""
    output_path = Path(output_dir)
    output_path.mkdir(exist_ok=True)

    for img_file in Path(input_dir).glob("*"):
        if img_file.suffix.lower() in [".jpg", ".jpeg", ".png", ".webp"]:
            with Image.open(img_file) as img:
                # アスペクト比を維持してリサイズ
                if img.width > max_width:
                    ratio = max_width / img.width
                    new_size = (max_width, int(img.height * ratio))
                    resized = img.resize(new_size, Image.LANCZOS)
                else:
                    resized = img

                # 保存
                save_path = output_path / img_file.name
                resized.save(save_path, quality=85, optimize=True)
                print(f"✓ {img_file.name}{resized.size[0]}x{resized.size[1]}")

if __name__ == "__main__":
    resize_images("uploads/raw", "uploads/optimized")

メール通知の自動送信

import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart

def send_report_email(to_email, subject, body):
    """レポートをメールで送信する"""
    msg = MIMEMultipart()
    msg["From"] = "noreply@shimalink.com"
    msg["To"] = to_email
    msg["Subject"] = subject
    msg.attach(MIMEText(body, "html", "utf-8"))

    with smtplib.SMTP("smtp.example.com", 587) as server:
        server.starttls()
        server.login("user", "password")  # 実際は環境変数で管理
        server.send_message(msg)

    print(f"✓ メール送信完了: {to_email}")

定期実行 — cronとスケジューリング

cronで定期実行(Linux/Mac)

# crontabを編集
crontab -e

# 毎朝9時にレポートを生成
0 9 * * * /usr/bin/python3 /home/user/scripts/weekly_report.py

# 毎週月曜8時にバックアップ
0 8 * * 1 /usr/bin/python3 /home/user/scripts/backup.py

cron式の読み方

┌───────── 分 (0-59)
│ ┌─────── 時 (0-23)
│ │ ┌───── 日 (1-31)
│ │ │ ┌─── 月 (1-12)
│ │ │ │ ┌─ 曜日 (0-7, 0と7=日曜)
│ │ │ │ │
* * * * *
意味
0 9 * * *毎日9:00
0 9 * * 1-5平日9:00
*/30 * * * *30分ごと
0 0 1 * *毎月1日0:00

Pythonでスケジューリング

pip install schedule
import schedule
import time

def daily_report():
    print("日次レポートを生成中...")
    # レポート生成処理

def hourly_check():
    print("サーバー状態を確認中...")
    # ヘルスチェック処理

# スケジュール設定
schedule.every().day.at("09:00").do(daily_report)
schedule.every().hour.do(hourly_check)
schedule.every().monday.at("08:00").do(lambda: print("週次バックアップ"))

# 実行ループ
while True:
    schedule.run_pending()
    time.sleep(60)

実践: ShimaLink運用自動化スクリプト

#!/usr/bin/env python3
"""
ShimaLink 日次自動化スクリプト
- 店舗データの集計
- 異常検知
- レポート生成
"""

import csv
import json
from datetime import datetime
from pathlib import Path

def load_shop_data(data_dir):
    """店舗データを読み込む"""
    shops = []
    for csv_file in Path(data_dir).glob("*.csv"):
        with open(csv_file, encoding="utf-8") as f:
            reader = csv.DictReader(f)
            shops.extend(list(reader))
    return shops

def detect_anomalies(shops):
    """異常なデータを検出する"""
    alerts = []
    for shop in shops:
        visitors = int(shop.get("visitors", 0))
        rating = float(shop.get("rating", 0))

        if visitors == 0:
            alerts.append(f"⚠ {shop['name']}: 訪問者数が0")
        if rating < 3.0:
            alerts.append(f"⚠ {shop['name']}: 評価が{rating}に低下")

    return alerts

def generate_daily_report(shops, alerts):
    """日次レポートを生成する"""
    total_visitors = sum(int(s.get("visitors", 0)) for s in shops)
    avg_rating = sum(float(s.get("rating", 0)) for s in shops) / max(len(shops), 1)

    report = {
        "date": datetime.now().isoformat(),
        "summary": {
            "total_shops": len(shops),
            "total_visitors": total_visitors,
            "average_rating": round(avg_rating, 2)
        },
        "alerts": alerts,
        "status": "warning" if alerts else "healthy"
    }

    # JSONで保存
    output_dir = Path("output/daily")
    output_dir.mkdir(parents=True, exist_ok=True)

    filename = f"report_{datetime.now().strftime('%Y%m%d')}.json"
    with open(output_dir / filename, "w", encoding="utf-8") as f:
        json.dump(report, f, ensure_ascii=False, indent=2)

    return report

def main():
    """メイン処理"""
    print(f"=== ShimaLink 日次レポート ({datetime.now().strftime('%Y-%m-%d')}) ===")

    # 1. データ読み込み
    shops = load_shop_data("data/shops")
    print(f"✓ {len(shops)}店舗のデータを読み込み")

    # 2. 異常検知
    alerts = detect_anomalies(shops)
    if alerts:
        print(f"⚠ {len(alerts)}件のアラート:")
        for alert in alerts:
            print(f"  {alert}")
    else:
        print("✓ 異常なし")

    # 3. レポート生成
    report = generate_daily_report(shops, alerts)
    print(f"✓ レポート生成完了: output/daily/")
    print(f"  - 総訪問者: {report['summary']['total_visitors']:,}人")
    print(f"  - 平均評価: {report['summary']['average_rating']}")

if __name__ == "__main__":
    main()

ポイント

  • 自動化の対象: 画像リサイズ、メール送信、データ集計、異常検知
  • cron やPythonの schedule で定期実行を設定
  • スクリプトは小さな関数に分割し、テストしやすくする
  • 環境変数でパスワードやAPIキーを管理する(ハードコーディング厳禁)
  • if __name__ == "__main__": で直接実行時のみ動作するようにする
📖 Story — Conclusion

金曜日の夕方。以前なら残業確定の時間帯だが、今日はチーム全員がリラックスしていた。

$ python weekly_report.py
[INFO] 102店舗のデータを集計中...
[INFO] グラフを生成中...
[INFO] PDFレポートを作成中...
[INFO] 完了! output/weekly_report_2025-03-21.pdf

3時間かかっていたレポート作成が、たった30秒で終わる。


あなた: 「嘘でしょ…毎週金曜に3時間かけてた作業がワンクリック?」

あなた: 「しかも、手作業の時よりミスがないんだよね。」

Mika: 「画像のリサイズも自動化できたから、お店のオーナーさんに写真送ってもらったら、5分で全部処理できるようになった!」

Yuki: 「Pythonは『最初の自動化言語』として最高なんだよ。でもね、大事なのは言語じゃなくて自動化マインド。同じことを2回やりそうになったら、まずスクリプトを書けないか考える。」

あなた: 「プログラマーの美徳は怠惰、ですね。」

Yuki: 「その通り。ところで、自動化で空いた時間をどう使う?」

あなた: 「新機能の開発でしょ!でもさ、最近新しい機能を追加するたびに、前の機能が壊れることがあるんだよね…」

Yuki: 「いいところに気づいたね。次はテストの話をしよう。壊れないコードを書く技術だよ。」


次のチャプター: Chapter 22: テストの極意 — 新機能が古い機能を壊す問題。テストピラミッドからTDDまで、品質を守る戦略を学ぶ。

🧠 理解度チェック

Q1.Pythonで変数を宣言する正しい方法は?

💡 Yukiが「Pythonの変数宣言はシンプル。余計なものは不要」と教えてくれたね。

Q2.Pythonのリストで最初の要素にアクセスする方法は?

💡 ShimaLinkの店舗リストを扱ったとき、最初のお店「海風テラス」はshops[0]でアクセスしたね。

Q3.Pythonでファイルを安全に開くための推奨構文は?

💡 Yukiが「withを使えばファイルの閉じ忘れがない」と強調していたのを思い出そう。

Q4.Webスクレイピングで最も重要な倫理的ルールは?

💡 Yukiが「ルールを守らないスクレイピングはサーバーへの攻撃と同じ」と警告していたね。

Q5.cron式 '0 9 * * 1-5' の意味は?

💡 ShimaLinkの日次レポートスクリプトを平日だけ自動実行するための設定だったね。

Q6.PythonのJSONファイル書き出しで日本語を正しく保存するオプションは?

💡 JSONに店舗名を保存した時、\u6d77\u98a8みたいに文字化けした原因がこれだったね。

Q7.Pythonの f"こんにちは、{name}さん" は何と呼ばれる?

💡 レポート生成でf"合計: {total}件"のように使っていた、あの便利な書き方だよ。

Q8.if __name__ == "__main__": の目的は?

💡 自動化スクリプトの最後に必ず書いていた、あのお約束パターンだね。

よくある質問

python3コマンドが見つからない

**Macの場合:** ```bash # Homebrewでインストール brew install python3 # 確認 python3 --version ``` **Windowsの場合:** 1. [python.org](https://python.org) からインストーラーをダウンロード 2. インストール時に「Add Python to PATH」にチェック 3. ターミナルを再起動 `python` と `python3` の違い: Macでは `python` がPython 2を指すことがあるので、必ず `python3` を使いましょう。

IndentationError: unexpected indent が出る

Pythonでは**インデント(字下げ)がコードの構造を決めます**。 **よくある原因:** - タブとスペースが混在している - インデントの深さが不統一(2スペースと4スペースが混在) ```python # NG: インデントが不統一 def hello(): print("A") # 4スペース print("B") # 2スペース → エラー! # OK: 統一されたインデント def hello(): print("A") # 4スペース print("B") # 4スペース ``` **VS Codeの設定:** 「Insert Spaces」をON、Tab Size を 4 に設定しましょう。

pip install でPermissionErrorが出る

**仮想環境(venv)を使いましょう:** ```bash # 仮想環境を作成 python3 -m venv myenv # 有効化(Mac/Linux) source myenv/bin/activate # 有効化(Windows) myenv\Scripts\activate # これでpip installできる pip install requests # 無効化 deactivate ``` `sudo pip install` は**使わないでください**。システムのPythonを壊す可能性があります。

CSVファイルを読み込むと文字化けする

**encoding を明示的に指定**してください: ```python # UTF-8で読み込む with open("data.csv", "r", encoding="utf-8") as f: reader = csv.reader(f) # Excelで作ったCSVはShift-JISの場合がある with open("data.csv", "r", encoding="cp932") as f: reader = csv.reader(f) ``` **エンコーディングの確認方法:** ```bash file -I data.csv # → data.csv: text/csv; charset=utf-8 ```

requestsでConnectionErrorが出る

**ネットワーク接続を確認**してください: ```python import requests try: response = requests.get("https://example.com", timeout=10) print(f"Status: {response.status_code}") except requests.ConnectionError: print("ネットワークに接続できません") except requests.Timeout: print("タイムアウトしました") ``` **チェックリスト:** - インターネット接続があるか - URLが正しいか(httpsのtypoなど) - ファイアウォールやプロキシがブロックしていないか - `timeout` パラメータを設定しているか

BeautifulSoupでfind()がNoneを返す

指定した要素がページに**存在しない**可能性があります: ```python from bs4 import BeautifulSoup # まずHTMLの中身を確認 print(soup.prettify()[:500]) # Noneチェックを入れる element = soup.find("div", class_="shop-card") if element: print(element.text) else: print("要素が見つかりません") ``` **よくある原因:** - クラス名やタグ名の**スペルミス** - JavaScriptで動的に生成されるコンテンツ(BeautifulSoupでは取得不可) - `class_` のアンダースコア忘れ(Pythonの予約語と被るため)

cronジョブが動かない

**よくある原因と対策:** 1. **Pythonのパスが通っていない** ```bash # フルパスで指定する 0 9 * * * /usr/local/bin/python3 /home/user/script.py # パスを確認 which python3 ``` 2. **作業ディレクトリの問題** ```bash # スクリプト内で明示的に設定 0 9 * * * cd /home/user/project && /usr/bin/python3 script.py ``` 3. **ログを取って原因を特定** ```bash 0 9 * * * /usr/bin/python3 /home/user/script.py >> /tmp/cron.log 2>&1 ``` 4. **crontabの確認** ```bash crontab -l # 現在のジョブを一覧表示 ```

Pythonの辞書とリストの違いがわからない

**リスト**は順番に並んだデータ、**辞書**は名前付きのデータです。 | | リスト (list) | 辞書 (dict) | |---|---|---| | 書き方 | `[1, 2, 3]` | `{"key": "value"}` | | アクセス | `data[0]` (番号) | `data["key"]` (名前) | | 用途 | 一覧データ | 構造化データ | | JSでの相当 | `Array` | `Object` | ```python # リスト: お店の名前一覧 shops = ["海風テラス", "首里城カフェ"] print(shops[0]) # → 海風テラス # 辞書: お店の詳細情報 shop = {"name": "海風テラス", "rating": 4.8} print(shop["name"]) # → 海風テラス ```

スクレイピングとAPIの違いは?

| | スクレイピング | API | |---|---|---| | データ取得先 | HTMLページ | 構造化されたエンドポイント | | 安定性 | ページ変更で壊れやすい | 仕様が公開されている | | 速度 | HTMLパース分遅い | 直接データを取得 | | 許可 | 要確認(グレーゾーン) | 提供者が許可している | **結論:** APIがあれば必ずAPIを使う。スクレイピングは最終手段です。 ```python # API(推奨) response = requests.get("https://api.example.com/shops") data = response.json() # スクレイピング(APIがない場合のみ) response = requests.get("https://example.com/shops") soup = BeautifulSoup(response.text, "html.parser") ```

仮想環境(venv)って何?なぜ必要?

**プロジェクトごとにPythonの環境を分離する仕組み**です。 マンションの部屋のように、プロジェクトAとBで異なるバージョンのライブラリを使えます。 ```bash # 作成 python3 -m venv myenv # 有効化 source myenv/bin/activate # Mac/Linux # パッケージインストール pip install requests beautifulsoup4 # 依存関係を記録 pip freeze > requirements.txt # 別の環境で復元 pip install -r requirements.txt # 無効化 deactivate ``` **なぜ必要?** システムのPythonにライブラリを入れると、他のプロジェクトと衝突する可能性があるからです。