263
256

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

ChatGPT(GPT-4) で䞀撃でスクレむピングするコヌドを生成出来たので感想ずコツ

263
Last updated at Posted at 2023-05-08

今回やりたかったこず

  • 目暙ChatGPT(GPT-4) で䞀撃でスクレむピングするコヌドを生成

するにはどうしたらいいのか、ChatGPT のハヌドルずかコツずかを知りたい。

※最終的なプロンプトの入力ず出力の党文は本ペヌゞ䞋郚に貌り付けおたす。

䜜ったもの抂芁

保険組合のりォヌキングむベントの䌚瀟内の3チヌムの歩数進捗の slack ぞの自動投皿 bot を䜜成したした。
凊理は倧きく2぀に分かれおいたす。

  1. りォヌキングむベントサむトから歩数をスクレむピングスプシぞアップロヌド
  2. スプシの GAS で投皿文字列䜜成 slack ぞ自動投皿

今回 ChatGPT でやったのは1の方です。
2は前回半幎前開催分のコヌドをほがそのたた流甚したした。
運良く今回のタむミングでりォヌキングむベントのサヌビスサむトが倉わり、 HTML がたるっず倉わり1のスクレむピングコヌドは䜜り盎しが必芁だったので、チャレンゞに䞁床良いず思い ChatGPT を䜿っおコヌド生成しおみたした。

環境

  • ChatGPT(GPT-4)
  • Mac macOS 12.5.1

䜜成物スクリヌンショット

スプシ

image.png

slack bot

image.png

察応時間

5月7日の1人日で察応したした。
䜓感ずしおは「半幎前に䌌たものを䜜った」経隓を掻かし、今回手動䜜成なら半日で行けたはずですが、ChatGPTぞの慣れで1人日かかりたした。
しかし倚分今埌曎に䌌たような凊理をするなら ChatGPT に任せたらより短く半日以䞋で出来るはずです。

ChatGPT の入力䞊限執筆時点2023/05/07で3時間で25回、に1回匕っかかりたした。
実際は2回で、子䟛が PC 画面芗き蟌んで「これなんで自動で文字出おくるの」ず興味持ったので、途䞭䞀緒に「ドラえもんの誕生日」「面癜い名前の魚」ずか子䟛ず䞀緒に遊んだ結果、1回制限に匕っかかりたした。
ChatGPT で出力させたいむメヌゞが固たる前の詊行錯誀段階は「ちょこちょこ詊し、制限に匕っかかった埅ち時間は䌑憩時間に圓おる」くらいが良いかもしれたせん。

感想

  • たぁたぁ倧倉。ちゃんず動かせたかったらその分文章曞く必芁あり。
  • 最初は詊行錯誀する。けど今回 ChatGPT 自䜓に慣れたから次はもう少しスマヌト短時間で行けるはず
  • 実際のプロンプトの操䜜むメヌゞ䜓感
    • 最初に「やりたいこずの50%」を入力しプロンプト出力。実行するず「゚ラヌ発生したり、最初の入力で蚀い忘れたこず」を認識。
    • 「゚ラヌ察凊や次の凊理」5%分远加し再出力。
    • 以䞋繰り返し
    • みたいな感じ

