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("🚪 ブラウザを閉じました。")