Go to list of users who liked
Share on X(Twitter)
Share on Facebook
More than 1 year has passed since last update.
ChatGPT(GPT-4) で一撃でスクレイピングするコードを生成出来たので感想とコツ
今回やりたかったこと
- 目標:ChatGPT(GPT-4) で一撃でスクレイピングするコードを生成
するにはどうしたらいいのか、ChatGPT のハードルとかコツとかを知りたい。
※最終的なプロンプトの入力と出力の全文は本ページ下部に貼り付けてます。
作ったもの概要
保険組合のウォーキングイベントの会社内の3チームの歩数進捗の slack への自動投稿 bot を作成しました。
処理は大きく2つに分かれています。
- ウォーキングイベントサイトから歩数をスクレイピング&スプシへアップロード
- スプシの GAS で投稿文字列作成& slack へ自動投稿
今回 ChatGPT でやったのは1の方です。
2は前回半年前開催分のコードをほぼそのまま流用しました。
運良く(?)今回のタイミングでウォーキングイベントのサービスサイトが変わり、 HTML がまるっと変わり1のスクレイピングコードは作り直しが必要だったので、チャレンジに丁度良いと思い ChatGPT を使ってコード生成してみました。
環境
- ChatGPT(GPT-4)
- Mac macOS 12.5.1
作成物スクリーンショット
スプシ
slack bot
対応時間
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 タグが空だったり、「集計中」が含まれたテキストが表示された場合はそこで終了。その旨エラー出力して。■ログインページの selectorID、パスワード、ログインボタン、それぞれ以下。sender-emailuser-pass<input type="submit" name="commit" value="ログイン" data-disable-with="ログイン">■取得するデータ・ランキングの table タグ。3列あり、左から「順位」、「チーム名」、「総歩数の平均」。1ページ30位まで記載があり、何ページまであるかは分からない。1つの順位分の tr タグ例は以下。これらのHTMLを selector としてしてください。<table> <tbody> <tr><td>順位</td><td>チーム名</td><td>総歩数の平均</td></tr> <tr><td><span>768</span><span>位</span></td><td>ACCESS_A</td><td><span>61715</span><span>歩</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 チームの URLA3セル:ACCESS_B チームの順位B3セル:「ACCESS_B」というテキストC3セル:「ACCESS_B チームの総歩数の平均」という数値D3セル:ACCESS_B チームの URLA4セル:ACCESS_C チームの順位B4セル:「ACCESS_C」というテキストC4セル:「ACCESS_C チームの総歩数の平均」という数値D4セル:ACCESS_C チームの URL出力
以下のコードをご確認ください。条件に合わせてコードを作成しました。importjsonimportosimportsysfrompathlibimportPathfromgoogle.oauth2importservice_accountfromgoogleapiclient.discoveryimportbuildfromseleniumimportwebdriverfromselenium.webdriver.chrome.serviceimportServicefromselenium.webdriver.common.byimportByfromwebdriver_manager.chromeimportChromeDriverManager# 設定TARGET_TEAM_NAMES=["ACCESS_A","ACCESS_B","ACCESS_C"]SPREADSHEET_ID="XXXX"SHEET_NAME="ウオキング"HEADLESS="--headless"insys.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"withopen(LOGIN_INFO_PATH,"r")asf:login_info=json.load(f)definit_driver(headless):options=webdriver.ChromeOptions()ifheadless:options.add_argument("--headless")service=Service(executable_path=ChromeDriverManager().install())driver=webdriver.Chrome(service=service,options=options)returndriverdeflogin(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()deffind_target_teams(driver):found_teams=[]page=1whileTrue: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")ifnottable_rowsor"集計中"intable_rows[0].text:print("集計中または空のページが見つかりました。終了します。")breakforrowintable_rows:team_name=row.find_element(By.CSS_SELECTOR,"td:nth-child(2)").textfortarget_team_nameinTARGET_TEAM_NAMES:iftarget_team_nameinteam_name:rank=row.find_element(By.CSS_SELECTOR,"td:nth-child(1) span.num-value").textavg_steps=row.find_element(By.CSS_SELECTOR,"td:nth-child(3) span.num-value").textfound_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)breakifnotTARGET_TEAM_NAMES:returnfound_teamspage+=1defsave_to_sheet(teams_data):service=build("sheets","v4",credentials=creds)fori,team_datainenumerate(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()defmain():driver=init_driver(HEADLESS)login(driver,login_info["email"],login_info["password"])found_teams=find_target_teams(driver)iffound_teams:save_to_sheet(found_teams)driver.quit()if__name__=="__main__":main()このコードは、指定された条件に従って特定のチームを探し、見つかったチームの情報をGoogleスプレッドシートに保存します。最後に
この記事自体も ChatGPT さんに整形してもらいましたw
体感「箇条書きで言いたいことなぐり書きしたら、良い感じに敬語に直してくれる」。
敬語部分のタイプ量数割減、くらい?
便利は便利。
本記事のプロンプト抜粋
このチャットで生成したコードを 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のスクレイピングコードは作り直しが必要だった。Register as a new user and use Qiita more conveniently
- You get articles that match your needs
- You can efficiently read back useful information
- You can use dark theme


