前端开发必备:JavaScript高效获取和解析DOM内容的完整方案

文章目录
    • 1. 理解DOM和页面结构
      • 1.1 DOM树结构
      • 1.2 为什么需要解析页面内容
    • 2. 获取整个页面的HTML代码
      • 2.1 使用document.documentElement.outerHTML
      • 2.2 使用document.documentElement.innerHTML
      • 2.3 使用document.getElementsByTagName(‘html’)[0]
      • 2.4 获取DOCTYPE声明
    • 3. 解析页面内容
      • 3.1 使用DOM选择器方法
        • 3.1.1 getElementById
        • 3.1.2 getElementsByClassName
        • 3.1.3 getElementsByTagName
        • 3.1.4 querySelector和querySelectorAll
      • 3.2 遍历DOM树
        • 3.2.1 父节点和子节点
        • 3.2.2 兄弟节点
        • 3.2.3 递归遍历整个DOM树
      • 3.3 提取元素属性和内容
        • 3.3.1 获取元素属性
        • 3.3.2 获取元素文本内容
        • 3.3.3 获取表单元素值
    • 4. 高级解析技术
      • 4.1 使用XPath解析
      • 4.2 使用TreeWalker遍历DOM
      • 4.3 使用DOMParser解析HTML字符串
      • 4.4 使用MutationObserver监听DOM变化
    • 5. 实际应用示例
      • 5.1 提取所有链接
      • 5.2 提取文章内容
      • 5.3 提取表格数据
      • 5.4 提取元数据
    • 6. 处理动态内容
      • 6.1 检测动态加载的内容
      • 6.2 等待特定元素出现
      • 6.3 模拟滚动以加载更多内容
    • 7. 性能优化和最佳实践
      • 7.1 批量操作减少重绘
      • 7.2 使用事件委托提高性能
      • 7.3 缓存DOM查询结果
      • 7.4 使用更高效的选择器
    • 8. 安全考虑
      • 8.1 防止XSS攻击
      • 8.2 处理用户生成的内容
    • 9. 跨域限制和解决方案
      • 9.1 同源策略限制
      • 9.2 使用CORS
      • 9.3 使用代理服务器
      • 9.4 浏览器扩展解决方案
    • 10. 完整的页面解析工具示例
    • 11. 总结

在这里插入图片描述

1. 理解DOM和页面结构

在开始获取和解析页面内容之前,我们需要理解DOM(Document Object Model)的概念。DOM是将HTML或XML文档表示为树状结构的编程接口,其中每个节点都是文档的一部分,如元素、属性或文本。
在这里插入图片描述

1.1 DOM树结构

DOM将文档表示为节点树,其中:

  • 文档节点是整个文档的根节点
  • 元素节点代表HTML元素
  • 属性节点代表HTML属性
  • 文本节点包含元素内的文本内容
<!DOCTYPE html>
<html>
<head>
    <title>示例页面</title>
</head>
<body>
    <h1>欢迎</h1>
    <p class="intro">这是一个示例段落。</p>
</body>
</html>

对应的DOM树结构:

  • Document
    • html
      • head
        • title
          • “示例页面” (文本节点)
      • body
        • h1
          • “欢迎” (文本节点)
        • p (class属性为"intro")
          • “这是一个示例段落。” (文本节点)
1.2 为什么需要解析页面内容

解析页面内容有许多实际应用:

  • 网页抓取(Web Scraping)
  • 内容分析
  • 自动化测试
  • 浏览器扩展开发
  • 数据提取和转换

2. 获取整个页面的HTML代码

在这里插入图片描述

2.1 使用document.documentElement.outerHTML

获取整个页面HTML代码的最简单方法是使用document.documentElement.outerHTML属性:

const fullPageHTML = document.documentElement.outerHTML;
console.log(fullPageHTML); // 输出完整的HTML文档

原理

  • document.documentElement代表HTML文档的根元素(通常是<html>元素)
  • outerHTML属性获取元素及其所有子元素的HTML表示
2.2 使用document.documentElement.innerHTML

如果只需要<html>元素内部的内容(不包括<html>标签本身),可以使用:

const htmlContent = document.documentElement.innerHTML;
console.log(htmlContent); // 输出<html>内部的所有内容

2.3 使用document.getElementsByTagName(‘html’)[0]

另一种获取整个HTML内容的方式:

const htmlElement = document.getElementsByTagName('html')[0];
const fullHTML = htmlElement.outerHTML;
console.log(fullHTML);

2.4 获取DOCTYPE声明

