Make it work perfectly. ---         // XPath selectors
        const xpathBookName = '//h3/a/span[@style="color: #ff6600;"]';
        const xpathPdfLink = '//h3/a/@href';
        const xpathCoverUrl = '//h3/following-sibling::p[1]/a/img/@src'; ---   <!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Fetch JNovels Data Using XPath</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            padding: 20px;
            background-color: #f9f9f9;
        }
        #status {
            margin-bottom: 20px;
            font-size: 1.2em;
        }
        .book {
            margin-bottom: 15px;
            border: 1px solid #ccc;
            padding: 10px;
            display: flex;
            align-items: center;
            background-color: #fff;
            border-radius: 5px;
            box-shadow: 0 0 5px rgba(0,0,0,0.1);
        }
        .book img {
            max-width: 100px;
            margin-right: 15px;
            border-radius: 3px;
        }
        .book-details {
            flex: 1;
        }
        .book-details p {
            margin: 5px 0;
            font-weight: bold;
        }
        .book-details a {
            color: #007BFF;
            text-decoration: none;
        }
        .book-details a:hover {
            text-decoration: underline;
        }
        .error {
            color: red;
            border-color: red;
            background-color: #ffe6e6;
        }
    </style>
</head>
<body>
    <h1>Fetching JNovels Data Using XPath...</h1>
    <div id="status">Initializing...</div>
    <div id="books-container"></div>

    <script>
        // Define the target URL
        const targetURL = 'https://jnovels.com/top-light-novels-to-read/';

        // Define the proxy URL using All Origins
        const proxyURL = 'https://api.codetabs.com/v1/proxy?quest=' + encodeURIComponent(targetURL);
        // Note: All Origins returns a JSON with 'contents' field containing the HTML.

        /**
         * Utility function to evaluate an XPath expression and return matching nodes.
         * @param {Document} doc - The DOM Document to query.
         * @param {string} xpath - The XPath expression.
         * @param {Node} contextNode - The context node for the XPath.
         * @param {number} resultType - The desired result type.
         * @returns {XPathResult} - The result of the XPath query.
         */
        function evaluateXPath(doc, xpath, contextNode = doc, resultType = XPathResult.ORDERED_NODE_SNAPSHOT_TYPE) {
            return doc.evaluate(xpath, contextNode, null, resultType, null);
        }

        /**
         * Converts a relative URL to an absolute URL based on a base URL.
         * @param {string} url - The URL to convert.
         * @param {string} base - The base URL.
         * @returns {string} - The absolute URL.
         */
        function toAbsoluteURL(url, base) {
            try {
                return new URL(url, base).href;
            } catch (e) {
                console.warn(`Failed to convert to absolute URL: ${url}`, e);
                return url;
            }
        }

        /**
         * Fetches data from the target URL via the proxy and processes it.
         */
        async function fetchData() {
            const statusDiv = document.getElementById('status');
            const booksContainer = document.getElementById('books-container');
            statusDiv.textContent = 'Fetching data...';

            try {
                // Fetch the content using the All Origins proxy
                const response = await fetch(proxyURL);
                if (!response.ok) {
                    throw new Error(`Network response was not ok: ${response.status} ${response.statusText}`);
                }

                // All Origins returns JSON with 'contents' field
                const data = await response.text();
                const htmlString = data.contents;

                // Parse the fetched HTML string into a DOM Document
                const parser = new DOMParser();
                const doc = parser.parseFromString(htmlString, 'text/html');

                // XPath to select all <h3> elements (each representing a book entry)
                const h3XPath = "//h3";
                const h3Nodes = evaluateXPath(doc, h3XPath);

                const books = [];

                // Iterate through each <h3> node to extract book data
                for (let i = 0; i < h3Nodes.snapshotLength; i++) {
                    const h3 = h3Nodes.snapshotItem(i);
                    const book = {};

                    // Extract Book Name using relative XPath
                    const bookNameXPath = '//h3/a/span[@style="color: #ff6600;"]';
                    const bookNameResult = doc.evaluate(bookNameXPath, h3, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null);
                    const bookName = bookNameResult.singleNodeValue ? bookNameResult.singleNodeValue.nodeValue.trim() : null;
                    book["BookName"] = bookName;

                    // Extract PDF Link using relative XPath
                    const pdfLinkXPath =
        const xpathPdfLink = '//h3/a/@href';
                    const pdfLinkResult = doc.evaluate(pdfLinkXPath, h3, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null);
                    const pdfLinkRaw = pdfLinkResult.singleNodeValue ? pdfLinkResult.singleNodeValue.nodeValue.trim() : null;
                    // Convert to absolute URL if necessary
                    const pdfLink = pdfLinkRaw ? toAbsoluteURL(pdfLinkRaw, targetURL) : null;
                    book["Pdflink"] = pdfLink;

                    // Extract Book Cover from the following <p> tag using relative XPath
                    const bookCoverXPath = '//h3/following-sibling::p[1]/a/img/@src';
                    const bookCoverResult = doc.evaluate(bookCoverXPath, h3, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null);
                    const imgSrcRaw = bookCoverResult.singleNodeValue ? bookCoverResult.singleNodeValue.nodeValue.trim() : null;
                    // Convert to absolute URL if necessary
                    const bookCover = imgSrcRaw ? toAbsoluteURL(imgSrcRaw, targetURL) : null;
                    book["BookCover"] = bookCover;

                    // Check for completeness
                    const isComplete = book.BookName && book.Pdflink && book.BookCover;
                    if (isComplete) {
                        books.push(book);
                    } else {
                        console.warn(`Incomplete data for a book entry. Skipping. Data:`, book);
                        // Optionally, display incomplete entries for debugging
                        displayIncompleteBook(book);
                    }
                }

                // Log the extracted books data
                console.log('Extracted Books Data:', books);
                statusDiv.textContent = `Extraction complete! Found ${books.length} books. Displaying results below.`;

                // Display the books on the webpage
                displayBooks(books);
            } catch (error) {
                console.error('Error fetching or processing data:', error);
                statusDiv.textContent = 'An error occurred. Check the console for details.';
            }
        }

        /**
         * Displays complete books on the webpage.
         * @param {Array} books - Array of book objects.
         */
        function displayBooks(books) {
            const booksContainer = document.getElementById('books-container');

            books.forEach(book => {
                const bookDiv = document.createElement('div');
                bookDiv.className = 'book';

                const img = document.createElement('img');
                img.src = book.BookCover;
                img.alt = book.BookName;

                const detailsDiv = document.createElement('div');
                detailsDiv.className = 'book-details';

                const name = document.createElement('p');
                name.textContent = book.BookName;

                const link = document.createElement('a');
                link.href = book.Pdflink;
                link.textContent = 'Download PDF';
                link.target = '_blank';
                link.rel = 'noopener noreferrer';

                detailsDiv.appendChild(name);
                detailsDiv.appendChild(link);

                bookDiv.appendChild(img);
                bookDiv.appendChild(detailsDiv);

                booksContainer.appendChild(bookDiv);
            });
        }

        /**
         * Displays incomplete book entries for debugging purposes.
         * @param {Object} book - Book object with potential missing fields.
         */
        function displayIncompleteBook(book) {
            const booksContainer = document.getElementById('books-container');

            const errorDiv = document.createElement('div');
            errorDiv.className = 'book error';

            const detailsDiv = document.createElement('div');
            detailsDiv.className = 'book-details';

            const errorMsg = document.createElement('p');
            errorMsg.textContent = `Incomplete Book Entry: ${JSON.stringify(book)}`;

            detailsDiv.appendChild(errorMsg);

            errorDiv.appendChild(detailsDiv);

            booksContainer.appendChild(errorDiv);
        }

        // Execute the fetchData function when the DOM is fully loaded
        document.addEventListener('DOMContentLoaded', fetchData);
    </script>
</body>
</html>