ããã«ã¡ã¯ãèã®ç©´ã©ãã®H.Hã§ãã
ä»åã¯å
æ¥çºè¡¨ãããChromeã®éçºä¸ã®æ°æ©è½ã§ããRecorderæ©è½ã«ã¤ãã¦ä½¿ç¨æ¹æ³ãå©ç¨ããéã®æ³¨æç¹ãªã©ãã¾ã¨ãã¾ããã
Recoderæ©è½ã¨ã¯
ãã©ã¦ã¶ã®Chrome97ã§è¿½å ãããäºå®ã®æ©è½ã§ããã©ã¦ã¶ã®ç»é¢ä¸ã§æä½ããè¨é²ãåå¾ãã¦ãããæ©è½ã«ãªãã¾ãã
ãã®è¨äºãæ¸ãã¦ãã2021å¹´11æ17æ¥ã§ã¯ä¸è¬ã«æä¾ããã¦ããChromeã®ææ°çã¯96ã¨ãªããéçºä¸ã®ãChrome Devããããã¯ãChrome Canaryãã§Recorderæ©è½ã使ç¨ãããã¨ãã§ãã¾ãã
å©ç¨ãã¦ããæã®æ§åã¯Chromeã®éçºè
åãã®ãã¼ã¸ã«å
¬éããã¦ãã¾ãã
ä¸»ãªæ©è½ã¯ä»¥ä¸ã®éãã§ãã
ã»æä½ã®è¨é²åã³åå®è¡(ãªãã¬ã¤)ã§ãã
ã»åå®è¡æã«ããã©ã¼ãã³ã¹ã®è¨é²ã»ç¢ºèªã§ãã
ã»è¨é²ããå
容ã®ç·¨éãã§ãã
ã»æä½ãPuppeteer(Chromeãèªåã§ç»é¢æä½ãè¡ãNode.jsã®ã©ã¤ãã©ãª)ã§å®è¡ã§ããè¨å®ãã¡ã¤ã«ãåºåã§ãã
ä»åPuppeteerã§å®è¡ã§ããè¨å®ãã¡ã¤ã«ãã©ã®ãããªãã®ã«ãªãã®ãã確èªããããã«ãRecorderæ©è½ã試ãã«ä½¿ã£ã¦ã¿ã¾ããã
è¨é²ããå
容ã¯Googleã®æ¤ç´¢ãã¼ã¸ã§ãèã®ç©´ã©ãããæ¤ç´¢ãã¦ãã³ã¼ãã¬ã¼ããµã¤ãã¾ã§ã¢ã¯ã»ã¹ããæä½ãåå¾ãã¦ããã¾ãã
å©ç¨éå§æé
ä»åã¯Macçã®ãChrome Devããå©ç¨ãã¦ç¢ºèªãã¦ããã¾ãã
1.ã¤ã³ã¹ãã¼ã«
以ä¸ã®ãªã³ã¯ã«ã¢ã¯ã»ã¹ãã¦ãã¢ããªã±ã¼ã·ã§ã³ããã¦ã³ãã¼ããã¦ã¤ã³ã¹ãã¼ã«ãã¾ãã
æé ã¯ãªãªã¼ã¹ããã¦ããä¸è¬å
¬éããã¦ããChromeã¨å¤ããã¾ããã
ã¾ããç°ãªãã¢ããªã±ã¼ã·ã§ã³ã¨ãã¦ã¿ãªãããã®ã§æ¢åã®Chromeã«ä¸æ¸ãããããã¨ãããã¾ããã
2.èµ·å
ã¤ã³ã¹ãã¼ã«ããã¨Chromeã®ãã´ã®ä¸ã«ãDevãã¨æ¸ãããã¢ããªã±ã¼ã·ã§ã³ãã§ããã®ã§ããã®ã¾ã¾èµ·åãã¾ãã
ã¡ãªã¿ã«Chromeã«ã¯ãªãªã¼ã¹ããããã¼ã¸ã§ã³ã®ä»ã«ãä¸ã¤å
ã®ãã¼ã¸ã§ã³ã§ãããBetaãçãããã«å
ã®ãã¼ã¸ã§ã³ã®ãDevãçãéçºä¸ã®å
å®¹ãæ¯æ¥é©ç¨ããããCanaryãçãããã¾ãã
ãã´ã¯ä¸ã®ç»åã®ããã«ãªã£ã¦ãã¾ããå·¦ããä¸è¬å
¬éãããChromeãBetaçãDevçãCanaryçã¨ãªãã¾ãã
3.Recorderã¿ãã®è¡¨ç¤º
Developerãã¼ã«ã«ã¯æ¨æºã§ã¯Recorderã®ã¿ãã¯åºã¦ãã¾ããã®ã§ãæ¯è»ãã¼ã¯ã®å³é£ã®ãã¿ã³ãã表示ããå¿
è¦ãããã¾ãã
ãMore ToolsãâãRecorderã
鏿ããã¨ä¸è¨ã®ãããªã¿ãã表示ããã¾ãã
Recorderæ©è½ã®å©ç¨æ¹æ³
1.è¨é²æ¹æ³
1.1äºåæºå
è¨é²ãéå§ãããã¼ã¸ã表示ãã¦ããã¾ãã
æ¬¡ã®æé ã§è¨é²ã«ååãã¤ãã¦ç¢ºå®ããã¨ããã«è¨é²ãå§ã¾ãã®ã§ãäºåã«éå§ãããã¼ã¸ã«ç§»åãã¦ããå¿
è¦ãããã¾ãã
ã¾ãã¬ã¹ãã³ã·ããã¶ã¤ã³ã®å ´åãç»é¢ãµã¤ãºã«ãã£ã¦è¡¨è¨ãå¤ãããã¨ãèããã®ã§ç»é¢ãµã¤ãºãäºåã«å¤ãã¦ããã¾ãã
è¨é²ãå§ã¾ãã¨ç»é¢ãµã¤ãºã®å¤æ´ã¯ã§ãã¾ããã
1.2è¨é²ã«ååãã¤ãã
å¾ããããããããä»»æã®ååãã¤ãããã¨ãã§ãã¾ããç¹ã«ã¢ã«ãã¡ãããéå®ã¨ããããã§ã¯ãªãæ¥æ¬èªã§ãè¨å®å¯è½ã§ããä»åã¯ããã¹ããã¨ããååã¨ãã¾ãã
1.3ç»é¢æä½ãè¡ã
è¨é²ãå§ã¾ã£ãããè¡ãããæä½ããã©ã¦ã¶ä¸ã§å®æ½ãã¾ãã
ä¸ã®ç»åã¯Googleã®æ¤ç´¢ãã¼ã¸ãããèã®ç©´ã©ããã¨æ¤ç´¢ãã¦å¼ç¤¾ã®ã³ã¼ãã¬ã¼ããµã¤ãã表示ããæã®è¡¨è¨ã§ãã
鏿ããããã¹ãããã¯ã¹ããã¼å
¥åã®ã¤ãã³ããè¨é²ããã¦ãããã¨ããããã¾ãã
æä½ãçµããã¨ãRecordingã¨è¡¨è¨ããã¦ããä¸ã«ãã赤ãã¹ããããã¿ã³ãæ¼ããã¨ã§è¨é²ã¯å®äºãã¾ãã
è¨é²ãã¦ããæã®æ§åã¯ãã¡ãã§ãã
2.ãªãã¬ã¤
æä½ã®ãªãã¬ã¤ã¯ååã®ããã¹ããã®å³ã«ããã¨éæåã®ãReplayããã¿ã³ãããããã®ãã¿ã³ãæ¼ããã¨ã§å®è¡ããã¾ãã
Recorderæ©è½ã§ã¯è¤æ°ã®æä½ãè¨é²ãã¦ãããã¨ãã§ããã®ã§ã以åã«ä½æããæä½ããªãã¬ã¤ã§å®è¡ãããã¨ãå¯è½ã§ãã
ãªãã¬ã¤æã«è¨å®ã¨ãã¦å¤æ´ã§ãããã®ã¯ãç¾ç¶ã§ã¯ãããã¯ã¼ã¯ã®åç·é度ãçä¼¼çã«ä¸ãããã¨ã ãã§ç»é¢ãµã¤ãºãªã©ã夿´ã§ãã¾ããã
3.ããã©ã¼ãã³ã¹ç¢ºèª
åå®è¡ããã¨ãã«è¡¨ç¤ºããéã®Loadingæéãªã©ã確èªãããã¨ãã§ãã¾ãã
ãReplayããã¿ã³ã®å³å´ã®ãMeasure performanceããæ¼ããã¨ã§ããªãã¬ã¤ãä¸åº¦åããã¦èªåçã«Performanceã®ãã¼ã¿ãåå¾ããã¾ãã
ã¿ãããPerformanceãã«ç§»ãè¦ããã¨ãã§ããã®ã§ãä¸é£ã®æä½ã®ä¸ã§é
ãé¨åãªã©ã確èªãããã¨ãã§ãã¾ãã
4.ç·¨é
ç»é¢æä½ã§åå¾ããè¨é²ã«ã¯ãã©ã®ãã¿ã³ãæ¼ãããã©ãã«ã©ã®ãããªæåãå
¥åããããç´°ããè¨é²ããã¦ãã¾ãããã®è¨é²ã¯ç»é¢ä¸ãã夿´ãããã¨ãã§ãã¾ãã
ClickãChangeãªã©ã®æä½ã®å·¦ã«ããç¢å°ãæ¼ããã¨ã§ãæä½ã®è©³ç´°ã表示ãããããã«ãªãã¾ãã
ç»åã¯Googleã®æ¤ç´¢ç»é¢ã«ãèã®ç©´ã©ããã¨å
¥åããé¨åã¨ãªãã¾ãã
valueã®å¤ãå¤ãããã¨ã§ãå¥ã®æååãæ¤ç´¢ããããã«ãã§ãã¾ãã
5.Puppeteerã§å©ç¨å¯è½ãªè¨å®ãã¡ã¤ã«ã®åºå
è¨é²ããæä½ãPuppeteerã§å®è¡å¯è½ãªJavaScriptãã¡ã¤ã«ã§åºåãããã¨ãã§ãã¾ãã
ä¸è¨ã®ãã¹ãåã®ãã«ãã¦ã³ã®å³ã«ããä¸åã®ç¢å°ã®ãã¿ã³ã§åºåããã¾ãã
åºåãããè¨å®ãã¡ã¤ã«ã¯ãã®ã¾ã¾Puppeteerã®ãããã¬ã¹ã¢ã¼ãã§å®è¡å¯è½ãªç¶æ
ã«ãªã£ã¦ãã¾ãã
ãã¡ããåºåããçµæã¨ãªãã¾ãã
const puppeteer = require('puppeteer'); (async () => { const browser = await puppeteer.launch(); const page = await browser.newPage(); async function waitForSelectors(selectors, frame) { for (const selector of selectors) { try { return await waitForSelector(selector, frame); } catch (err) { console.error(err); } } throw new Error('Could not find element for selectors: ' + JSON.stringify(selectors)); } async function waitForSelector(selector, frame) { if (selector instanceof Array) { let element = null; for (const part of selector) { if (!element) { element = await frame.waitForSelector(part); } else { element = await element.$(part); } if (!element) { throw new Error('Could not find element: ' + part); } element = (await element.evaluateHandle(el => el.shadowRoot ? el.shadowRoot : el)).asElement(); } if (!element) { throw new Error('Could not find element: ' + selector.join('|')); } return element; } const element = await frame.waitForSelector(selector); if (!element) { throw new Error('Could not find element: ' + selector); } return element; } async function waitForElement(step, frame) { const count = step.count || 1; const operator = step.operator || '>='; const comp = { '==': (a, b) => a === b, '>=': (a, b) => a >= b, '<=': (a, b) => a <= b, }; const compFn = comp[operator]; await waitForFunction(async () => { const elements = await querySelectorsAll(step.selectors, frame); return compFn(elements.length, count); }); } async function querySelectorsAll(selectors, frame) { for (const selector of selectors) { const result = await querySelectorAll(selector, frame); if (result.length) { return result; } } return []; } async function querySelectorAll(selector, frame) { if (selector instanceof Array) { let elements = []; let i = 0; for (const part of selector) { if (i === 0) { elements = await frame.$$(part); } else { const tmpElements = elements; elements = []; for (const el of tmpElements) { elements.push(...(await el.$$(part))); } } if (elements.length === 0) { return []; } const tmpElements = []; for (const el of elements) { const newEl = (await el.evaluateHandle(el => el.shadowRoot ? el.shadowRoot : el)).asElement(); if (newEl) { tmpElements.push(newEl); } } elements = tmpElements; i++; } return elements; } const element = await frame.$$(selector); if (!element) { throw new Error('Could not find element: ' + selector); } return element; } async function waitForFunction(fn) { let isActive = true; setTimeout(() => { isActive = false; }, 5000); while (isActive) { const result = await fn(); if (result) { return; } await new Promise(resolve => setTimeout(resolve, 100)); } throw new Error('Timed out'); } { const targetPage = page; await targetPage.setViewport({"width":799,"height":605}) } { const targetPage = page; const promises = []; promises.push(targetPage.waitForNavigation()); await targetPage.goto('https://www.google.com/?hl=ja'); await Promise.all(promises); } { const targetPage = page; const element = await waitForSelectors([["aria/æ¤ç´¢"],["body > div.L3eUgb > div.o3j99.ikrT4e.om7nvf > form > div:nth-child(1) > div.A8SBwf > div.RNNXgb > div > div.a4bIc > input"]], targetPage); await element.click({ offset: { x: 221.5, y: 21.5} }); } { const targetPage = page; const element = await waitForSelectors([["aria/æ¤ç´¢"],["body > div.L3eUgb > div.o3j99.ikrT4e.om7nvf > form > div:nth-child(1) > div.A8SBwf.sbfc > div.RNNXgb > div > div.a4bIc > input"]], targetPage); const type = await element.evaluate(el => el.type); if (["textarea","select-one","text","url","tel","search","password","number","email"].includes(type)) { await element.type('èã®ç©´ã©ã'); } else { await element.focus(); await element.evaluate((el, value) => { el.value = value; el.dispatchEvent(new Event('input', { bubbles: true })); el.dispatchEvent(new Event('change', { bubbles: true })); }, "èã®ç©´ã©ã"); } } { const targetPage = page; await targetPage.keyboard.up("Enter"); } { const targetPage = page; const promises = []; promises.push(targetPage.waitForNavigation()); const element = await waitForSelectors([["aria/Google æ¤ç´¢"],["body > div.L3eUgb > div.o3j99.ikrT4e.om7nvf > form > div:nth-child(1) > div.A8SBwf > div.FPdoLc.lJ9FBc > center > input.gNO89b"]], targetPage); await element.click({ offset: { x: 68.21875, y: 20} }); await Promise.all(promises); } { const targetPage = page; const promises = []; promises.push(targetPage.waitForNavigation()); const element = await waitForSelectors([["aria/ã¨ãã©ã â èã®ç©´ã©ãæ ªå¼ä¼ç¤¾"],["#rso > div:nth-child(1) > div > div > div > div > div > div.yuRUbf > a > h3"]], targetPage); await element.click({ offset: { x: 208, y: 15.203125} }); await Promise.all(promises); } await browser.close(); })();
ãããPuppeteerãã¤ã³ã¹ãã¼ã«ããã端æ«ã§å®è¡ããã°åãåããåç¾ããã¾ãã
ãããã¬ã¹ã¢ã¼ãã§å®è¡ãããã®ã§ç»é¢ã«ã¯ãã©ã¦ã¶ãªã©ã¯ç«ã¡ä¸ããã¾ãããããç»é¢ã®è¡¨ç¤ºã確èªãããå ´åã¯ã以ä¸ã®ããã«ã³ã¼ããæ¸ãæãããã¨ã§å¯è½ã§ãã
const browser = await puppeteer.launch(); â const browser = await puppeteer.launch({headless: false});
Puppeteerã®ä½¿ãæ¹ã«ã¤ãã¦ã¯ã以åã¤ã³ã¹ãã¼ã«æ¹æ³ãªã©ãã¾ã¨ããè¨äºãæ¸ãã¦ãã¾ãã®ã§ãã²åèã«ãã¦ã¿ã¦ãã ããã
ããã¾ã§ãRecorderæ©è½ã®ä½¿ãæ¹ã¨ãªãã¾ãã
注æç¹
1.è©³ç´°ã«æä½ã®è¨é²ãåãã
ããã¾ã§ç»é¢æä½ãè¨é²ãããã®ã¨ãã¦HeadlessRecorderã¨ããChromeã®æ¡å¼µæ©è½ãããã¾ãããä»åã®Chromeã®Recorderæ©è½ã§åºåããPuppeteeråãã®è¨å®ãã¡ã¤ã«ã®å
容ãè¦ãéãHeadlessRecorderã§åå¾ã§ããå
容ããããªãæ£ç¢ºãªå
容ã§ããã
HeadlessRecorderã ã¨åããªãã£ãããã¹ãã¨ãªã¢ã®å
¥åã«é¢ãã¦ã詳細ã«åå¾ãããã¨ãã§ããããããã¡ã¤ã«åºåå¾ã«å®è¡ããã¨ãã«ã¨ã©ã¼ã«ãªãäºã¯ããªãå°ãªããªã£ã¦ããã¨èãããã¾ãã(HeadlessRecorderã¯Playwriteã¨ãããã¼ã«åãã®è¨å®ãã¡ã¤ã«ãåºåãããã¨ãã§ããç¹ãä»åã®Recorderæ©è½ã§ã¯ã§ããªãäºã«ãªãã¾ã)
ãã ãæ£ç¢ºã«åå¾ã§ããåé¢IDããã¹ã¯ã¼ãã¨ãã£ãå
¥åãå¹³æã§åå¾ã§ãã¦ãã¾ãããã誤ã£ã¦æ¬çªã®ç°å¢ã§è¨é²ããè¨å®ãã¡ã¤ã«ãå
¬éãã¦ãã¾ãã¨ãã¹ã¯ã¼ããæµåºãã¦ãã¾ãå¯è½æ§ãããã®ã§æ³¨æãå¿
è¦ã§ãã
2.æä½ã®ã³ãã¼ãä½ãäºã¯ã§ããªã
以åã®æä½ãã³ãã¼ãã¦ä¸é¨å¤æ´ããæä½ãä½ããã¨ãã§ããªããããã©ã®ãããªå ´åã§ãæä½ã¯ä¸åº¦è¨é²ãè¡ãå¿
è¦ãããã¾ãã
æ®æ®µã®æä½ã§ã¯ãã¾ããªãã¨æãã¾ããããã¹ãã§æä½ãè¨é²ãã¦ããWEBãã¼ã¸ã®é¡ä¼¼ãã¼ã¸ã§ãæ£å¸¸ã«åä½ããã®ã確ããããã¨ããããã¨æãã¾ãããã®éã«ã¯ä¸åº¦æä½ããã¦å¥ã®æä½ã®è¨é²ãåããããã§ã«ããæä½ãæ¸ãæãã¦ãªãã¬ã¤ããå¿
è¦ãããã¾ãã
3.å¥ãã©ã¦ã¶ã§ã®å®è¡ã¯Puppeteerã®ã¿
æä½ãè¨é²ããChromeä¸ã§ã¯æä½ãç»é¢é·ç§»ããããããã表示ããã¦ãã¾ããããããå¥ã®äººã®Chromeã«ã³ãã¼ããäºã¯ã§ãã¾ããããã®ãããä»ã®äººãæä½ãåç¾ããå ´åã«ã¯Puppeteerç¨ã®è¨å®ãã¡ã¤ã«ãããã£ã¦Puppeteerã§èµ·åãããã¨ã«ãªãã¾ãã
ã¾ã¨ã
ä»åã¯éçºä¸ã®Recorderæ©è½ã«ã¤ãã¦ä½¿ç¨ãã¦ã¿ã¾ããããã®è¨äºãæ¸ãã¦ããã¿ã¤ãã³ã°ã§Qiitaã§ãç§ã¨åãããã«åãã確èªããçµæãã¾ã¨ãããã¦ããæ¹ããã¾ãããä¸è¨ã®è¨äºãæ¸ãããæ¹ãè¨åããã¦ãã¾ãããã¾ã éçºä¸ã®å
容ãªã®ã§å®éã«å
¬éãããéã«ã¯å¤æ´ã«ãªã£ã¦ãå¯è½æ§ãããã¾ãã
https://qiita.com/YoshikiIto/items/62a6caf7a1e1cf96bcb3
ä»ååºåã§ããå 容ãè¦ãéãããªãè©³ç´°ã«æä½ãè¨é²ã§ããPuppeteerç¨ã®ãã¡ã¤ã«ãåºåãããã¨ãã§ãã¦ããã®ã§ããªãæç¨ã ã¨æãã¾ããã
P.S.
æ¡ç¨æ å ±
â åéè·ç¨®
yumenosora.co.jp
ã«ã¸ã¥ã¢ã«é¢è«ãéæéå¬ä¸ã§ã
â ãç³ãè¾¼ã¿ã¯ãã¡ãï¼
news.toranoana.jp
â ToraLab.fmã¹ã¿ã¼ããã¾ããï¼
ã¡ã³ãã¼ã«ããPodcastãé
ä¿¡ä¸ï¼
æ¯éã¹ããæéã«èãã¦é ããã¨å¬ããã§ãã
anchor.fm
â Twitterããã©ãã¼ãã¦ãã ãããï¼
ãã¤ãã¿ã¼ã§ãéææ
å ±çºä¿¡ããã¦ãã¾ã
twitter.com