如果需要包含DOCTYPE声明,可以组合使用:

const doctype = document.doctype;
const doctypeString = doctype ? `<!DOCTYPE ${doctype.name}${doctype.publicId ? ` PUBLIC "${doctype.publicId}"` : ''}${doctype.systemId ? ` "${doctype.systemId}"` : ''}>` : '';
const fullDocument = doctypeString + document.documentElement.outerHTML;
console.log(fullDocument);

在这里插入图片描述

3. 解析页面内容

获取HTML代码后,下一步是解析其中的内容。JavaScript提供了多种方法来选择和操作DOM元素。

3.1 使用DOM选择器方法
3.1.1 getElementById

通过元素的ID获取单个元素:

const header = document.getElementById('header');
console.log(header.textContent);

3.1.2 getElementsByClassName

通过类名获取元素集合:

const items = document.getElementsByClassName('item');
Array.from(items).forEach(item => {
    console.log(item.textContent);
});

3.1.3 getElementsByTagName

通过标签名获取元素集合:

const paragraphs = document.getElementsByTagName('p');
Array.from(paragraphs).forEach(p => {
    console.log(p.innerHTML);
});

3.1.4 querySelector和querySelectorAll

使用CSS选择器语法选择元素:

// 获取第一个匹配的元素
const firstItem = document.querySelector('.list-item');
console.log(firstItem.textContent);

// 获取所有匹配的元素
const allItems = document.querySelectorAll('.list-item');
allItems.forEach(item => {
    console.log(item.textContent);
});

3.2 遍历DOM树

在这里插入图片描述

3.2.1 父节点和子节点
const parent = document.querySelector('.parent');
const children = parent.children; // 获取所有子元素

// 遍历子节点
Array.from(children).forEach(child => {
    console.log(child.tagName);
});

// 获取父节点
const child = document.querySelector('.child');
const parentNode = child.parentNode;
console.log(parentNode.tagName);

3.2.2 兄弟节点
const item = document.querySelector('.item');
const nextSibling = item.nextElementSibling;
const previousSibling = item.previousElementSibling;

console.log('下一个兄弟节点:', nextSibling);
console.log('上一个兄弟节点:', previousSibling);

3.2.3 递归遍历整个DOM树
function traverseDOM(node, depth = 0) {
    // 打印当前节点信息
    console.log(`${' '.repeat(depth * 2)}${node.nodeName}${node.nodeValue ? `: ${node.nodeValue.trim()}` : ''}`);
    
    // 如果有子节点,递归遍历
    if (node.childNodes && node.childNodes.length > 0) {
        Array.from(node.childNodes).forEach(child => {
            traverseDOM(child, depth + 1);
        });
    }
}

// 从body开始遍历
traverseDOM(document.body);

3.3 提取元素属性和内容
3.3.1 获取元素属性
const link = document.querySelector('a');
console.log('href:', link.getAttribute('href'));
console.log('class:', link.className);
console.log('id:', link.id);
console.log('所有属性:', link.attributes);

3.3.2 获取元素文本内容
const paragraph = document.querySelector('p');
console.log('textContent:', paragraph.textContent); // 包括隐藏元素的文本
console.log('innerText:', paragraph.innerText); // 仅显示文本,受CSS影响
console.log('innerHTML:', paragraph.innerHTML); // 包含HTML标签

3.3.3 获取表单元素值
const input = document.querySelector('input[type="text"]');
console.log('输入值:', input.value);
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/a3878042aafe4c62b4b69a2fa122c956.png)
const checkbox = document.querySelector('input[type="checkbox"]');
console.log('是否选中:', checkbox.checked);

const select = document.querySelector('select');
console.log('选择的值:', select.value);
console.log('选择的文本:', select.options[select.selectedIndex].text);

4. 高级解析技术

4.1 使用XPath解析

XPath提供了一种在XML/HTML文档中导航和选择节点的强大方式:

