Quick wins for a faster PC:
Scan for outdated or missing drivers - takes under a minuteDriver Scan →Clear out junk files and repair common Windows errorsFree Scan →Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Use one comma-separated CSS selector with Cheerio: const headings = $('h1, h2');. The comma means “match an h1 or an h2.” First load your markup with cheerio.load(), then call the returned $ function with the selector list.
The direct method: a comma-separated selector
Cheerio uses CSS selector syntax. To select several HTML tag names in one query, place the tags in a comma-separated list:
const cheerio = require('cheerio');
const $ = cheerio.load('<h1>Title</h1><p>Body</p><h2>Section</h2>');
const headings = $('h1, h2');
The load() call creates a document-bound query function named $. The selector h1, h2 contains two alternatives, so the result includes every h1 and every h2 in the loaded document.
What the comma means—and what it does not mean
Comma-separated tags are alternatives
In $('h1, h2, h3'), the comma separates independent selector branches. An element only needs to match one branch to be selected. Add or remove tag names as your extraction task changes:
Recommended Free Tools
#1 Best Overall
const headings = $('h1, h2, h3');
const textBlocks = $('p, blockquote, li');
const media = $('img, video, audio');
Adjacent selector parts are combined conditions
Do not confuse a comma with adjacent selector syntax. p.selected means a p element that also has the selected class. It is not equivalent to p, .selected, which means any paragraph or any element with that class.
const selectedParagraphs = $('p.selected'); // both conditions
const paragraphsOrSelected = $('p, .selected'); // either branch
Use commas when you want different tag names. Use a compound selector when every match must satisfy multiple conditions.
A complete example you can adapt
This example loads a small document, selects three tag types, and prints each element’s tag name and text:
const cheerio = require('cheerio');
const html = `
<article>
<h1>Page title</h1>
<p>Introduction</p>
<h2>Details</h2>
<div>Other content</div>
</article>
`;
const $ = cheerio.load(html);
const wanted = $('h1, h2, p');
wanted.each((_, element) => {
console.log(element.tagName, $(element).text());
});
The selector is the only part that changes when you need a different set of tags. For example, replace it with $('title, meta, link') to inspect those element types, or with $('table, ul, ol') to collect list and table containers.
The Tool Desk
Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Limit the search to a specific part of the document
A global query searches the loaded document. When a page contains repeated components, scope the query to a container so that unrelated matches are excluded.
Pass a context
Cheerio’s query function accepts a selector and a context. Select the container first, then use that selection as the context for the tag list:
const article = $('.article');
const content = $('h2, p', article);
Here, only h2 and p descendants of .article are considered.
Use .find() for descendant searches
The equivalent descendant query uses .find():
const content = $('.article').find('h2, p');
.find('h2, p') searches for either tag inside the current selection. This is useful when you keep a reference to a component and perform several operations on its descendants.
Free tools Windows power users keep installed
One-click scans. No signup required.
Rank #2
Scope nested components separately
If a document contains multiple articles, iterate over each one and run the same comma selector within that article:
$('.article').each((index, article) => {
const headingAndText = $(article).find('h2, p');
console.log('Article', index, headingAndText.text());
});
Scoping this way prevents content from one component being mixed with another in your output.
Combine multiple tags with classes and attributes
Each branch in a comma-separated selector can have its own additional conditions. This lets you express “these tags, but only when they meet their respective rules”:
const targets = $('h1.page-title, h2.section-title, p.lede');
The first branch selects an h1 with page-title; the second selects an h2 with section-title; the third selects a p with lede. A branch can also use an attribute selector:
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
const resources = $('a[rel="nofollow"], img[loading="lazy"]');
Keep each branch readable. If a selector becomes difficult to review, select a stable candidate set first and apply additional checks in JavaScript.
Handle untrusted values safely
Do not interpolate attacker-controlled text directly into selector syntax. A value inserted into an attribute selector can change the selector itself. Instead, select candidates with a fixed selector and compare the attribute value as data with .filter().
const wantedId = userProvidedId;
const matches = $('*[data-id]').filter((_, element) => {
return $(element).attr('data-id') === wantedId;
});
The selector *[data-id] is constant. The untrusted value is used only in a JavaScript equality comparison, so quote characters or selector operators in the input cannot alter the query.
Extract values from the matched set
Read text
Calling .text() on a selection returns its combined text. For per-element processing, iterate with .each():
Do these 3 things before closing this tab:
1Repair Windows errors before they cause bigger problems2Fix the driver behind crashes, sound loss and screen glitches3Clear out junk files and repair common Windows errorsconst labels = [];
$('h1, h2, h3').each((_, element) => {
labels.push($(element).text().trim());
});
console.log(labels);
Read attributes by tag
Different tag branches often expose different attributes. Check the tag name before reading the relevant value:
const records = [];
$('a, img').each((_, element) => {
const node = $(element);
const tag = element.tagName;
records.push({
tag,
value: tag === 'a' ? node.attr('href') : node.attr('src'),
text: node.text().trim()
});
});
This keeps the multi-tag selection in one query while preserving tag-specific extraction logic.
Keep the original element available
The callback receives the underlying element. Wrap it with $(element) whenever you need Cheerio methods such as .text(), .attr(), or .find().
Common mistakes and fixes
Only the last tag appears
Cause: the code called separate queries and overwrote the first variable, or used a selector without a comma.
Fix: keep the alternatives in one string, such as $('h1, h2, h3'), or store separate selections under different names.
The result is empty
Cause: the markup loaded by Cheerio does not contain the requested tags, the selector has a spelling error, or the query is scoped to the wrong context.
Fix: print or inspect the input HTML, test a simple selector such as $('body').length, then add the tag branches and context one at a time.
Unrelated content is included
Cause: a document-wide query is selecting matching tags outside the component you need.
Rank #4
Fix: select the container first and call .find('tag1, tag2'), or pass the container as the query context.
A compound selector returns no matches
Cause: a selector such as p.selected requires both the tag and class on the same element.
Fix: use a comma if you meant alternatives, for example p, .selected, or correct the class and attribute conditions if both are required.
Input changes the selector’s meaning
Cause: user-controlled text was concatenated into a selector.
Fix: use a fixed candidate selector and compare the untrusted value in .filter(), as shown above.
Performance and maintainability considerations
A single comma-separated query is usually easier to maintain than several nearly identical loops. Keep the selector close to the extraction code, give the resulting selection a descriptive name, and scope it to the smallest useful container. Narrow contexts reduce accidental matches and make later markup changes easier to diagnose.
If each tag requires substantially different processing, one combined query can still be correct, but separate clearly named branches may be easier to read. Choose based on whether shared iteration logic outweighs tag-specific handling.
Version and scope note
This guidance reflects the Cheerio documentation available on September 29, 2026. Selector support can change between releases, so check the documentation for the exact Cheerio version pinned by your project. The documented API uses CSS selectors, load() to create the query function, comma-separated alternatives, contexts, and .find() for descendant searches.
Best Value
Or skip the browser setup
If your next step is capturing the rendered page rather than parsing supplied HTML, ScreenshotNeo provides a single website-screenshot request. It accepts a URL and returns a PNG, JPEG, WebP, or PDF; you do not need to configure a browser locally.
Cookie and consent banners, newsletter popups, and chat widgets are removed before the shot. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing status. Its MCP server exposes take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients.
cURL
See the ScreenshotNeo API documentation for the complete option list.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
Python
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
timeout=90,
)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)
Node.js
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
const body = Buffer.from(await res.arrayBuffer());
require('fs').writeFileSync('shot.webp', body);
ScreenshotNeo includes full-page capture with lazy images loaded, element capture by CSS selector, custom CSS and JavaScript, waits for a selector, delay, or network idle, device presets and custom viewports, dark mode, retina scale, PDF controls, request and resource blocking, headers, cookies, user agents, authorization, timezone, geolocation, transparent backgrounds, resizing, selectable cache TTLs, signed links, asynchronous jobs with signed webhooks, bulk capture for up to 100 URLs per call, a usage API, and an OpenAPI specification. Parameter names used by other screenshot APIs also work for easier migration.
Windows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallOutdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchThe Free plan includes 1,000 shots per month with no card. Paid plans start at $5 for 3,000 shots; higher plans are Growth at $15 for 15,000, Pro at $39 for 60,000, Scale at $99 for 250,000, and Business at $249 for 1,000,000. Yearly billing provides two months free, and every feature is available on every plan. Sign up free for ScreenshotNeo to get the 1,000 monthly shots without a card.
Frequently Asked Questions
Does the selector need spaces around the comma?
No. Both h1,h2 and h1, h2 express the same two alternatives; the spaced form is generally easier for people to read.
Can I add another tag later without changing the extraction loop?
Yes. Extend the selector string, for example from $('h1, h2') to $('h1, h2, h3'), while keeping the same iteration code if the processing is shared.
Which Cheerio version should I use?
Pin the version your project supports and consult that version’s documentation, because selector-engine behavior and APIs may change across releases.
The Bottom Line
For multiple tag names in Cheerio, use one comma-separated CSS selector—such as $('h1, h2, p')—and add a context or .find() when the search must stay inside a component.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




