mirror of
https://github.com/puppeteer/puppeteer
synced 2024-06-14 14:02:48 +00:00
1 line
12 KiB
JavaScript
1 line
12 KiB
JavaScript
"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[64885],{3905:(e,t,n)=>{n.d(t,{Zo:()=>c,kt:()=>d});var o=n(67294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function l(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?r(Object(n),!0).forEach((function(t){a(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):r(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function i(e,t){if(null==e)return{};var n,o,a=function(e,t){if(null==e)return{};var n,o,a={},r=Object.keys(e);for(o=0;o<r.length;o++)n=r[o],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(o=0;o<r.length;o++)n=r[o],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=o.createContext({}),p=function(e){var t=o.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},c=function(e){var t=p(e.components);return o.createElement(s.Provider,{value:t},e.children)},m={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},u=o.forwardRef((function(e,t){var n=e.components,a=e.mdxType,r=e.originalType,s=e.parentName,c=i(e,["components","mdxType","originalType","parentName"]),u=p(n),d=a,h=u["".concat(s,".").concat(d)]||u[d]||m[d]||r;return n?o.createElement(h,l(l({ref:t},c),{},{components:n})):o.createElement(h,l({ref:t},c))}));function d(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var r=n.length,l=new Array(r);l[0]=u;var i={};for(var s in t)hasOwnProperty.call(t,s)&&(i[s]=t[s]);i.originalType=e,i.mdxType="string"==typeof e?e:a,l[1]=i;for(var p=2;p<r;p++)l[p]=n[p];return o.createElement.apply(null,l)}return o.createElement.apply(null,n)}u.displayName="MDXCreateElement"},52838:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>i,default:()=>u,frontMatter:()=>l,metadata:()=>s,toc:()=>c});n(67294);var o=n(3905);function a(){return a=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var o in n)Object.prototype.hasOwnProperty.call(n,o)&&(e[o]=n[o])}return e},a.apply(this,arguments)}function r(e,t){if(null==e)return{};var n,o,a=function(e,t){if(null==e)return{};var n,o,a={},r=Object.keys(e);for(o=0;o<r.length;o++)n=r[o],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(o=0;o<r.length;o++)n=r[o],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}const l={},i="Query Selectors",s={unversionedId:"guides/query-selectors",id:"guides/query-selectors",title:"Query Selectors",description:"Queries are the primary mechanism for interacting with the DOM on your site. For example, a typical workflow goes like:",source:"@site/../docs/guides/query-selectors.md",sourceDirName:"guides",slug:"/guides/query-selectors",permalink:"/next/guides/query-selectors",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"docs",previous:{title:"Configuration",permalink:"/next/guides/configuration"},next:{title:"Locators",permalink:"/next/guides/locators"}},p={},c=[{value:"<code>P</code> Selectors",id:"p-selectors",level:2},{value:"<code>>>></code> and <code>>>>></code> combinators",id:"-and--combinators",level:3},{value:"Example",id:"example",level:4},{value:"<code>P</code>-elements",id:"p-elements",level:3},{value:"Text selectors (<code>-p-text</code>)",id:"text-selectors--p-text",level:4},{value:"Example",id:"example-1",level:5},{value:"XPath selectors (<code>-p-xpath</code>)",id:"xpath-selectors--p-xpath",level:4},{value:"Example",id:"example-2",level:5},{value:"ARIA selectors (<code>-p-aria</code>)",id:"aria-selectors--p-aria",level:4},{value:"Example",id:"example-3",level:5},{value:"Custom selectors",id:"custom-selectors",level:3},{value:"Example",id:"example-4",level:4}],m={toc:c};function u(e){var{components:t}=e,n=r(e,["components"]);return(0,o.kt)("wrapper",a({},m,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",a({},{id:"query-selectors"}),"Query Selectors"),(0,o.kt)("p",null,"Queries are the primary mechanism for interacting with the DOM on your site. For example, a typical workflow goes like:"),(0,o.kt)("pre",null,(0,o.kt)("code",a({parentName:"pre"},{className:"language-ts"}),"// Import puppeteer\nimport puppeteer from 'puppeteer';\n\n(async () => {\n // Launch the browser\n const browser = await puppeteer.launch();\n\n // Create a page\n const page = await browser.newPage();\n\n // Go to your site\n await page.goto('YOUR_SITE');\n\n // Query for an element handle.\n const element = await page.waitForSelector('div > .class-name');\n\n // Do something with element...\n await element.click(); // Just an example.\n\n // Dispose of handle\n await element.dispose();\n\n // Close browser.\n await browser.close();\n})();\n")),(0,o.kt)("h2",a({},{id:"p-selectors"}),(0,o.kt)("inlineCode",{parentName:"h2"},"P")," Selectors"),(0,o.kt)("p",null,"Puppeteer uses a superset of the CSS selector syntax for querying. We call this syntax ",(0,o.kt)("em",{parentName:"p"},"P selectors")," and it's supercharged with extra capabilities such as deep combinators and text selection."),(0,o.kt)("admonition",a({},{type:"caution"}),(0,o.kt)("p",{parentName:"admonition"},"Although P selectors look like real CSS selectors (we intentionally designed it this way), they should not be used for actually CSS styling. They are designed only for Puppeteer.")),(0,o.kt)("admonition",a({},{type:"note"}),(0,o.kt)("p",{parentName:"admonition"},'P selectors only work on the first "depth" of selectors; for example, ',(0,o.kt)("inlineCode",{parentName:"p"},":is(div >>> a)")," will not work.")),(0,o.kt)("h3",a({},{id:"-and--combinators"}),(0,o.kt)("inlineCode",{parentName:"h3"},">>>")," and ",(0,o.kt)("inlineCode",{parentName:"h3"},">>>>")," combinators"),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},">>>")," and ",(0,o.kt)("inlineCode",{parentName:"p"},">>>>")," are called ",(0,o.kt)("em",{parentName:"p"},"deep descendent")," and ",(0,o.kt)("em",{parentName:"p"},"deep")," combinators respectively. Both combinators have the effect of going into shadow hosts with ",(0,o.kt)("inlineCode",{parentName:"p"},">>>")," going into every shadow host under a node and ",(0,o.kt)("inlineCode",{parentName:"p"},">>>>")," going into the immediate one (if the node is a shadow host; otherwise, it's a no-op)."),(0,o.kt)("admonition",a({},{type:"note"}),(0,o.kt)("p",{parentName:"admonition"},"A common question is when should ",(0,o.kt)("inlineCode",{parentName:"p"},">>>>")," be chosen over ",(0,o.kt)("inlineCode",{parentName:"p"},">>>")," considering the flexibility of ",(0,o.kt)("inlineCode",{parentName:"p"},">>>"),". A similar question can be asked about ",(0,o.kt)("inlineCode",{parentName:"p"},">")," and a space; choose ",(0,o.kt)("inlineCode",{parentName:"p"},">")," if you do not need to query all elements under a given node and a space otherwise. This answer extends to ",(0,o.kt)("inlineCode",{parentName:"p"},">>>>")," (",(0,o.kt)("inlineCode",{parentName:"p"},">"),") and ",(0,o.kt)("inlineCode",{parentName:"p"},">>>")," (space) naturally.")),(0,o.kt)("h4",a({},{id:"example"}),"Example"),(0,o.kt)("p",null,"Suppose we have the markup"),(0,o.kt)("pre",null,(0,o.kt)("code",a({parentName:"pre"},{className:"language-html"}),'<custom-element>\n <template shadowrootmode="open">\n <slot></slot>\n </template>\n <custom-element>\n <template shadowrootmode="open">\n <slot></slot>\n </template>\n <custom-element>\n <template shadowrootmode="open">\n <slot></slot>\n </template>\n <h2>Light content</h2>\n </custom-element>\n </custom-element>\n</custom-element>\n')),(0,o.kt)("blockquote",null,(0,o.kt)("p",{parentName:"blockquote"},"Note: ",(0,o.kt)("inlineCode",{parentName:"p"},'<template shadowrootmode="open">')," is not supported on Firefox.\nYou can read more about it ",(0,o.kt)("a",a({parentName:"p"},{href:"https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template#attributes"}),"here"),".")),(0,o.kt)("p",null,"Then ",(0,o.kt)("inlineCode",{parentName:"p"},"custom-element >>> h2")," will return ",(0,o.kt)("inlineCode",{parentName:"p"},"h2"),", but ",(0,o.kt)("inlineCode",{parentName:"p"},"custom-element >>>> h2")," will return nothing since the inner ",(0,o.kt)("inlineCode",{parentName:"p"},"h2")," is in a deeper shadow root."),(0,o.kt)("h3",a({},{id:"p-elements"}),(0,o.kt)("inlineCode",{parentName:"h3"},"P"),"-elements"),(0,o.kt)("p",null,(0,o.kt)("inlineCode",{parentName:"p"},"P")," elements are ",(0,o.kt)("a",a({parentName:"p"},{href:"https://developer.mozilla.org/en-US/docs/Web/CSS/Pseudo-elements"}),"pseudo-elements")," with a ",(0,o.kt)("inlineCode",{parentName:"p"},"-p")," vendor prefix. It allows you to enhance your selectors with Puppeteer-specific query engines such as XPath, text queries, and ARIA."),(0,o.kt)("h4",a({},{id:"text-selectors--p-text"}),"Text selectors (",(0,o.kt)("inlineCode",{parentName:"h4"},"-p-text"),")"),(0,o.kt)("p",null,'Text selectors will select "minimal" elements containing the given text, even within (open) shadow roots. Here, "minimum" means the deepest elements that contain a given text, but not their parents (which technically will also contain the given text).'),(0,o.kt)("h5",a({},{id:"example-1"}),"Example"),(0,o.kt)("pre",null,(0,o.kt)("code",a({parentName:"pre"},{className:"language-ts"}),"const element = await page.waitForSelector('div ::-p-text(My name is Jun)');\n// You can also use escapes.\nconst element = await page.waitForSelector(\n ':scope >>> ::-p-text(My name is Jun \\\\(pronounced like \"June\"\\\\))'\n);\n// or quotes\nconst element = await page.waitForSelector(\n 'div >>>> ::-p-text(\"My name is Jun (pronounced like \\\\\"June\\\\\")\"):hover'\n);\n")),(0,o.kt)("h4",a({},{id:"xpath-selectors--p-xpath"}),"XPath selectors (",(0,o.kt)("inlineCode",{parentName:"h4"},"-p-xpath"),")"),(0,o.kt)("p",null,"XPath selectors will use the browser's native ",(0,o.kt)("a",a({parentName:"p"},{href:"https://developer.mozilla.org/en-US/docs/Web/API/Document/evaluate"}),(0,o.kt)("inlineCode",{parentName:"a"},"Document.evaluate"))," to query for elements."),(0,o.kt)("h5",a({},{id:"example-2"}),"Example"),(0,o.kt)("pre",null,(0,o.kt)("code",a({parentName:"pre"},{className:"language-ts"}),"const element = await page.waitForSelector('::-p-xpath(h2)');\n")),(0,o.kt)("h4",a({},{id:"aria-selectors--p-aria"}),"ARIA selectors (",(0,o.kt)("inlineCode",{parentName:"h4"},"-p-aria"),")"),(0,o.kt)("p",null,"ARIA selectors can be used to find elements with a given ARIA label. These labels are computed using Chrome's internal representation."),(0,o.kt)("h5",a({},{id:"example-3"}),"Example"),(0,o.kt)("pre",null,(0,o.kt)("code",a({parentName:"pre"},{className:"language-ts"}),"const node = await page.waitForSelector('::-p-aria(Submit)');\nconst node = await page.waitForSelector(\n '::-p-aria([name=\"Click me\"][role=\"button\"])'\n);\n")),(0,o.kt)("h3",a({},{id:"custom-selectors"}),"Custom selectors"),(0,o.kt)("p",null,"Puppeteer provides users the ability to add their own query selectors to Puppeteer using ",(0,o.kt)("a",a({parentName:"p"},{href:"/next/api/puppeteer.registercustomqueryhandler"}),"Puppeteer.registerCustomQueryHandler"),". This is useful for creating custom selectors based on framework objects or other vendor-specific objects."),(0,o.kt)("h4",a({},{id:"example-4"}),"Example"),(0,o.kt)("p",null,"Suppose you register a custom selector called ",(0,o.kt)("inlineCode",{parentName:"p"},"lit"),". You can use it like so:"),(0,o.kt)("pre",null,(0,o.kt)("code",a({parentName:"pre"},{className:"language-ts"}),"const node = await page.waitForSelector('::-p-lit(LitElement)');\n")))}u.isMDXComponent=!0}}]); |