// 评估XPath表达式
function evaluateXPath(xpath, context = document) {
    const result = [];
    const query = document.evaluate(xpath, context, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
    
    for (let i = 0; i < query.snapshotLength; i++) {
        result.push(query.snapshotItem(i));
    }
    
    return result;
}

// 使用示例:获取所有h2标题的文本
const headings = evaluateXPath('//h2');
headings.forEach(h2 => {
    console.log(h2.textContent);
});

4.2 使用TreeWalker遍历DOM

TreeWalker接口提供了更灵活的DOM遍历方式:

const treeWalker = document.createTreeWalker(
    document.body, // 根节点
    NodeFilter.SHOW_ELEMENT, // 只显示元素节点
    { acceptNode: function(node) { 
        return node.tagName === 'P' ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP; 
    }}, // 只接受<p>元素
    false
);

const paragraphs = [];
let currentNode = treeWalker.nextNode();
while (currentNode) {
    paragraphs.push(currentNode);
    currentNode = treeWalker.nextNode();
}

console.log('找到的段落:', paragraphs);

4.3 使用DOMParser解析HTML字符串

如果需要解析HTML字符串而不是现有文档:

const htmlString = `<html><body><h1>标题</h1><p>段落内容</p></body></html>`;
const parser = new DOMParser();
const doc = parser.parseFromString(htmlString, 'text/html');

// 现在可以像普通DOM一样操作
const title = doc.querySelector('h1');
console.log(title.textContent); // 输出"标题"

4.4 使用MutationObserver监听DOM变化

如果需要监控DOM的变化:

const observer = new MutationObserver(mutations => {
    mutations.forEach(mutation => {
        console.log('DOM发生了变化:', mutation);
        
        if (mutation.addedNodes.length) {
            console.log('添加的节点:', mutation.addedNodes);
        }
        
        if (mutation.removedNodes.length) {
            console.log('移除的节点:', mutation.removedNodes);
        }
    });
});

// 开始观察body元素及其子元素的变化
observer.observe(document.body, {
    childList: true,
    subtree: true,
    attributes: true,
    characterData: true
});

// 停止观察
// observer.disconnect();

5. 实际应用示例

在这里插入图片描述

5.1 提取所有链接
function extractAllLinks() {
    const links = document.querySelectorAll('a[href]');
    const urls = Array.from(links).map(link => {
        return {
            text: link.textContent.trim(),
            href: link.getAttribute('href'),
            title: link.getAttribute('title') || ''
        };
    });
    
    console.log('页面中的所有链接:', urls);
    return urls;
}

extractAllLinks();

5.2 提取文章内容
function extractArticleContent() {
    // 尝试找到可能包含文章内容的元素
    const potentialSelectors = [
        'article', 
        '.article', 
        '.post', 
        '.content', 
        'main', 
        '#main'
    ];
    
    let articleElement = null;
    
    for (const selector of potentialSelectors) {
        const element = document.querySelector(selector);
        if (element) {
            articleElement = element;
            break;
        }
    }
    
    // 如果没有找到特定元素,尝试启发式方法
    if (!articleElement) {
        // 查找包含多个段落的最长元素
        const allElements = document.querySelectorAll('body *');
        let maxLength = 0;
        
        allElements.forEach(el => {
            const textLength = el.textContent.trim().length;
            const paragraphCount = el.querySelectorAll('p').length;
            
            if (textLength > maxLength && paragraphCount > 1) {
                maxLength = textLength;
                articleElement = el;
            }
        });
    }
    
    if (articleElement) {
        const title = document.querySelector('h1') || 
                     document.querySelector('title') || 
                     { textContent: '无标题' };
        
        const paragraphs = Array.from(articleElement.querySelectorAll('p'))
            .map(p => p.textContent.trim())
            .filter(text => text.length > 0);
        
        const images = Array.from(articleElement.querySelectorAll('img'))
            .map(img => img.getAttribute('src'));
        
        return {
            title: title.textContent.trim(),
            paragraphs,
            images
        };
    }
    
    return null;
}

console.log('提取的文章内容:', extractArticleContent());

5.3 提取表格数据
function extractTableData() {
    const tables = document.querySelectorAll('table');
    const tableData = [];
    
    tables.forEach((table, index) => {
        const rows = table.querySelectorAll('tr');
        const data = [];
        
        rows.forEach(row => {
            const cells = row.querySelectorAll('td, th');
            const rowData = Array.from(cells).map(cell => cell.textContent.trim());
            data.push(rowData);
        });
        
        tableData.push({
            tableIndex: index + 1,
            rows: data
        });
    });
    
    console.log('提取的表格数据:', tableData);
    return tableData;
}

extractTableData();

5.4 提取元数据
function extractMetaData() {
    const metaTags = document.querySelectorAll('meta');
    const metadata = {};
    
    metaTags.forEach(tag => {
        const name = tag.getAttribute('name') || 
                    tag.getAttribute('property') || 
                    tag.getAttribute('itemprop');
        const content = tag.getAttribute('content');
        
        if (name && content) {
            metadata[name] = content;
        }
    });
    
    // 获取标题
    metadata.title = document.title;
    
    // 获取描述(优先从meta标签获取)
    if (!metadata.description) {
        const firstParagraph = document.querySelector('p');
        if (firstParagraph) {
            metadata.description = firstParagraph.textContent.trim().substring(0, 150) + '...';
        }
    }
    
    // 获取关键词
    if (!metadata.keywords) {
        metadata.keywords = [];
    } else if (typeof metadata.keywords === 'string') {
        metadata.keywords = metadata.keywords.split(',').map(k => k.trim());
    }
    
    console.log('页面元数据:', metadata);
    return metadata;
}

extractMetaData();

6. 处理动态内容

在这里插入图片描述
现代网页经常使用JavaScript动态加载内容,这给内容提取带来了挑战。

6.1 检测动态加载的内容
// 使用MutationObserver检测动态加载的内容
function watchForDynamicContent(callback) {
    const observer = new MutationObserver(mutations => {
        mutations.forEach(mutation => {
            if (mutation.addedNodes.length) {
                callback(mutation.addedNodes);
            }
        });
    });
    
    observer.observe(document.body, {
        childList: true,
        subtree: true
    });
    
    return observer;
}

// 示例:检测新加载的内容并提取其中的链接
const dynamicLinks = new Set();

const observer = watchForDynamicContent(nodes => {
    nodes.forEach(node => {
        if (node.nodeType === Node.ELEMENT_NODE) {
            const links = node.querySelectorAll('a[href]');
            links.forEach(link => {
                const href = link.getAttribute('href');
                if (!dynamicLinks.has(href)) {
                    dynamicLinks.add(href);
                    console.log('发现新链接:', href);
                }
            });
        }
    });
});

// 停止观察
// observer.disconnect();

6.2 等待特定元素出现
function waitForElement(selector, timeout = 5000) {
    return new Promise((resolve, reject) => {
        if (document.querySelector(selector)) {
            return resolve(document.querySelector(selector));
        }
        
        const observer = new MutationObserver(mutations => {
            if (document.querySelector(selector)) {
                observer.disconnect();
                resolve(document.querySelector(selector));
            }
        });
        
        observer.observe(document.body, {
            childList: true,
            subtree: true
        });
        
        setTimeout(() => {
            observer.disconnect();
            reject(new Error(`等待元素 "${selector}" 超时`));
        }, timeout);
    });
}

// 使用示例
waitForElement('.dynamic-content')
    .then(element => {
        console.log('元素已加载:', element);
    })
    .catch(error => {
        console.error(error);
    });

6.3 模拟滚动以加载更多内容
async function scrollToLoadAllContent() {
    let lastHeight = document.body.scrollHeight;
    let attempts = 0;
    const maxAttempts = 10;
    
    while (attempts < maxAttempts) {
        // 滚动到底部
        window.scrollTo(0, document.body.scrollHeight);
        
        // 等待内容加载
        await new Promise(resolve => setTimeout(resolve, 2000));
        
        // 检查高度是否变化
        const newHeight = document.body.scrollHeight;
        if (newHeight === lastHeight) {
            break;
        }
        
        lastHeight = newHeight;
        attempts++;
    }
    
    console.log('完成滚动,最终高度:', lastHeight);
}

// 使用示例
scrollToLoadAllContent().then(() => {
    console.log('所有内容已加载(或达到最大尝试次数)');
});

7. 性能优化和最佳实践

在这里插入图片描述

7.1 批量操作减少重绘
// 不推荐的方式(每次循环都会导致重绘)
const items = document.querySelectorAll('.item');
items.forEach(item => {
    item.style.color = 'red';
});

// 推荐的方式(使用文档片段批量操作)
const fragment = document.createDocumentFragment();
const newItems = Array(10).fill().map((_, i) => {
    const div = document.createElement('div');
    div.className = 'item';
    div.textContent = `项目 ${i + 1}`;
    fragment.appendChild(div);
    return div;
});

document.body.appendChild(fragment);

7.2 使用事件委托提高性能
// 不推荐的方式(为每个元素添加事件监听器)
document.querySelectorAll('.clickable-item').forEach(item => {
    item.addEventListener('click', handleClick);
});

// 推荐的方式(事件委托)
document.body.addEventListener('click', event => {
    if (event.target.closest('.clickable-item')) {
        handleClick(event);
    }
});

function handleClick(event) {
    console.log('点击的项目:', event.target);
}

7.3 缓存DOM查询结果
// 不推荐的方式(多次查询相同的元素)
function updateElements() {
    document.querySelector('.item').style.color = 'red';
    document.querySelector('.item').style.fontSize = '16px';
    document.querySelector('.item').textContent = '更新后的文本';
}

// 推荐的方式(缓存查询结果)
function updateElementsOptimized() {
    const item = document.querySelector('.item');
    item.style.color = 'red';
    item.style.fontSize = '16px';
    item.textContent = '更新后的文本';
}

7.4 使用更高效的选择器
// 不高效的选择器(过于通用)
const allDivs = document.querySelectorAll('div div div');

// 更高效的选择器(更具体)
const specificDivs = document.querySelectorAll('.container > .wrapper > .content');

8. 安全考虑

在这里插入图片描述

8.1 防止XSS攻击

当处理动态内容时,要注意防范XSS(跨站脚本)攻击:

// 不安全的方式(直接插入HTML)
function unsafeInsert(content) {
    document.querySelector('.output').innerHTML = content;
}

// 安全的方式(使用textContent或DOMPurify)
function safeInsert(content) {
    // 方法1:仅插入文本
    document.querySelector('.output').textContent = content;
    
    // 方法2:使用DOMPurify清理HTML
    // const clean = DOMPurify.sanitize(content);
    // document.querySelector('.output').innerHTML = clean;
}

8.2 处理用户生成的内容
function sanitizeUserInput(input) {
    // 移除脚本标签
    let sanitized = input.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '');
    
    // 移除危险的属性
    sanitized = sanitized.replace(/\son\w+="[^"]*"/g, '');
    
    // 其他清理逻辑...
    return sanitized;
}

