What is the syntax for advanced CSS selectors in jsoup?
Jsoup provides powerful CSS selector support that goes far beyond basic element selection. Understanding advanced CSS selector syntax allows you to precisely target elements in HTML documents using complex queries, attribute matching, and structural relationships.
Understanding Jsoup CSS Selector Basics
Jsoup implements CSS3 selectors through its select()
method, which accepts CSS selector strings and returns matching elements. The selector engine supports most CSS3 features with some extensions specific to HTML parsing.
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;
// Basic selector usage
Document doc = Jsoup.connect("https://example.com").get();
Elements elements = doc.select("div.content p:first-child");
Advanced Attribute Selectors
Jsoup supports sophisticated attribute matching patterns that allow precise element targeting based on attribute values and patterns.
Exact Attribute Matching
// Select elements with exact attribute values
Elements exactMatch = doc.select("input[type=email]");
Elements dataAttribute = doc.select("div[data-role=navigation]");
Elements multipleAttrs = doc.select("img[alt][src]"); // Has both attributes
Attribute Value Patterns
// Attribute contains specific value
Elements contains = doc.select("div[class*=sidebar]"); // class contains "sidebar"
// Attribute starts with value
Elements startsWith = doc.select("a[href^=https://]"); // https links only
// Attribute ends with value
Elements endsWith = doc.select("img[src$=.jpg]"); // JPG images only
// Attribute contains word (space-separated)
Elements containsWord = doc.select("div[class~=active]"); // class list contains "active"
// Attribute starts with value or value followed by hyphen
Elements startsWithOrHyphen = doc.select("div[lang|=en]"); // lang="en" or lang="en-US"
Case-Insensitive Attribute Matching
// Case-insensitive attribute matching (jsoup extension)
Elements caseInsensitive = doc.select("input[type=EMAIL i]");
Elements caseInsensitiveContains = doc.select("a[href*=GITHUB i]");
Structural Pseudo-Selectors
Jsoup supports advanced structural pseudo-selectors for targeting elements based on their position and relationships.
Position-Based Selectors
// First and last child selectors
Elements firstChild = doc.select("ul li:first-child");
Elements lastChild = doc.select("table tr:last-child");
// Nth-child selectors with formulas
Elements evenRows = doc.select("tr:nth-child(even)");
Elements oddRows = doc.select("tr:nth-child(odd)");
Elements everyThird = doc.select("li:nth-child(3n)");
Elements customFormula = doc.select("div:nth-child(2n+1)"); // 1st, 3rd, 5th, etc.
// Nth-of-type selectors
Elements secondParagraph = doc.select("p:nth-of-type(2)");
Elements lastImage = doc.select("img:nth-last-of-type(1)");
Content-Based Selectors
// Select by text content
Elements containsText = doc.select("p:contains(JavaScript)");
Elements exactText = doc.select("button:containsOwn(Submit)"); // Exact text match
Elements regexText = doc.select("div:matches(\\d{4}-\\d{2}-\\d{2})"); // Regex pattern
// Select empty elements
Elements emptyElements = doc.select("div:empty");
Elements hasContent = doc.select("p:not(:empty)");
Complex Combinators and Relationships
Advanced selectors can express complex relationships between elements using combinators.
Child and Descendant Combinators
// Direct child combinator
Elements directChild = doc.select("nav > ul > li"); // Direct child only
// Descendant combinator
Elements anyDescendant = doc.select("article p"); // Any p inside article
// Adjacent sibling combinator
Elements nextSibling = doc.select("h2 + p"); // p immediately after h2
// General sibling combinator
Elements anySibling = doc.select("h2 ~ p"); // Any p after h2 at same level
Advanced Relationship Queries
// Combining multiple relationships
Elements complexQuery = doc.select("main article:first-child h2 + p a[href^=http]");
// Parent selection (jsoup extension)
Elements parentElements = doc.select("img:has(alt)").parents();
Elements conditionalParent = doc.select("div:has(> img.featured)");
Pseudo-Class Extensions
Jsoup provides additional pseudo-classes beyond standard CSS specifications.
Jsoup-Specific Pseudo-Classes
// Element has specific child elements
Elements hasChild = doc.select("div:has(img)");
Elements hasDirectChild = doc.select("ul:has(> li.active)");
// Element is nth element of its type
Elements nthOfType = doc.select("h3:nth-of-type(2)");
// Element matching by index (0-based)
Elements byIndex = doc.select("tr:eq(0)"); // First row
Elements afterIndex = doc.select("li:gt(2)"); // Items after index 2
Elements beforeIndex = doc.select("td:lt(3)"); // First 3 columns
Multiple Selector Patterns
Combine multiple selectors for complex queries and grouping.
Selector Grouping
// Multiple selectors (OR operation)
Elements multipleSelectors = doc.select("h1, h2, h3"); // All headers
Elements complexGroup = doc.select("nav a, footer a, .sidebar a"); // All links in specific areas
// Intersection of selectors
Elements intersection = doc.select("div.content").select("p:contains(important)");
Negation Selectors
// NOT pseudo-class
Elements notClass = doc.select("p:not(.advertisement)");
Elements notAttribute = doc.select("input:not([disabled])");
Elements notMultiple = doc.select("li:not(:first-child):not(:last-child)");
// Complex negation
Elements complexNot = doc.select("a:not([href^=mailto]):not([href^=tel])");
Practical Advanced Examples
Here are real-world examples demonstrating advanced CSS selector usage in jsoup.
E-commerce Product Scraping
public class ProductScraper {
public void scrapeProducts(String url) throws IOException {
Document doc = Jsoup.connect(url).get();
// Select products with prices and ratings
Elements products = doc.select("div.product:has(.price):has(.rating)");
// Get discounted items only
Elements discounted = doc.select(".product:has(.original-price):has(.sale-price)");
// Select high-rated products (4+ stars)
Elements highRated = doc.select(".product .rating[data-stars^=4], .product .rating[data-stars=5]");
// Products with specific shipping options
Elements freeShipping = doc.select(".product:contains(Free Shipping) .title");
for (Element product : products) {
String title = product.select("h3.title").text();
String price = product.select(".price:not(.original-price)").text();
String rating = product.select(".rating").attr("data-stars");
System.out.printf("Product: %s, Price: %s, Rating: %s%n", title, price, rating);
}
}
}
Form Analysis and Data Extraction
public class FormAnalyzer {
public void analyzeForms(Document doc) {
// Required fields in forms
Elements requiredFields = doc.select("form input[required], form select[required], form textarea[required]");
// Form fields with validation patterns
Elements emailFields = doc.select("input[type=email], input[pattern*=@]");
Elements phoneFields = doc.select("input[type=tel], input[pattern*=phone i]");
// Forms with file uploads
Elements uploadForms = doc.select("form:has(input[type=file])");
// Multi-step forms
Elements multiStepForms = doc.select("form:has(.step), form:has([data-step])");
// AJAX forms (likely)
Elements ajaxForms = doc.select("form[data-ajax=true], form.ajax-form, form:has(input[name*=ajax])");
System.out.println("Required fields found: " + requiredFields.size());
System.out.println("Upload forms found: " + uploadForms.size());
}
}
Performance Optimization Tips
When using advanced CSS selectors in jsoup, consider these performance optimization strategies:
Selector Efficiency
// More efficient: specific to general
Elements efficient = doc.select("article.post h2.title");
// Less efficient: general to specific
Elements lessEfficient = doc.select("h2").select(".title").select("article.post h2");
// Use ID selectors when possible (fastest)
Elements byId = doc.select("#main-content p");
// Cache frequently used selections
Elements articles = doc.select("article.post");
for (Element article : articles) {
String title = article.select("h2.title").first().text();
String content = article.select(".content").text();
}
Error Handling and Validation
Implement robust error handling when working with complex selectors:
public class SafeSelector {
public static Elements safeSelect(Document doc, String selector) {
try {
Elements elements = doc.select(selector);
if (elements.isEmpty()) {
System.out.println("Warning: No elements found for selector: " + selector);
}
return elements;
} catch (Exception e) {
System.err.println("Invalid selector syntax: " + selector);
return new Elements();
}
}
public static String safeSelectText(Document doc, String selector, String defaultValue) {
Elements elements = safeSelect(doc, selector);
return elements.isEmpty() ? defaultValue : elements.first().text();
}
}
Integration with Modern Web Scraping
While jsoup excels at parsing static HTML, complex modern websites often require JavaScript execution for dynamic content handling. For such cases, you might need to combine jsoup with headless browsers or consider advanced DOM manipulation techniques when dealing with JavaScript-heavy applications.
Conclusion
Mastering advanced CSS selectors in jsoup enables precise element targeting and efficient HTML parsing. The combination of attribute matching, structural pseudo-selectors, and complex combinators provides the flexibility needed for sophisticated web scraping tasks. Remember to balance selector complexity with performance requirements, and always implement proper error handling for robust applications.
By leveraging these advanced CSS selector patterns, you can create more maintainable and reliable web scraping solutions that adapt to complex HTML structures and changing website layouts.