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

如何将Adblock规则应用到MechanicalSoup获取的网页?

解决MechanicalSoup网页处理的编码报错与Adblock规则应用方案

嘿,我来帮你搞定这两个问题——先是那个烦人的Unicode编码声明报错,再是把Adblock规则顺利应用到你抓取的网页上。

一、先搞定编码声明的ValueError

你碰到的ValueError: Unicode strings with encoding declaration are not supported...这个问题,本质是lxml的etree解析器不接受带XML编码声明(比如<?xml version="1.0" encoding="UTF-8"?>)的Unicode字符串,它更偏好直接处理字节流或者不带声明的内容片段。这里给你两个简单的修复方案:

方案1:直接用字节流解析(推荐)

MechanicalSoup返回的page.content是原始字节数据,直接用它初始化etree就能绕开编码声明的坑:

import mechanicalsoup
from lxml import etree

browser = mechanicalsoup.StatefulBrowser()
page = browser.open("https://your-target-url.com")

# 直接用字节内容解析etree,完美避开编码问题
tree = etree.HTML(page.content)

方案2:手动移除编码声明再解析

如果你已经拿到了字符串格式的网页内容,手动砍掉开头的XML声明就行:

html_str = page.text
# 检查并移除开头的XML编码声明
if html_str.startswith('<?xml'):
    html_str = html_str.split('?>', 1)[1].strip()
tree = etree.HTML(html_str)

二、给抓取的网页应用Adblock规则

要把Adblock规则用到已下载的网页上,核心是解析规则,然后移除网页中匹配的元素。我们主要处理元素隐藏规则(比如##.ad-container、#ad-banner这类),因为网络请求类规则可以在抓取阶段拦截,这里先聚焦页面元素处理:

1. 解析Adblock规则

推荐用adblock-parser库来解析规则(先装一下:pip install adblock-parser),它能帮你处理大部分标准的Adblock语法:

from adblockparser import AdblockRules

# 你的Adblock规则列表,替换成你自己的
adblock_rules = [
    "##.ad-box",
    "#top-ad",
    "###sidebar-ad",
    "div[class*='advert']"
]

# 初始化规则解析器
rules = AdblockRules(adblock_rules)

2. 移除匹配规则的元素

不管你用BeautifulSoup还是lxml etree,都可以遍历元素并检查匹配:

用BeautifulSoup实现(MechanicalSoup自带的soup对象直接用)

soup = page.soup  # 直接拿MechanicalSoup返回的BeautifulSoup对象

# 遍历所有元素,检查是否要隐藏
for element in soup.find_all():
    # 构造规则匹配需要的元素信息
    selector_info = {
        "tag": element.name,
        "id": element.get("id", ""),
        "class": element.get("class", []),
        "attributes": element.attrs
    }
    # 匹配到就移除元素
    if rules.should_hide_element(selector_info):
        element.decompose()

用lxml etree实现

# 写个递归函数遍历节点并移除广告元素
def remove_ad_elements(node):
    # 先处理子节点,避免遍历过程中节点被删除导致的问题
    for child in list(node):
        remove_ad_elements(child)
    
    # 构造当前节点的匹配信息
    tag = node.tag if hasattr(node, 'tag') else ''
    node_id = node.get('id', '')
    node_classes = node.get('class', [])
    attrs = node.attrib
    
    selector_info = {
        "tag": tag,
        "id": node_id,
        "class": node_classes,
        "attributes": attrs
    }
    
    # 匹配规则就移除
    if rules.should_hide_element(selector_info):
        parent = node.getparent()
        if parent is not None:
            parent.remove(node)

# 处理整个etree树
remove_ad_elements(tree)

3. 保存处理后的内容

处理完之后,你可以直接保留BeautifulSoup对象或者etree对象用于后续操作,也可以转成HTML文件保存:

# 保存BeautifulSoup处理后的内容
with open("cleaned_page.html", "w", encoding="utf-8") as f:
    f.write(soup.prettify())

# 保存etree处理后的内容
cleaned_html = etree.tostring(tree, encoding='utf-8', pretty_print=True).decode('utf-8')
with open("cleaned_page_etree.html", "w", encoding="utf-8") as f:
    f.write(cleaned_html)

三、额外小贴士

  • 有些复杂的Adblock规则(比如伪类、高级通配符)adblock-parser可能支持得不够完美,如果遇到这种情况,可以手动扩展匹配逻辑。
  • 如果要处理网络请求类的Adblock规则(比如阻止加载广告图片、脚本),可以给MechanicalSoup的session添加钩子,拦截匹配规则的请求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 09:04:29