const userInput = '<script>alert("XSS")</script><img src="x" onerror="alert(1)">';
console.log('清理后的输入:', sanitizeUserInput(userInput));

9. 跨域限制和解决方案

在这里插入图片描述

9.1 同源策略限制

浏览器出于安全考虑实施了同源策略,限制了从不同源(协议、域名、端口)加载和操作内容的能力。

9.2 使用CORS

如果目标服务器支持CORS(跨源资源共享),可以直接请求:

fetch('https://api.example.com/data', {
    method: 'GET',
    mode: 'cors',
    headers: {
        'Content-Type': 'application/json'
    }
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('错误:', error));

9.3 使用代理服务器

对于不支持CORS的网站,可以通过自己的服务器代理请求:

// 前端代码
fetch('/proxy?url=' + encodeURIComponent('https://example.com'))
    .then(response => response.text())
    .then(html => {
        const parser = new DOMParser();
        const doc = parser.parseFromString(html, 'text/html');
        // 解析文档...
    });

// 服务器端(Node.js示例)
/*
app.get('/proxy', async (req, res) => {
    const { url } = req.query;
    try {
        const response = await axios.get(url);
        res.send(response.data);
    } catch (error) {
        res.status(500).send('代理请求失败');
    }
});
*/

9.4 浏览器扩展解决方案

如果是开发浏览器扩展,可以使用chrome.webRequest API绕过某些限制:

// 在manifest.json中声明权限
/*
"permissions": [
    "webRequest",
    "webRequestBlocking",
    "<all_urls>"
]
*/

// 在background.js中
/*
chrome.webRequest.onBeforeSendHeaders.addListener(
    details => {
        // 修改请求头
        details.requestHeaders.push({
            name: 'Origin',
            value: 'https://your-extension-id.chromiumapp.org'
        });
        return { requestHeaders: details.requestHeaders };
    },
    { urls: ['<all_urls>'] },
    ['blocking', 'requestHeaders']
);
*/

10. 完整的页面解析工具示例

在这里插入图片描述
下面是一个完整的示例,展示如何构建一个功能丰富的页面解析工具:

class PageParser {
    constructor() {
        this.parsedData = {
            metadata: {},
            structure: {},
            content: {},
            resources: {}
        };
    }
    
    // 解析页面元数据
    parseMetadata() {
        // 标题
        this.parsedData.metadata.title = document.title;
        
        // meta标签
        this.parsedData.metadata.metaTags = {};
        document.querySelectorAll('meta').forEach(tag => {
            const name = tag.getAttribute('name') || 
                        tag.getAttribute('property') || 
                        tag.getAttribute('itemprop');
            if (name) {
                this.parsedData.metadata.metaTags[name] = tag.getAttribute('content');
            }
        });
        
        // 链接标签
        this.parsedData.metadata.links = [];
        document.querySelectorAll('link').forEach(link => {
            this.parsedData.metadata.links.push({
                rel: link.getAttribute('rel'),
                href: link.getAttribute('href'),
                type: link.getAttribute('type')
            });
        });
        
        return this;
    }
    
    // 分析页面结构
    analyzeStructure() {
        // 统计各类元素数量
        this.parsedData.structure.elementCounts = {};
        const allElements = document.querySelectorAll('*');
        Array.from(allElements).forEach(el => {
            const tag = el.tagName.toLowerCase();
            this.parsedData.structure.elementCounts[tag] = 
                (this.parsedData.structure.elementCounts[tag] || 0) + 1;
        });
        
        // 获取主要内容区域
        this.parsedData.structure.mainContent = this.findMainContent();
        
        return this;
    }
    
    // 查找主要内容区域
    findMainContent() {
        const contentSelectors = [
            'main',
            'article',
            '.main-content',
            '.content',
            '#content',
            '.article',
            '.post'
        ];
        
        for (const selector of contentSelectors) {
            const element = document.querySelector(selector);
            if (element) {
                return {
                    selector,
                    textLength: element.textContent.length,
                    paragraphCount: element.querySelectorAll('p').length
                };
            }
        }
        
        // 启发式方法:查找包含最多文本的元素
        let maxLength = 0;
        let mainElement = null;
        
        document.querySelectorAll('body > div, body > section').forEach(el => {
            const length = el.textContent.length;
            if (length > maxLength) {
                maxLength = length;
                mainElement = el;
            }
        });
        
        return mainElement ? {
            selector: this.generateSelector(mainElement),
            textLength: mainElement.textContent.length,
            paragraphCount: mainElement.querySelectorAll('p').length
        } : null;
    }
    
    // 生成元素选择器
    generateSelector(element) {
        if (element.id) {
            return `#${element.id}`;
        }
        
        const path = [];
        let current = element;
        
        while (current && current !== document.body) {
            let selector = current.tagName.toLowerCase();
            
            if (current.className && typeof current.className === 'string') {
                const classes = current.className.split(/\s+/).filter(c => c);
                if (classes.length) {
                    selector += `.${classes.join('.')}`;
                }
            }
            
            // 如果有兄弟元素,添加:nth-child
            const siblings = Array.from(current.parentNode.children);
            const index = siblings.indexOf(current);
            if (siblings.length > 1) {
                selector += `:nth-child(${index + 1})`;
            }
            
            path.unshift(selector);
            current = current.parentNode;
        }
        
        return path.join(' > ');
    }
    
    // 提取页面内容
    extractContent() {
        // 提取所有文本段落
        this.parsedData.content.paragraphs = Array.from(document.querySelectorAll('p'))
            .map(p => p.textContent.trim())
            .filter(text => text.length > 0);
        
        // 提取所有标题
        this.parsedData.content.headings = {};
        ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'].forEach(tag => {
            this.parsedData.content.headings[tag] = Array.from(document.querySelectorAll(tag))
                .map(el => el.textContent.trim());
        });
        
        // 提取图片
        this.parsedData.content.images = Array.from(document.querySelectorAll('img'))
            .map(img => ({
                src: img.getAttribute('src'),
                alt: img.getAttribute('alt') || '',
                width: img.width,
                height: img.height
            }));
        
        return this;
    }
    
    // 收集页面资源
    collectResources() {
        // 脚本
        this.parsedData.resources.scripts = Array.from(document.querySelectorAll('script[src]'))
            .map(script => script.getAttribute('src'));
        
        // 样式表
        this.parsedData.resources.stylesheets = Array.from(document.querySelectorAll('link[rel="stylesheet"]'))
            .map(link => link.getAttribute('href'));
        
        // 图片
        this.parsedData.resources.images = Array.from(document.querySelectorAll('img[src]'))
            .map(img => img.getAttribute('src'));
        
        // 外部链接
        this.parsedData.resources.links = Array.from(document.querySelectorAll('a[href]'))
            .filter(a => {
                const href = a.getAttribute('href');
                return href && !href.startsWith('#') && !href.startsWith('javascript:');
            })
            .map(a => a.getAttribute('href'));
        
        return this;
    }
    
    // 获取解析结果
    getResult() {
        return this.parsedData;
    }
    
    // 静态方法:完整解析页面
    static parseFullPage() {
        return new PageParser()
            .parseMetadata()
            .analyzeStructure()
            .extractContent()
            .collectResources()
            .getResult();
    }
}

