You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何按顺序获取单个元素内的多段文本与元素属性?

解决混合文本与带alt属性图片的网页内容抓取问题

问题背景

原有代码通过遍历子元素提取textContent和img的alt属性拼接帖子内容,但遇到单个父元素内同时包含文本节点和带alt的img元素时,会丢失文本节点内容或alt属性,无法得到预期的顺序输出:#link1 A :) B C #link2 D :( E。

特殊HTML结构示例:

<span class="post">
    <div class="paragraph1">
        <div>
            <span class="html-span link">
                <a>#link1 </a>
            </span>
            "A "
            <span class="html-span emoji">
                <img alt=":)"/>
            </span>
            "B "
        </div>
    </div>
    <div class="paragraph2">
        <div>
            "C "
            <span class="html-span link">
                <a>#link2</a>
            </span>
            "D "
            <span class="html-span emoji">
                <img alt=":("/>
            </span>
            "E"
        </div>
    </div>
</span>

现有方案的问题

  • 仅抓取特定子元素:丢失直接包含在父元素中的文本节点(如示例中的"A "、"B "等)
  • 获取父元素textContent:忽略img的alt属性,无法保留表情符号

解决方案

方法1:通过JavaScript遍历所有节点(含文本节点)

利用Selenium的execute_script执行JS代码,直接遍历目标元素下的所有节点,按顺序处理文本和img的alt属性:

from selenium import webdriver
from selenium.webdriver.common.by import By

driver = webdriver.Chrome()
# 假设已加载目标页面
parent = driver.find_element(By.XPATH, "//span[@class='post']")

# 执行JS遍历节点并提取内容
post_content = driver.execute_script("""
    function extractContent(node) {
        let content = [];
        for (let child of node.childNodes) {
            if (child.nodeType === Node.TEXT_NODE) {
                // 清理文本节点的多余引号和空格,可根据实际结构调整
                let text = child.nodeValue.trim().replace(/^"|"$/g, '');
                if (text) content.push(text);
            } else if (child.nodeType === Node.ELEMENT_NODE) {
                if (child.tagName === 'IMG') {
                    let alt = child.getAttribute('alt');
                    if (alt) content.push(alt);
                } else {
                    // 递归处理子元素
                    content = content.concat(extractContent(child));
                }
            }
        }
        return content;
    }
    return extractContent(arguments[0]);
""", parent)

text = ' '.join(post_content)
print(text)

方法2:Python递归遍历DOM节点的childNodes

通过Selenium获取元素的所有子节点(含文本节点),在Python中递归处理:

from selenium import webdriver
from selenium.webdriver.common.by import By

def extract_content(element):
    content = []
    # 获取当前元素的所有子节点(含文本节点)
    child_nodes = element.find_elements(By.XPATH, "./node()")
    for node in child_nodes:
        if node.tag_name is None:
            # 处理文本节点,清理多余格式
            text = node.get_attribute('nodeValue').strip().replace('"', '')
            if text:
                content.append(text)
        else:
            if node.tag_name.lower() == 'img':
                # 提取img的alt属性
                alt = node.get_attribute('alt')
                if alt:
                    content.append(alt)
            else:
                # 递归处理子元素
                content.extend(extract_content(node))
    return content

driver = webdriver.Chrome()
# 假设已加载目标页面
parent = driver.find_element(By.XPATH, "//span[@class='post']")
post_content = extract_content(parent)
text = ' '.join(post_content)
print(text)

按段落class分组的处理方式

如果需要按paragraph1、paragraph2类分组构建内容,可以先定位段落元素再分别提取:

from selenium import webdriver
from selenium.webdriver.common.by import By

def extract_content(element):
    content = []
    child_nodes = element.find_elements(By.XPATH, "./node()")
    for node in child_nodes:
        if node.tag_name is None:
            text = node.get_attribute('nodeValue').strip().replace('"', '')
            if text:
                content.append(text)
        else:
            if node.tag_name.lower() == 'img':
                alt = node.get_attribute('alt')
                if alt:
                    content.append(alt)
            else:
                content.extend(extract_content(node))
    return content

driver = webdriver.Chrome()
# 假设已加载目标页面
paragraphs = driver.find_elements(By.XPATH, "//span[@class='post']//div[contains(@class, 'paragraph')]")

grouped_content = {}
for para in paragraphs:
    para_class = para.get_attribute('class')
    para_content = extract_content(para)
    grouped_content[para_class] = ' '.join(para_content)

# 输出分组结果
for cls, content in grouped_content.items():
    print(f"{cls}: {content}")

说明

两种核心方法均通过**遍历所有节点(含文本节点)**保证内容顺序,同时处理img的alt属性;文本节点的清理逻辑可根据实际HTML结构调整(比如无引号时可去掉引号替换代码)。

内容的提问来源于stack exchange,提问作者J_L

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 06:44:52