liveBook · Manning

Scraping

As explained in Practical Automation with PowerShell: Effective scripting from the console to the cloud

Web scraping is the automated extraction of data from web pages by retrieving and parsing their content.

Web scraping retrieves web pages and extracts structured data from their HTML when no public backend is available. In PowerShell, PowerHTML’s ConvertFrom-Html turns retrieved HTML into a navigable document that XPath queries can search. section 13.3 section 13.3.1

Treat scraping as a two-stage workflow: query a results page, then visit each detail page. This matters when one search returns several records, each with information exposed only through its own details view. section 13.3.1

Build a maintainable scraper by separating the navigation and extraction steps:

  • Construct the search URL from the requested identifier and parse its response into an HTML document. section 13.3.1
  • Use browser developer tools to inspect a representative link and copy its XPath, then generalize the query around stable attributes such as class and href. section 13.3.1
  • Enumerate matching result links, remove link-specific suffixes from IDs, and form the detail URL for every result. section 13.3.1
  • Select detail-page nodes and normalize their text into useful fields, such as architecture, supported products, and superseding updates. section 13.3.1
  • Request external pages in integration tests and assert stable shapes and allowed values rather than brittle, fixed page contents. section 13.4.1

Finding superseding Microsoft updates

A KB search can return separate Windows Server 2016 and Windows 10 results. Select all matching update links, request each scoped detail page, then extract its architecture, products, and the linked KB updates that supersede it. Parse each superseding link into a custom object containing its KB number, title, and ID. section 13.3.1

Listing 13.4 Find-KbSupersedence.ps1
Function Find-KbSupersedence {
    param(
        $KbArticle
    )
 
    $UriHost = 'https:/ /www.catalog.update.microsoft.com/'
    $SearchUri = $UriHost + 'Search.aspx?q=' +
        $KbArticle
    $Search = ConvertFrom-Html -URI $SearchUri
 
    $xPath = '//*[' +                                          #1
    '@class="contentTextItemSpacerNoBreakLink" ' +
    'and @href="javascript:void(0);"]'
 
    $Search.SelectNodes($xPath) | ForEach-Object {             #2
        $Title = $_.InnerText.Trim()                           #3
        $Id = $_.Id.Replace('_link', '')
 
        $DetailsUri = $UriHost +                               #4
            "ScopedViewInline.aspx?updateid=$($Id)"
        $Headers = @{"accept-language"="en-US,en;q=0.9"}
        $Request = Invoke-WebRequest -Uri $DetailsUri -Headers $Headers
        $Details = ConvertFrom-Html -Content $Request
 
        $xPath = '//*[@id="archDiv"]'                          #5
        $Architecture = $Details.SelectSingleNode($xPath).InnerText
        $Architecture = $Architecture.Replace('Architecture:', '').Trim()
 
        $xPath = '//*[@id="productsDiv"]'                      #6
        $Products = $Details.SelectSingleNode($xPath).InnerText
        $Products = $Products.Replace('Supported products:', '')
        $Products = $Products.Split(',').Trim()
 
        $xPath = '//*[@id="supersededbyInfo"]'                 #7
        $DivElements = $Details.SelectSingleNode($xPath).Elements("div")
        if ($DivElements.HasChildNodes) {
            $SupersededBy = $DivElements.Elements("a") | Foreach-Object {
                $KB = [regex]::Match($_.InnerText.Trim(), 'KB[0-9]{7}')
                [pscustomobject]@{
                    KbArticle = $KB.Value
                    Title     = $_.InnerText.Trim()
                    ID        = [guid]$_.Attributes.Value.Split('=')[-1]
                }
            }
        }
 
        [pscustomobject]@{                                     #8
            KbArticle    = $KbArticle
            Title        = $Title
            Id           = $Id
            Architecture = $Architecture
            Products     = $Products
            SupersededBy = $SupersededBy
        }
    }
}

This reusable function ties URL construction, XPath-based result discovery, detail requests, and field extraction into one KB-supersedence lookup. section 13.3.1

External sites change. Validate both presence and shape: IDs can match a GUID pattern, products can be non-null, architectures can be limited to expected values, and a known update can return at least a minimum number of superseding records. These checks expose markup or data changes without failing merely because new updates appear. section 13.4.1

How Practical Automation with PowerShell: Effective scripting from the console to the cloud covers it

How deep it goes
Builds a complete XPath-driven PowerShell workflow, then tests its external-data assumptions against changing pages.
Examples
Uses KB4521858 search results and Microsoft Update Catalog detail pages to extract update metadata and supersedence.
What it assumes
Starts XPath discovery through browser inspection rather than assuming prior XPath query-writing knowledge.
What you can do after
Build it from scratch as a reusable PowerShell function that collects and validates update-supersedence data.
How it connects
Connects ConvertFrom-Html, XPath, browser developer tools, Invoke-WebRequest, integration testing, and Pester assertions.

Also explained in

Compare how 9 books explain scraping →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Practical Automation with PowerShell: Effective scripting from the console to the cloud. The section links point to the parts of the book it draws on.