// 使用示例
document.addEventListener('DOMContentLoaded', () => {
    const pageData = PageParser.parseFullPage();
    console.log('完整页面分析结果:', pageData);
    
    // 可以将结果发送到服务器或保存
    // fetch('/api/save-analysis', {
    //     method: 'POST',
    //     body: JSON.stringify(pageData)
    // });
});

11. 总结

本文详细介绍了如何使用JavaScript获取和解析页面内容,涵盖了从基础到高级的各种技术。我们学习了:

  1. 获取页面HTML:使用outerHTMLinnerHTML等方法获取完整或部分的HTML代码
  2. DOM遍历和选择:使用各种选择器方法和遍历技术定位特定元素
  3. 内容提取:从元素中提取文本、属性和结构化数据
  4. 高级技术:XPath、TreeWalker、MutationObserver等高级API的使用
  5. 动态内容处理:监控和等待动态加载的内容
  6. 性能优化:批量操作、事件委托等提高性能的技术
  7. 安全考虑:防范XSS攻击和正确处理用户输入
  8. 跨域限制:理解和解决同源策略带来的限制
  9. 完整工具实现:构建一个功能全面的页面解析工具

通过这些技术,你可以构建强大的网页抓取工具、内容分析系统或浏览器扩展,满足各种实际应用需求。记住在实际应用中要考虑性能、安全和合法性,确保你的代码既高效又负责任。
在这里插入图片描述

