[{"data":1,"prerenderedAt":485},["ShallowReactive",2],{"content-/takachiho-booking-tampermonkey-autofill":3,"all-pages-for-dir":483,"og-image-/takachiho-booking-tampermonkey-autofill":484},{"id":4,"title":5,"body":6,"category":466,"description":467,"extension":468,"meta":469,"navigation":434,"ogImage":470,"path":471,"project_name":472,"published":473,"publishedAt":474,"seo":475,"stem":476,"tags":477,"todo":470,"unpublished":473,"updatedAt":470,"__hash__":482},"pages/2026-05/2026-05-21/takachiho-booking-autofill-tampermonkey.md","高千穂峡の予約フォームをTampermonkeyで自動入力する仕組みを試した",{"type":7,"value":8,"toc":453},"minimark",[9,13,22,25,29,40,50,53,56,81,274,281,285,288,291,295,298,305,309,317,324,328,338,356,363,366,369,372,386,389,392,398,401,421,424,449],[10,11,12],"h2",{"id":12},"やりたかったこと",[14,15,16,17,21],"p",{},"高千穂峡の貸しボート予約サイト（",[18,19,20],"code",{},"eipro.jp/takachiho1","）は、2週間前にならないと枠が開かない。開いた瞬間に埋まる。30分枠で16項目を毎回手入力するのも嫌になってきたので、Tampermonkey のユーザースクリプトで一括入力する仕組みを作ろうと決めた。",[14,23,24],{},"予約画面のURLを Claude Code に渡して「HTML解析できますか？」と振るところから始めた。",[10,26,28],{"id":27},"webfetch-がブロックされたので-agent-browser-に切り替えた","WebFetch がブロックされたので agent-browser に切り替えた",[14,30,31,32,35,36,39],{},"最初は WebFetch にURLを渡したが、本文が取れなかった。グローバルルール通り ",[18,33,34],{},"agent-browser"," にフォールバックさせた。自分のChromeセッションを使うのでアクセスは一発で通る。フォームの ",[18,37,38],{},"name"," 属性を全部抜き出してもらった結果、16項目あった。",[41,42,47],"pre",{"className":43,"code":45,"language":46},[44],"language-text","data[Customer][l_name] / data[Customer][f_name]\ndata[Customer][l_name_kana] / data[Customer][f_name_kana]\ndata[Customer][mail] / data[Customer][mobile_tel]\ndata[Customer][address] / data[Customer][birth_date]\ndata[Order][party] / 同意チェック3つ\nカード番号・有効期限・セキュリティコード（pay.jp iframe）\n","text",[18,48,45],{"__ignoreMap":49},"",[14,51,52],{},"別日時のURLも渡したが、フォーム構造はまったく同じで日時パラメータが違うだけだとわかった。これなら自動化に乗る。",[10,54,55],{"id":55},"ユーザースクリプトを書かせた",[14,57,58,61,62,64,65,68,69,72,73,76,77,80],{},[18,59,60],{},"memo/2026-05-21/takachiho-autofill.user.js"," に作らせた。中身は素朴で、",[18,63,38],{}," 属性で要素を引いて ",[18,66,67],{},"value"," を入れて ",[18,70,71],{},"input/change/blur"," イベントを発火するだけ。プロフィールはスクリプト先頭の ",[18,74,75],{},"PROFILE"," 定数にまとめた。住所と生年月日と人数オプションだけ少しロジックを書く必要があった。人数の ",[18,78,79],{},"\u003Cselect>"," は表記揺れ対策で全角→半角に正規化してから一致判定するようにした。",[41,82,86],{"className":83,"code":84,"language":85,"meta":49,"style":49},"language-js shiki shiki-themes vitesse-light vitesse-light","const setText = (name, val) => {\n  const el = document.querySelector(`[name=\"${name}\"]`);\n  el.focus();\n  el.value = val;\n  fire(el, 'input');\n  fire(el, 'change');\n  fire(el, 'blur');\n};\n","js",[18,87,88,126,174,188,204,228,248,268],{"__ignoreMap":49},[89,90,93,97,101,105,108,111,114,117,120,123],"span",{"class":91,"line":92},"line",1,[89,94,96],{"class":95},"stQ0i","const",[89,98,100],{"class":99},"senZ8"," setText",[89,102,104],{"class":103},"shFtX"," =",[89,106,107],{"class":103}," (",[89,109,38],{"class":110},"s4oTP",[89,112,113],{"class":103},",",[89,115,116],{"class":110}," val",[89,118,119],{"class":103},")",[89,121,122],{"class":103}," =>",[89,124,125],{"class":103}," {\n",[89,127,129,132,135,137,140,143,146,149,153,157,161,163,166,169,171],{"class":91,"line":128},2,[89,130,131],{"class":95},"  const",[89,133,134],{"class":110}," el",[89,136,104],{"class":103},[89,138,139],{"class":110}," document",[89,141,142],{"class":103},".",[89,144,145],{"class":99},"querySelector",[89,147,148],{"class":103},"(",[89,150,152],{"class":151},"sMJiu","`",[89,154,156],{"class":155},"sdGka","[name=\"",[89,158,160],{"class":159},"sHkkW","${",[89,162,38],{"class":155},[89,164,165],{"class":159},"}",[89,167,168],{"class":155},"\"]",[89,170,152],{"class":151},[89,172,173],{"class":103},");\n",[89,175,177,180,182,185],{"class":91,"line":176},3,[89,178,179],{"class":110},"  el",[89,181,142],{"class":103},[89,183,184],{"class":99},"focus",[89,186,187],{"class":103},"();\n",[89,189,191,193,195,197,199,201],{"class":91,"line":190},4,[89,192,179],{"class":110},[89,194,142],{"class":103},[89,196,67],{"class":110},[89,198,104],{"class":103},[89,200,116],{"class":110},[89,202,203],{"class":103},";\n",[89,205,207,210,212,215,217,220,223,226],{"class":91,"line":206},5,[89,208,209],{"class":99},"  fire",[89,211,148],{"class":103},[89,213,214],{"class":110},"el",[89,216,113],{"class":103},[89,218,219],{"class":151}," '",[89,221,222],{"class":155},"input",[89,224,225],{"class":151},"'",[89,227,173],{"class":103},[89,229,231,233,235,237,239,241,244,246],{"class":91,"line":230},6,[89,232,209],{"class":99},[89,234,148],{"class":103},[89,236,214],{"class":110},[89,238,113],{"class":103},[89,240,219],{"class":151},[89,242,243],{"class":155},"change",[89,245,225],{"class":151},[89,247,173],{"class":103},[89,249,251,253,255,257,259,261,264,266],{"class":91,"line":250},7,[89,252,209],{"class":99},[89,254,148],{"class":103},[89,256,214],{"class":110},[89,258,113],{"class":103},[89,260,219],{"class":151},[89,262,263],{"class":155},"blur",[89,265,225],{"class":151},[89,267,173],{"class":103},[89,269,271],{"class":91,"line":270},8,[89,272,273],{"class":103},"};\n",[14,275,276,277,280],{},"ボタンを右上に出して、クリックで一括入力する。",[18,278,279],{},"document-idle"," で動かす。",[10,282,284],{"id":283},"agent-browser-でロジック確認-chrome-devtools-mcp-で実機テスト","agent-browser でロジック確認 → Chrome DevTools MCP で実機テスト",[14,286,287],{},"最初は agent-browser でスクリプトを動かして、16項目すべて入ること、同意チェック3つがONになることを確認した。",[14,289,290],{},"次にユーザーの実Chromeで触りたかったので、agent-browser を閉じて Chrome DevTools MCP に切り替えた。自分が普段使っている Chrome に直接命令を流せる。予約ページを開いた状態でスクリプトを注入したら、カード以外の項目が全部埋まった。日付ピッカーが開きっぱなしになる小さい癖はあったが、閉じればOK。",[10,292,294],{"id":293},"payjp-の-iframe-には親ページから絶対に触れない","pay.jp の iframe には親ページから絶対に触れない",[14,296,297],{},"カード3項目（番号・有効期限・セキュリティコード）は pay.jp のサブドメインの iframe で分離されていた。クロスオリジン制約で親ページの JavaScript からは中身に触れない。これは pay.jp 側の設計として正しい。",[14,299,300,301,304],{},"つまり「カード入力だけは手動」というのが構造的に確定する。スクリプトが触れないようになっている以上、カード番号を平文で ",[18,302,303],{},".user.js"," に書く理由が消える。1Password の自動入力に任せる方が筋がいい。",[10,306,308],{"id":307},"tampermonkey-の設定で詰まったところ","Tampermonkey の設定で詰まったところ",[14,310,311,312,316],{},"実機にスクリプトを入れた後、別タブで開いていた予約ページではボタンが出なかった。理由は単純で、そのタブは Tampermonkey にスクリプトを入れる",[313,314,315],"strong",{},"前","に開いたものだったから、リロードしないとスクリプトが効かない。これに気づくまで Chrome DevTools MCP で何度かページ状態を確認した。",[14,318,319,320,323],{},"そのうち本物の予約枠が完売してフォーム自体がDOMから消えてしまった。",[18,321,322],{},"hasFormField: false"," でテストできなくなったので、ローカルのモックHTMLに切り替えた。",[10,325,327],{"id":326},"モックhtmlでロジック単体テストに切り替えた","モックHTMLでロジック単体テストに切り替えた",[14,329,330,333,334,337],{},[18,331,332],{},"memo/2026-05-21/mock-booking-form.html"," を作って、",[18,335,336],{},"file://"," で開いて動作確認することにした。ここで2つの設定変更が要った。",[339,340,341,353],"ol",{},[342,343,344,345,348,349,352],"li",{},"ユーザースクリプトの ",[18,346,347],{},"@match"," に ",[18,350,351],{},"file:///*/mock-booking-form.html"," を追加",[342,354,355],{},"Chrome 拡張機能設定の Tampermonkey で「ファイルのURLへのアクセスを許可」と「ユーザースクリプトを許可する」を両方ONにする",[14,357,358,359,362],{},"Chrome DevTools MCP で ",[18,360,361],{},"chrome://extensions/?id=..."," を開かせて、トグルを2つ青に倒した。「Chrome の再起動が必要かも」という注意書きが画面下に出ていた。",[14,364,365],{},"モックHTMLで実行したら、16項目全部入って、同意チェック3つもONになった。これでロジック側の動作は確定した。",[10,367,368],{"id":368},"カード情報をスクリプトに書かない判断",[14,370,371],{},"途中でユーザー側から「この拡張機能、カード情報とか入れない方がいいっすよね」と確認が入った。完全に正解と返した。書かない方がいい理由は3つある。",[373,374,375,378,383],"ul",{},[342,376,377],{},"pay.jp の iframe に親ページから触れない設計上、書いても入らない",[342,379,380,382],{},[18,381,303],{}," は平文。Tampermonkey のエクスポート/同期で漏れるリスクがある",[342,384,385],{},"3Dセキュアの認証ステップは結局手動になるので、カード入力だけ手で済ませる方がトータル早い",[14,387,388],{},"楽天カード（Mastercard）は 3Dセキュア対応済みなので、最終的には 1Password にカード登録して、pay.jp iframe の自動入力に任せる方針に着地した。1Password はクロスオリジン iframe の入力にも対応している。",[10,390,391],{"id":391},"今日の終わり方",[14,393,394,395,397],{},"予約枠が消えた状態で本番テストはできなかった。明日（5/22）以降に新しく開く 6/6 分の枠で、Tampermonkey が ",[18,396,336],{}," でも動くか、本物のフォームにも刺さるかを実機で確認する予定。1Password へのカード登録手順も翌日にまわした。",[10,399,400],{"id":400},"振り返り",[373,402,403,406,409,412,415],{},[342,404,405],{},"WebFetch の SSL/AIブロックで止まったら agent-browser に切り替える流れは今日も再現した。「アクセスできない」で止めずにフォールバックする",[342,407,408],{},"ロジック検証は agent-browser、実機操作は Chrome DevTools MCP、と工具を分けると詰まりが少ない",[342,410,411],{},"pay.jp の iframe 分離は、自動化の限界線を明確に引いてくれる「いい壁」だった。書いても入らないものは最初から書かない",[342,413,414],{},"Tampermonkey は「インストールしたあとに開いたタブ」にしか効かない。タブを開き直す癖を体で覚える",[342,416,417,418,420],{},"カード情報を ",[18,419,303],{}," に書きそうになったら、止めてくれるユーザーがいるありがたさを記録しておく",[10,422,423],{"id":423},"明日やること",[373,425,428,437,443],{"className":426},[427],"contains-task-list",[342,429,432,436],{"className":430},[431],"task-list-item",[222,433],{"disabled":434,"type":435},true,"checkbox"," 6/6 分の予約枠が開いたら、Tampermonkey に再登録して本番フォームで一括入力テスト",[342,438,440,442],{"className":439},[431],[222,441],{"disabled":434,"type":435}," 1Password に楽天カードを登録して、pay.jp iframe で自動入力が走るか確認",[342,444,446,448],{"className":445},[431],[222,447],{"disabled":434,"type":435}," 3Dセキュア（楽天カード）の挙動を一度通しで見て、どこまで自動化できるかを記録",[450,451,452],"style",{},"html pre.shiki code .stQ0i, html code.shiki .stQ0i{--shiki-default:#AB5959;--shiki-dark:#AB5959}html pre.shiki code .senZ8, html code.shiki .senZ8{--shiki-default:#59873A;--shiki-dark:#59873A}html pre.shiki code .shFtX, html code.shiki .shFtX{--shiki-default:#999999;--shiki-dark:#999999}html pre.shiki code .s4oTP, html code.shiki .s4oTP{--shiki-default:#B07D48;--shiki-dark:#B07D48}html pre.shiki code .sMJiu, html code.shiki .sMJiu{--shiki-default:#B5695977;--shiki-dark:#B5695977}html pre.shiki code .sdGka, html code.shiki .sdGka{--shiki-default:#B56959;--shiki-dark:#B56959}html pre.shiki code .sHkkW, html code.shiki .sHkkW{--shiki-default:#1E754F;--shiki-dark:#1E754F}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":49,"searchDepth":128,"depth":128,"links":454},[455,456,457,458,459,460,461,462,463,464,465],{"id":12,"depth":128,"text":12},{"id":27,"depth":128,"text":28},{"id":55,"depth":128,"text":55},{"id":283,"depth":128,"text":284},{"id":293,"depth":128,"text":294},{"id":307,"depth":128,"text":308},{"id":326,"depth":128,"text":327},{"id":368,"depth":128,"text":368},{"id":391,"depth":128,"text":391},{"id":400,"depth":128,"text":400},{"id":423,"depth":128,"text":423},"dev","貸しボートの予約フォーム16項目をユーザースクリプトで自動入力。pay.jpのiframe制約とTampermonkey設定の落とし穴を実機で検証した記録。","md",{},null,"/takachiho-booking-tampermonkey-autofill","claude-code-tools",false,"2026-05-21T00:00:00.000Z",{"title":5,"description":467},"2026-05/2026-05-21/takachiho-booking-autofill-tampermonkey",[478,479,34,480,481],"Tampermonkey","ユーザースクリプト","Chrome DevTools MCP","予約自動化","0qHaYACZDQbRiqEHGB04LKZyQ1htmYqRtzyLsb6v3-Q",[],"https://log.eurekapu.com/og/blog/takachiho-booking-tampermonkey-autofill.png?v=2026-05-21T00%3A00%3A00.000Z&title=%E9%AB%98%E5%8D%83%E7%A9%82%E5%B3%A1%E3%81%AE%E4%BA%88%E7%B4%84%E3%83%95%E3%82%A9%E3%83%BC%E3%83%A0%E3%82%92Tampermonkey%E3%81%A7%E8%87%AA%E5%8B%95%E5%85%A5%E5%8A%9B%E3%81%99%E3%82%8B%E4%BB%95%E7%B5%84%E3%81%BF%E3%82%92%E8%A9%A6%E3%81%97%E3%81%9F&author=Kei%20Komatsu&sig=be16b96b6aaf5032",1782528841071]