[メモ] Python + Selenium でメルカリのフォローリストをスクレイピングする（bot 検知回避付き）



## 🔍 なぜ作ったのか？
- 自分のフォローリストを抽出したかったのですが、手作業でコピペするには多すぎたため、自動で取得できるスクリプトをメモとして残しておきます。
- これは個人のデータ整理のためのスクリプトです。

## ⚠️ 注意点
- スクレイピング技術はサイトの利用規約に違反する可能性があるため、適切に使用してください。
- 大量のリクエストを送るとサイトに負荷をかける可能性があるので、適切な遅延を入れて動作させるようにしましょう（というかしない）

## 💡 反省点
- 今思えばこんな面倒をしなくても描画済みの HTML を解析してデータを抜き出せば良かった


```python
import undetected_chromedriver as uc
import time
import random
import os
import pandas as pd
from dotenv import load_dotenv
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

# 環境変数の読み込み（ログイン情報は.envに保存）
load_dotenv()
MERCARI_EMAIL = os.getenv("MERCARI_EMAIL")  #.env を使う
MERCARI_PASSWORD = os.getenv("MERCARI_PASSWORD")

# Chrome オプション設定（bot 検知を回避）
options = uc.ChromeOptions()
options.add_argument("--disable-blink-features=AutomationControlled")
options.add_argument("--disable-gpu")
options.add_argument("--no-sandbox")
options.add_argument("--disable-dev-shm-usage")
options.add_argument("--disable-extensions")
options.add_argument("--start-maximized")
options.add_argument("--user-agent=Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36")

# `undetected_chromedriver` を使用（バージョン指定）
driver = uc.Chrome(version_main=132, options=options)
driver.implicitly_wait(5)

# メルカリのログインページへ移動(+param
driver.get("https://login.jp.mercari.com/signin")
print("✅ メルカリのログインページを開きました！")

wait = WebDriverWait(driver, 10)

# メールとパスワードの入力
email_input = wait.until(EC.presence_of_element_located((By.NAME, "emailOrPhone")))
for char in MERCARI_EMAIL:
    email_input.send_keys(char)
    time.sleep(random.uniform(0.1, 0.4))  

password_input = wait.until(EC.presence_of_element_located((By.NAME, "password")))
for char in MERCARI_PASSWORD:
    password_input.send_keys(char)
    time.sleep(random.uniform(0.1, 0.4))

# ログインボタンをクリック
login_button = wait.until(EC.element_to_be_clickable((By.XPATH, "//button[@type='submit']")))
ActionChains(driver).move_to_element(login_button).pause(random.uniform(0.5, 1.5)).click().perform()
print("✅ ログインボタンをクリックしました")

# 2段階認証の処理（必要なら入力）
try:
    mfa_input = wait.until(EC.presence_of_element_located((By.NAME, "otp")))
    otp_code = input("🔐 2段階認証コードを入力してください: ")
    for char in otp_code:
        mfa_input.send_keys(char)
        time.sleep(random.uniform(0.1, 0.3))
    mfa_input.send_keys(Keys.RETURN)
    print("✅ 2段階認証を突破しました")
except:
    print("✅ 2段階認証は不要でした")

# フォローユーザーページへ移動
driver.get("https://jp.mercari.com/mypage/follow/users")
time.sleep(5)

# スクロールして全てのフォローアカウントを取得
prev_height = driver.execute_script("return document.body.scrollHeight")

while True:
    driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
    time.sleep(random.uniform(1.5, 2.5))  
    new_height = driver.execute_script("return document.body.scrollHeight")
    if new_height == prev_height:
        break
    prev_height = new_height

# ユーザーリスト取得
user_data = []
user_elements = driver.find_elements(By.CSS_SELECTOR, "a[href*='/user/profile/']")

for user_element in user_elements:
    user_url = user_element.get_attribute("href")
    user_id = user_url.split("/")[-1]  # user ID の抽出
    profile_url = f"https://jp.mercari.com/user/profile/{user_id}"

    # ユーザー名の取得
    try:
        user_name_element = user_element.find_element(By.XPATH, ".//p[contains(@class, 'merText')]")
        user_name = user_name_element.text.strip()
    except:
        user_name = "Unknown User"

    # アイコン画像の取得
    try:
        image_element = user_element.find_element(By.XPATH, ".//img")
        image_url = image_element.get_attribute("src")
    except:
        image_url = "No Image"

    user_data.append([user_name, profile_url, image_url])

# CSVに保存
df = pd.DataFrame(user_data, columns=["User Name", "Profile URL", "Image URL"])
df.to_csv("mercari_following_list.csv", index=False, encoding="utf-8-sig")

print("✅ データをCSVに保存しました: mercari_following_list.csv")

# 終了処理
driver.quit()
print("🚪 ブラウザを閉じました。")

```