前言

在人工智能(AI)迅速发展的背景下,从传统的编程领域如Java程序员转向大模型开发是一个既充满挑战也充满机遇的过程。对于 Java 程序员来说,这也是一个实现职业转型、提升薪资待遇的绝佳机遇。

为大家整理了一份大模型AGI-CSDN独家资料包,微信扫码即可获取!
在这里插入图片描述

一、明确大模型概念

简单来说,大模型就是具有大量参数和强大计算能力的人工智能模型,可以处理各种复杂的任务,如自然语言处理、图像识别等。想象一下,大模型就像是一个超级聪明的大脑,能够理解和处理各种信息。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

二、转行步骤

第一步:学习基础知识。了解机器学习、深度学习的基本概念和原理,掌握常见的算法和模型架构。可以通过在线课程、书籍等资源进行系统学习。

第二步:掌握相关工具和框架。大模型的开发通常需要使用一些特定的工具和框架,如 TensorFlow、PyTorch 等。虽然 Java 程序员可能对这些工具不太熟悉,但可以通过学习和实践逐渐掌握。

第三步:提升编程能力。大模型的开发需要高效的编程能力,尤其是在处理大规模数据和复杂计算时。Java 程序员可以进一步提升自己的编程技巧,学习优化算法和代码结构的方法。

