Last active
July 28, 2026 16:16
-
-
Save ninmonkey/b59e33cec6765a2c782edaf5c4807b17 to your computer and use it in GitHub Desktop.
Web Scraping Example - Using CSS Selector Queries.js
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #requires -Modules PSParseHTML | |
| <# | |
| .link | |
| javascript answer: https://gist.github.com/ninmonkey/b59e33cec6765a2c782edaf5c4807b17 | |
| #> | |
| Import-Module PSParseHTML | |
| $url = 'https://tavex.pl/zloto/zlote-sztabki/page/1?filter%5Bweight%5D%5B0%5D=1&meta%5B0%5D=tax-gold%3Azlote-sztabki&sorting=recommended' | |
| $html ??= Invoke-WebRequest -url $Url -UseBasicParsing | |
| $doc ??= ConvertFrom-Html -Content $html -Engine AngleSharp # AngleSharp uses CSS Selector queries :) | |
| $doc | ft -auto | |
| ( $parents = $doc.QuerySelectorAll('.product.product--gold') ) |Ft -auto | |
| 'Found {0} parents' -f $parents.count | Write-Host -fore blue | |
| $summary = @( | |
| foreach( $elem in $parents ) { | |
| $title = $elem.QuerySelectorAll('.product__title-inner')[0].TextContent.Trim() | |
| $labels = $elem.QuerySelectorAll( '.product__price-label' ) | |
| $price = $elem.QuerySelectorAll( '.product__price-value' ) | |
| foreach( $i in 0..($labels.count - 1 )) { | |
| [pscustomobject]@{ | |
| Product = $title | |
| Label = $labels[ $i ].TextContent.Trim() | |
| Price = $price[ $i ].TextContent.Trim() | |
| } | |
| } | |
| } | |
| ) | |
| $summary | ft -auto | |
| $summary | ConvertTo-Json | |
| | Jq -C # if you have JQ, it adds syntax highlighting |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * @summary scraping objects from this url: <https://tavex.pl/zloto/?filter%5Bweight%5D%5B0%5D=1&meta%5B0%5D=%3A&sorting=recommended> | |
| */ | |
| str1 = `.product.product--gold` // grab the root product element | |
| str2 = `.product.product--gold .product__price` // grab the root of the prices element | |
| all_products = document.querySelectorAll( str1 ) | |
| all_prices = document.querySelectorAll( str2 ) // note this query loses the connection to the parent so I do it differently below. | |
| all_products.forEach( (elem) => { elem.style.border = `4px dashed yellow` } ) | |
| all_prices.forEach( (elem) => { elem.style.border = `4px dashed orange` } ) | |
| // before looping, lets test we can grab nested prices | |
| grab = grabPrices( all_products[1] ) | |
| console.table( grab, ['label', 'price'] ) | |
| function grabPrices( elem ) { | |
| // once you have a parent product element, grab only prices that are children | |
| const label = elem.querySelectorAll('.product__price-label') | |
| const price = elem.querySelectorAll('.product__price-value') | |
| const merged = Array.from(label).map((labelElem, index) => ({ | |
| label: labelElem.innerText, | |
| price: price[index].innerText | |
| })) | |
| return merged | |
| } | |
| function printJson( target ) { | |
| // pretty-print as json | |
| console.log( JSON.stringify( target, null, 4 ) ) | |
| } | |
| /* | |
| for each product element, drill into its children to find prices | |
| save that list with the product's title. | |
| */ | |
| summary = Array | |
| .from(all_products) | |
| .map( (root) => { | |
| const title = root.querySelector(`.product__title-inner`).innerText | |
| const prices = grabPrices( root ) | |
| return { | |
| title, | |
| prices | |
| } | |
| }) | |
| // preview the first row of data. if this is for a tabular datasource | |
| // you'll probably want to expand the prices list, so you have a flat table at the end | |
| printJson( summary[0] ) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment