深度学习在DOM解析中的应用:自动识别页面关键内容区块

摘要

本文介绍了如何在爬取东方财富吧(https://www.eastmoney.com)财经新闻时,利用深度学习模型对 DOM 树中的内容区块进行自动识别和过滤,并将新闻标题、时间、正文等关键信息分类存储。文章聚焦爬虫整体性能瓶颈,通过指标对比、优化策略、压测数据及改进结果,展示了从单页耗时约 5 秒优化到约 2 秒的过程,极大提升了工程效率。


一、性能瓶颈点

  1. 网络请求与代理调度
    • 每次 HTTP 请求需经由爬虫代理,存在连接与认证开销。
  2. DOM 解析与深度学习推理
    • 使用 BeautifulSoup 遍历大规模节点;
    • 对每个候选区块进行深度学习模型推理(TensorFlow/Keras),推理时间占比高。
  3. 单线程串行抓取
    • 不支持并发,无法充分利用多核 CPU 与网络带宽。

二、指标对比(优化前)

指标 单页耗时 (秒) CPU 占用 内存占用
网络请求 + 代理 1.2 5% 50 MB
DOM 解析 0.8 10% 100 MB
模型推理 (单区块) 2.5 30% 200 MB
数据存储(本地 SQLite) 0.5 5% 20 MB
总计 5.0 50% 370 MB

三、优化策略

  1. 代理连接复用
    • 启用 requests.Session 并开启 HTTP Keep-Alive,减少握手耗时;
  2. 批量深度学习推理
    • 将多个候选区块合并为批次(Batch)输入模型,一次性完成推理,减少启动开销;
  3. 多线程并发抓取
    • 采用 concurrent.futures.ThreadPoolExecutor 实现多线程并发请求与解析,提高吞吐量;
  4. 模型量化与 TensorFlow Lite
    • 将 Keras 模型导出为 TFLite,并启用浮点16量化,推理更快、占用更低;
  5. 异步存储
    • 异步写入 SQLite 或切换到轻量级 NoSQL(如 TinyDB),降低阻塞;

四、压测数据(优化后)

指标 单页耗时 (秒) CPU 占用 内存占用
网络请求 + 代理复用 0.8 8% 55 MB
DOM 解析 0.6 12% 110 MB
批量模型推理 (TFLite) 0.4 20% 120 MB
多线程与异步存储 0.2 10% 25 MB
总计 2.0 50% 310 MB

五、改进结果

  • 平均单页耗时 从 5.0 秒降至 2.0 秒,性能提升 60%+;
  • 内存占用 减少 60 MB,推理内存占比降低;
  • CPU 利用率 更均衡,多线程并发可支撑更高并发量。
  • 整体爬虫更稳定,并可扩展至分布式部署。

代码示例

python 复制代码
import time
import requests
from bs4 import BeautifulSoup
import sqlite3
import tensorflow as tf
import numpy as np
from concurrent.futures import ThreadPoolExecutor

# -----配置代理 IP(亿牛云爬虫代理示例 www.16yun.cn)-----
PROXY_HOST = "proxy.16yun.cn"
PROXY_PORT = 8100
PROXY_USER = "16YUN"
PROXY_PASS = "16IP"
proxy_meta = f"http://{PROXY_USER}:{PROXY_PASS}@{PROXY_HOST}:{PROXY_PORT}"
proxies = {
    "http": proxy_meta,
    "https": proxy_meta,
}

# --------- HTTP 会话与头部设置 ---------
session = requests.Session()
session.proxies.update(proxies)
session.headers.update({
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
                  "(KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36",
})
# 示例 Cookie 设置
session.cookies.set("st_si", "123456789", domain="eastmoney.com")
session.cookies.set("st_asi", "abcdefg", domain="eastmoney.com")


# --------- 数据库初始化 ---------
conn = sqlite3.connect("eastmoney_news.db", check_same_thread=False)
cursor = conn.cursor()
cursor.execute("""
CREATE TABLE IF NOT EXISTS news (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    title TEXT,
    pub_time TEXT,
    content TEXT
)
""")
conn.commit()


# --------- 加载并量化模型(TFLite) ---------
# 假设已有 Keras 模型 'content_block_model.h5',先转换为 TFLite
def convert_to_tflite(h5_path, tflite_path):
    model = tf.keras.models.load_model(h5_path)
    converter = tf.lite.TFLiteConverter.from_keras_model(model)
    converter.optimizations = [tf.lite.Optimize.DEFAULT]
    tflite_model = converter.convert()
    with open(tflite_path, "wb") as f:
        f.write(tflite_model)

# convert_to_tflite("content_block_model.h5", "model_quant.tflite")  # 一次性执行

# 加载 TFLite 模型
interpreter = tf.lite.Interpreter(model_path="model_quant.tflite")
interpreter.allocate_tensors()
input_details = interpreter.get_input_details()
output_details = interpreter.get_output_details()

# 模型预测函数(批量)
def predict_blocks(text_list):
    # 文本预处理示例:截断/填充到固定长度
    seqs = [[ord(c) for c in text[:200]] + [0] * (200 - len(text[:200])) for text in text_list]
    inp = np.array(seqs, dtype=np.float32)
    interpreter.set_tensor(input_details[0]['index'], inp)
    interpreter.invoke()
    preds = interpreter.get_tensor(output_details[0]['index'])
    # 返回布尔列表,True 表示为"关键区块"
    return [bool(p[1] > 0.5) for p in preds]


# --------- 爬取解析函数 ---------
def fetch_and_parse(url):
    start = time.time()

    # 1. 获取页面
    resp = session.get(url, timeout=10)
    resp.raise_for_status()
    # 2. 解析 DOM
    soup = BeautifulSoup(resp.text, "lxml")
    # 3. 提取候选区块(示例:所有 <div>)
    divs = soup.find_all("div")
    texts = [div.get_text(strip=True) for div in divs]
    # 4. 批量模型预测
    is_key = predict_blocks(texts)
    # 5. 筛选关键区块并抽取新闻字段
    news_items = []
    for div, flag in zip(divs, is_key):
        if not flag:
            continue
        title_tag = div.find("h1") or div.find("h2") or div.find("h3")
        time_tag = div.find("span", class_="time") or div.find("em")
        content = div.get_text(strip=True)
        if title_tag and time_tag:
            news_items.append({
                "title": title_tag.get_text(strip=True),
                "pub_time": time_tag.get_text(strip=True),
                "content": content
            })
    # 6. 存储到 SQLite
    for item in news_items:
        cursor.execute(
            "INSERT INTO news (title, pub_time, content) VALUES (?, ?, ?)",
            (item["title"], item["pub_time"], item["content"])
        )
    conn.commit()

    end = time.time()
    return end - start  # 返回耗时


# --------- 多线程压测 ---------
if __name__ == "__main__":
    urls = [
        "https://www.eastmoney.com/a/20250422XYZ.html",
        # ... 更多新闻页 URL 列表 ...
    ]
    with ThreadPoolExecutor(max_workers=5) as executor:
        times = list(executor.map(fetch_and_parse, urls))
    print(f"平均单页耗时:{sum(times)/len(times):.2f} 秒")

说明

  • 上述代码中,爬虫代理、Cookie、User-Agent 都已配置;
  • 将 Keras 模型量化为 TFLite 并启用批量推理,缩短深度学习部分耗时;
  • 使用 ThreadPoolExecutor 并发抓取与解析;
  • 最终压测中,多线程 + 模型量化后,平均单页耗时降至约 2 秒。

通过以上性能调优思路和代码实现,可显著提高基于深度学习的 DOM 内容区块识别爬虫的效率,为大规模抓取与分类存储奠定坚实基础。

相关推荐
何双新2 小时前
第1讲:Transformers 的崛起:从RNN到Self-Attention
人工智能·rnn·深度学习
AIGC大时代2 小时前
高质量学术引言如何妙用ChatGPT?如何写提示词
人工智能·深度学习·chatgpt·学术写作·chatgpt-o3·deep reaserch
数据智能老司机4 小时前
构建具备自主性的人工智能系统——探索协调者、工作者和委托者方法
深度学习·llm·aigc
数据智能老司机4 小时前
构建具备自主性的人工智能系统——使代理能够使用工具和进行规划
深度学习·llm·aigc
2301_769624404 小时前
基于Pytorch的深度学习-第二章
人工智能·pytorch·深度学习
-一杯为品-5 小时前
【深度学习】#9 现代循环神经网络
人工智能·rnn·深度学习
硅谷秋水5 小时前
ORION:通过视觉-语言指令动作生成的一个整体端到端自动驾驶框架
人工智能·深度学习·机器学习·计算机视觉·语言模型·自动驾驶
豆芽8196 小时前
强化学习(Reinforcement Learning, RL)和深度学习(Deep Learning, DL)
人工智能·深度学习·机器学习·强化学习
别摸我的婴儿肥7 小时前
从0开始LLM-注意力机制-2
深度学习