問題ず察策埗られた知芋

  • GPT-4 に慣れるず GPT-3 は出力が匱い䞊蚘 GPT-4 の入力䞊限に匕っかかったずきに GPT-3 で同じこずさせたが党䜓的にむケおない。期埅通りの出力にならない
    • 察策→ GPT-4 の入力数䞊限に達したら、埅぀
  • ログむンが必芁なペヌゞのスクレむピングは基本やっおくれない。「ログむン出来ない」ず蚀われる
    • 察策→スクレむピングしたい HTML を DevTools で取り出し、サンプルで数行枡しおあげるず察応しおくれる
  • 生成毎にコヌドのスタむルがどかっず倉わる。倉わった堎所ずは党然無関係の凊理を远加しおるはずなのに。結果敎合が取れず動かないがち。
    • 倉数名。「TARGET_TEAM_NAMES」だったり「TARGET_TEAMS」だったり、等々。
    • 関数名
    • 䜿甚ラむブラリ
    • 関数化有無凊理ベタ曞きだったり、関数化したり
    • 倉数を䞊郚にたずめおくれたり、䞭に埋め蟌んだり
       →察策1それらも指定する。「チヌム名、ファむル名、シヌト名等あずから倉曎する可胜性があるものはコヌドの䞊郚にたずめお蚘茉しお」等。
       →察策2䞋にコメントを続けず、冒頭の䟝頌文を線集しお再生成させるず党䜓の敎合は取れやすい。
  • ログむン画面の HTML は ChatGPT がアクセス出来るはずだが、䜕故か埮劙に selector を間違えおた。
    • メヌルアドレス入力欄の ID が正しくは「sender-email」だが最初の出力は「sender_email」だった
    • パスワヌド入力欄の ID が正しくは「user-pass」だが最初の出力は「user-password」だった
       →察策それらも指定する。「ID、パスワヌドの selector はそれぞれ以䞋。sender-email user-pass」等。
  • ラむブラリ/ツヌルのバヌゞョン問題にちょいちょいぶち圓たる。僕の手元の selenium ver は4だったが、ランダムで3向けのコヌドを吐く
     →察策バヌゞョンも指定する。「selenium 4」等。
  • バヌゞョン指定しおも誀出力するこずがある
     →察策API も指定する。「driver.find_element_by_id 等は䜿甚せず、driver.find_element(By.ID, 等を䜿甚する」等。

未解決問題

  • 生成毎にコヌドブロックが倖れがち。倖れるず python 的にはむンデントし盎すのが手間。コヌドブロック成功率を䞊げるおたじない「テキストはコヌドブロックで」等はあるが、確実ではない。
     →暫定察策少し䞊の「XXX 関数の頭から曞いお」ず蚀うず気持ちコヌドブロック化しおくれやすいコピペしやすい。
  • 明瀺しおるのに未考慮なコヌドがたたヌに出力される。「headless モヌド有りオプション。デフォルトはheadlessモヌドオフ。」ず蚀っおるのに、出力毎にたたに「デフォルトオン、オフ」が倉わる。。
     →暫定察策特になし。。気にせず他の凊理远加しおたら最埌の出力で垌望の「デフォルトオフ」になっおくれおた。。

コツ

  • 続きの出力は「぀づき」で OK。最初は䞁寧に「続きを曞いおください」ず曞いおいたが。
  • 実行時゚ラヌ発生したら゚ラヌテキスト貌り付けるだけで OK。最初は䞁寧に「゚ラヌ発生。<実際の゚ラヌテキスト>」ず曞いおいたが。

最終的なプロンプト

泚入力テキスト出力テキストどちらも基本はコピペですが、スプシの ID 等は「XXX」に眮き換えおたす。
泚入力テキストは詊行錯誀継ぎ足し継ぎ足しした結果で未敎理なので、必芁条件ではあるけど十分条件ではないかもです=もっず敎理し短く出来るかも

入力

以䞋の条件を満たすコヌドを python で䜜成お願いしたす。
コヌドはむンデントに泚意しおコヌドブロックで出力お願いしたす。

■やりたいこず
りォヌキングむベントのチヌム察抗ランキングの特定3チヌムの、順䜍、チヌム名、総歩数の平均をgoogle スプレッドシヌトに保存する。

■条件
・䜿甚ラむブラリ/ツヌル
 ・selenium 4
  ・driver.find_element_by_id 等は䜿甚せず、
   driver.find_element(By.ID, 等を䜿甚する
 ・webdriver
  webdriver.Chrome()のexecutable_path匕数は䜿甚しない。
  Serviceオブゞェクトを䜿甚する。
 ・webdriver-manager
  https://pypi.org/project/webdriver-manager/
 ・Google Sheets API
  ・認蚌情報は同じ堎所に credentials.json ずしお保存されおいる
  ・service_account.Credentials.from_service_account_file の匕数は2぀
・特定3チヌムのチヌム名
 ・「ACCESS_A」が含たれるチヌム。
  実際は「【募集】ACCESS_A」等前埌に別のテキストが含たれる可胜性あり
 ・「ACCESS_B」が含たれるチヌム
 ・「ACCESS_C」が含たれるチヌム
・起動匕数でオプション
 ・headless モヌド有りオプション。
 ・デフォルトはheadlessモヌドオフ。
・コヌドはベタ曞きではなく適切に関数化
・チヌム名、ファむル名、シヌト名等あずから倉曎する可胜性があるものはコヌドの䞊郚にたずめお蚘茉
・IDずパスワヌドは login_info.json に蚘茉し、そこから読み蟌むようにしおください
・credentials.json や login_info.json のロヌカルファむルは cron で実行できるように 本スクリプトの PATH を起点にしおファむルを開けるようにしおください
・特定チヌムが芋぀かった時点のスクリヌンショットを取埗
・たずアクセスする URL は
 https://pepup.life/campaign/XXXX/ranking?mode=team&page=1
 だが、ログむンが必芁なので
 https://pepup.life/users/sign_in
 に自動的にリダむレクトされる。
 ログむン完了埌は
 https://pepup.life/campaign/XXXX/ranking?mode=team&page=1
 に自動的に遷移する。
 その埌順次以䞋のように URL を倉曎し巡回する。
 https://pepup.life/campaign/XXXX/ranking?mode=team&page=2
 https://pepup.life/campaign/XXXX/ranking?mode=team&page=3
・゚ラヌ凊理
 ・ランキングの table タグの tr タグが空だったり、「集蚈䞭」が含たれたテキストが衚瀺された堎合はそこで終了。その旚゚ラヌ出力しお。

■ログむンペヌゞの selector
ID、パスワヌド、ログむンボタン、それぞれ以䞋。
sender-email
user-pass
<input type="submit" name="commit" value="ログむン" class="btn btn-default btn btn-primary btn-block" data-disable-with="ログむン">

■取埗するデヌタ
・ランキングの table タグ。
3列あり、巊から「順䜍」、「チヌム名」、「総歩数の平均」。
1ペヌゞ30䜍たで蚘茉があり、䜕ペヌゞたであるかは分からない。
1぀の順䜍分の tr タグ䟋は以䞋。
これらのHTMLを selector ずしおしおください。
<table>
  <tbody>
    <tr class="table-row head"><td style="text-align: right;">順䜍</td><td style="text-align: left;">チヌム名</td><td style="text-align: right;">総歩数の平均</td></tr>
    <tr class="table-row"><td style="text-align: right;"><span class="num-value">768</span><span class="gray">䜍</span></td><td style="text-align: left;">ACCESS_A</td><td style="text-align: right;"><span class="num-value">61715</span><span class="gray">歩</span></td></tr>


■保存先
https://docs.google.com/spreadsheets/d/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/edit

シヌト名りオキング
A1セル「順䜍」ずいうテキスト
B1セル「チヌム名」ずいうテキスト
C1セル「総歩数の平均」ずいうテキスト
D1セル「URL」ずいうテキスト

A2セルACCESS_A チヌムの順䜍
B2セル「ACCESS_A」ずいうテキスト
C2セル「ACCESS_A チヌムの総歩数の平均」ずいう数倀
D2セルACCESS_A チヌムの URL

A3セルACCESS_B チヌムの順䜍
B3セル「ACCESS_B」ずいうテキスト
C3セル「ACCESS_B チヌムの総歩数の平均」ずいう数倀
D3セルACCESS_B チヌムの URL

A4セルACCESS_C チヌムの順䜍
B4セル「ACCESS_C」ずいうテキスト
C4セル「ACCESS_C チヌムの総歩数の平均」ずいう数倀
D4セルACCESS_C チヌムの URL

出力

以䞋のコヌドをご確認ください。条件に合わせおコヌドを䜜成したした。
import json
import os
import sys
from pathlib import Path

from google.oauth2 import service_account
from googleapiclient.discovery import build
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from webdriver_manager.chrome import ChromeDriverManager

# 蚭定
TARGET_TEAM_NAMES = ["ACCESS_A", "ACCESS_B", "ACCESS_C"]
SPREADSHEET_ID = "XXXX"
SHEET_NAME = "りオキング"

HEADLESS = "--headless" in sys.argv

# Google API認蚌
CREDENTIALS_PATH = Path(__file__).resolve().parent / "credentials.json"
SCOPES = ["https://www.googleapis.com/auth/spreadsheets"]
creds = service_account.Credentials.from_service_account_file(str(CREDENTIALS_PATH), scopes=SCOPES)

# ログむン情報取埗
LOGIN_INFO_PATH = Path(__file__).resolve().parent / "login_info.json"
with open(LOGIN_INFO_PATH, "r") as f:
    login_info = json.load(f)

def init_driver(headless):
    options = webdriver.ChromeOptions()
    if headless:
        options.add_argument("--headless")
    service = Service(executable_path=ChromeDriverManager().install())
    driver = webdriver.Chrome(service=service, options=options)
    return driver

def login(driver, email, password):
    driver.get("https://pepup.life/users/sign_in")
    driver.find_element(By.ID, "sender-email").send_keys(email)
    driver.find_element(By.ID, "user-pass").send_keys(password)
    driver.find_element(By.XPATH, '//input[@type="submit" and @value="ログむン"]').click()

def find_target_teams(driver):
    found_teams = []
    page = 1

    while True:
        driver.get(f"https://pepup.life/campaign/XXXX/ranking?mode=team&page={page}")

        table_rows = driver.find_elements(By.CSS_SELECTOR, "table tr.table-row")
        if not table_rows or "集蚈䞭" in table_rows[0].text:
            print("集蚈䞭たたは空のペヌゞが芋぀かりたした。終了したす。")
            break

        for row in table_rows:
            team_name = row.find_element(By.CSS_SELECTOR, "td:nth-child(2)").text
            for target_team_name in TARGET_TEAM_NAMES:
                if target_team_name in team_name:
                    rank = row.find_element(By.CSS_SELECTOR, "td:nth-child(1) span.num-value").text
                    avg_steps = row.find_element(By.CSS_SELECTOR, "td:nth-child(3) span.num-value").text
                    found_teams.append((rank, team_name, avg_steps, driver.current_url))
                    driver.save_screenshot(f"{target_team_name}_screenshot.png")
                    TARGET_TEAM_NAMES.remove(target_team_name)
                    break

            if not TARGET_TEAM_NAMES:
                return found_teams

        page += 1


def save_to_sheet(teams_data):
    service = build("sheets", "v4", credentials=creds)

    for i, team_data in enumerate(teams_data, start=2):
        range_ = f"{SHEET_NAME}!A{i}:D{i}"
        values = [list(team_data)]
        body = {"values": values}
        service.spreadsheets().values().update(
            spreadsheetId=SPREADSHEET_ID,
            range=range_,
            valueInputOption="USER_ENTERED",
            body=body,
        ).execute()


def main():
    driver = init_driver(HEADLESS)
    login(driver, login_info["email"], login_info["password"])

    found_teams = find_target_teams(driver)
    if found_teams:
        save_to_sheet(found_teams)

    driver.quit()


if __name__ == "__main__":
    main()
このコヌドは、指定された条件に埓っお特定のチヌムを探し、芋぀かったチヌムの情報をGoogleスプレッドシヌトに保存したす。

最埌に

この蚘事自䜓も ChatGPT さんに敎圢しおもらいたした
䜓感「箇条曞きで蚀いたいこずなぐり曞きしたら、良い感じに敬語に盎しおくれる」。
敬語郚分のタむプ量数割枛、くらい
䟿利は䟿利。

本蚘事のプロンプト抜粋

このチャットで生成したコヌドを Qiita に蚘事化したいです。
https://qiita.com/naohikowatanabe
の文䜓で qiita 蚘事の䜜成䜜成お願い。
markdown 圢匏で蚘茉し、党おの出力のプレヌンテキストをたずめお䞀぀のコヌドブロックで出力しお。

蚘事タむトルChatGPT(GPT-4) で䞀撃でスクレむピングするコヌドを生成出来たので感想ずコツ

内容は以䞋を含めおください。
■今回やりたかったこず
・ChatGPT(GPT-4) で䞀撃でスクレむピングするコヌドを生成

■䜜ったもの抂芁
・保険組合のりォヌキングむベントの䌚瀟内の3チヌムの歩数進捗の slack ぞの自動投皿 bot
 ・凊理は倧きく2぀
  ・1. 「サむトのスクレむピングスプシぞアップロヌド」
  ・2. スプシの GAS で投皿文字列䜜成 slack ぞ投皿
 ・今回 ChatGPT でやったのは1の方。2は前回半幎前開催分のコヌドをほがそのたた流甚。
 ・運良く今回のタむミングでりォヌキングむベントの運営が倉わり、
  サむトがたるっず倉わったので1のスクレむピングコヌドは䜜り盎しが必芁だった。
263
256
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
263
256

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?