第四步:数学知识储备。高数、概率论和线性代数等数学知识对于理解和开发大模型至关重要。Java 程序员可以通过复习和学习相关数学课程,提升自己的数学水平。(

第五步:项目实践。参与开源项目、参加数据竞赛或者通过企业实习获取实际项目经验。在实践中,不仅可以巩固所学知识,还能了解大模型在实际应用中的需求和挑战。

三、Java 程序员的优势

对于 Java 程序员来说,转行做大模型具备一定的优势。Java 语言在企业级应用开发中广泛使用,程序员们对软件架构和开发流程有较为深入的理解,这对于大模型的工程化实施非常有帮助。

总之,Java 程序员要成功转行做大模型,需要不断学习、实践和积累经验。在 AI 时代的浪潮中,抓住机遇,勇敢迈出转型的步伐,迎接新的职业挑战和发展机遇。

四、AI大模型时代的价值技术岗位

随着AI大模型时代的到来,开发工程师出现了许多新的工种。这些工种的核心不再是关注语言本身,而是模型本身带来的巨大潜力,因为当一个旧维度的东西被一个全新维度的东西代替的时候,人们处理问题的效率回得到十倍甚至是百倍的增长。而这种被行业聚焦的岗位自然变得炽手可热,下面列举一些我认为比较有竞争力的岗位。这些新的工种反映了AI技术的不断进步和应用范围的拓展,为开发工程师提供了更多选择和机会。

在这里插入图片描述

4.1 AI工程师

专门负责设计、开发和实施人工智能系统和算法的工程师。他们需要有扎实的机器学习和深度学习知识,能够构建和训练复杂的神经网络模型。

4.2 数据工程师

负责处理和管理大规模数据的工程师。他们需要设计和实施数据采集、存储、处理和分析的系统,并确保数据的质量和可靠性。

在这里插入图片描述

4.3 模型架构师

负责设计和构建大规模AI模型的架构的工程师。他们需要了解不同类型的模型架构,并在实际应用中选择合适的架构来解决问题。

4.4 算法工程师

专门研究和开发新的算法和技术来提升AI模型的性能和效果的工程师。他们需要深入理解机器学习和统计学原理,并具备独立开发新算法的能力。

在这里插入图片描述

4.5 质量测试工程师

负责测试和验证AI模型的质量和性能的工程师。他们需要设计和执行各种测试用例,确保模型在各种情况下都能正常运行。

4.5 部署工程师

负责将AI模型部署到生产环境中并确保其高效运行的工程师。他们需要优化模型的性能和资源利用,处理模型的扩展性和容错性等方面的问题。
在这里插入图片描述

4.6 训练数据工程师

负责准备和标注训练数据集的工程师。他们需要清洗、标注和整理大规模的数据集,并确保数据的准确性和完整性。

2.7 解释性AI工程师

专门研究如何解释和理解AI模型决策过程的工程师。他们需要开发和应用解释性AI技术,以提高模型的可解释性和可信度。

在这里插入图片描述

五、AI工程师需要学习哪些知识

成为一个AI工程师难度实际上是非常高的,很多岗位都起码是要硕士起步,因为需要学习的东西非常多,也需要不断积淀,具体而言,深入学习这些领域的原理、算法和实践经验将有助于成为一名优秀的AI工程师。下面列表一些相关知识:

领域知识点
数学线性代数、概率与统计、微积分、优化理论等
编程Python、C++、Java等编程语言,算法和数据结构的基础知识
机器学习监督学习、无监督学习、强化学习、深度学习等方法和算法
神经网络前馈神经网络、递归神经网络、卷积神经网络等深度学习模型
自然语言处理文本分析、语言生成、语义理解、信息检索等技术
计算机视觉图像处理、目标检测、图像分类和分割等相关技术
数据科学数据清洗和预处理、特征工程、数据可视化等方法
软件工程软件开发过程、版本控制、软件测试和调试等技巧
深度学习框架TensorFlow、PyTorch、Keras等常用深度学习框架
人工智能伦理学研究人工智能对社会、经济和伦理方面的影响和应用

一、大模型风口已至:月薪30K+的AI岗正在批量诞生

2025年大模型应用呈现爆发式增长,根据工信部最新数据:

国内大模型相关岗位缺口达47万

初级工程师平均薪资28K(数据来源:BOSS直聘报告)

70%企业存在"能用模型不会调优"的痛点

真实案例:某二本机械专业学员,通过4个月系统学习,成功拿到某AI医疗公司大模型优化岗offer,薪资直接翻3倍!

在这里插入图片描述

如何学习AI大模型 ?

“最先掌握AI的人,将会比较晚掌握AI的人有竞争优势”。

这句话,放在计算机、互联网、移动互联网的开局时期,都是一样的道理。

相信大家在刚刚开始学习的过程中总会有写摸不着方向,故此将并将重要的AI大模型资料包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程等免费分享出来。

如果你是零基础小白,想快速入门大模型是可以考虑的。

一方面是学习时间相对较短,学习内容更全面更集中。

二方面是可以根据这些资料规划好学习计划和方向。

😝有需要的小伙伴,可以微信扫码领取!

在这里插入图片描述

👉1.大模型入门学习思维导图👈

要学习一门新的技术,作为新手一定要先有一个明确的学习路线方向不对,努力白费。

对于从来没有接触过AI大模型的同学,我们帮你准备了详细的学习路线图。可以说是最科学最系统的学习路线,大家跟着这个大的方向学习准没问题。(完整路线在公众号内领取)

在这里插入图片描述

大模型学习路线

👉2.大模型配套视频👈

很多朋友都不喜欢晦涩的文字,我也为大家准备了视频教程,每个章节都是当前板块的精华浓缩。(篇幅有限,仅展示部分)

img

大模型教程

👉3.大模型经典学习电子书👈

随着人工智能技术的飞速发展,AI大模型已经成为了当今科技领域的一大热点。这些大型预训练模型,如GPT-3、BERT、XLNet等,以其强大的语言理解和生成能力,正在改变我们对人工智能的认识。 那以下这些PDF籍就是非常不错的学习资源。(篇幅有限,仅展示部分,公众号内领取)

img

电子书

👉4.大模型面试题&答案👈

截至目前大模型已经超过200个,在大模型纵横的时代,不仅大模型技术越来越卷,就连大模型相关的岗位和面试也开始越来越卷了。为了让大家更容易上车大模型算法赛道,我总结了大模型常考的面试题。(篇幅有限,仅展示部分,公众号内领取)

img

大模型面试

**因篇幅有限,仅展示部分资料,需要的扫描下方二维码领取 **

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员一粟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值