
本文介绍一种基于正则表达式与句子级过滤的稳健方法,用于在 pandas 文本预处理中精准识别并移除“premium content”“login”“subscription”等典型付费墙提示语句,避免误删正文、支持多关键词批量匹配,且兼容省略号(…)等非标准分句场景。
本文介绍一种基于正则表达式与句子级过滤的稳健方法,用于在 pandas 文本预处理中精准识别并移除“premium content”“login”“subscription”等典型付费墙提示语句,避免误删正文、支持多关键词批量匹配,且兼容省略号(…)等非标准分句场景。
在新闻聚合、爬虫数据清洗或 NLP 预处理任务中,常遇到含付费墙提示的文本(如 “Premium Content is available to subscribers only. Please login here…”)。若直接用 nltk.sent_tokenize() 分句,可能因标点不规范(如省略号 …、无句号结尾、HTML 残留)导致切分失败;而逐词检测再整段丢弃,又极易误伤含关键词的合法正文(例如:“We recommend a subscription to our newsletter” 并非付费墙语句)。
更可靠的做法是:以句子为单位进行语义级过滤——先合理切分句子,再对每句执行“是否含付费墙意图”的判定,仅剔除明确服务于订阅引导的整句。
✅ 推荐方案:正则驱动的句子级过滤(兼容 Pandas)
以下函数专为 pandas.Series.str.apply() 设计,支持向量化处理:
import re
import pandas as pd
def remove_paywall_sentences(text: str,
keywords: list = None,
sep: str = r'[.!?]+|\.\.\.|…') -> str:
"""
从文本中移除包含付费墙关键词的完整句子。
Parameters:
-----------
text : str
待处理的原始文本
keywords : list of str, optional
付费墙敏感词列表,默认为 ["login", "subscription", "purchase.*subscription", "subscribers", "premium.*content"]
sep : str
句子分割正则表达式,默认支持 '.', '!', '?', '...' 和 '…'
Returns:
--------
str : 清洗后的文本(保留原标点,仅删除匹配句)
"""
if not isinstance(text, str) or not text.strip():
return text
if keywords is None:
keywords = [
r"login",
r"subscription",
r"purchase.*subscription",
r"subscribers",
r"premium.*content",
r"access.*content",
r"become.*member"
]
# 编译全局匹配模式:任意关键词出现在句中即命中(不区分大小写)
patt = re.compile('|'.join(f'({kw})' for kw in keywords), re.IGNORECASE)
# 使用正则安全分句(比 str.split('.') 更鲁棒)
sentences = re.split(sep, text)
# 重建带分隔符的句子对:[句1, 分隔符1, 句2, 分隔符2, ...]
parts = []
for i, part in enumerate(sentences):
if i % 2 == 0 and part.strip(): # 偶数索引为句子内容
parts.append(part.strip())
elif i % 2 == 1 and part.strip(): # 奇数索引为分隔符(保留用于还原格式)
parts.append(part)
# 按“句子内容”部分判断是否保留(跳过分隔符)
cleaned_parts = []
for i, part in enumerate(parts):
if i % 2 == 0 and part: # 只对句子内容做匹配
if not patt.search(part): # 不含付费墙关键词才保留
cleaned_parts.append(part)
# 若下一项是分隔符,一并保留(维持结构)
if i + 1 < len(parts) and not parts[i + 1].strip().isalpha():
cleaned_parts.append(parts[i + 1])
elif i % 2 == 1 and part and cleaned_parts: # 已有前句,且当前是合法分隔符
if not cleaned_parts[-1].endswith(part.strip()):
cleaned_parts.append(part)
# 合并结果(避免多余空格)
result = ''.join(cleaned_parts).strip()
# 清理连续空白与异常标点
result = re.sub(r'\s+', ' ', result)
result = re.sub(r'([.!?])\s+([a-z])', r'\1 \2', result) # 修复标点后空格
return result
# ✅ 在 Pandas 中使用示例:
df = pd.DataFrame({
'article_text': [
"In order to put a stop to the invasive bush honeysuckle... Premium Content is available to subscribers only. Please login here to access content or go here to purchase a subscription.",
"Of the hundreds of thousands of high school wrestlers... is part of that percentage. The Richmond junior joined that group by winning… Premium Content is available to subscribers only. Please login here to access content or go here to purchase a subscription."
]
})
df['clean_text'] = df['article_text'].apply(remove_paywall_sentences)
print(df['clean_text'].iloc[0])
# 输出:In order to put a stop to the invasive bush honeysuckle...⚠️ 关键注意事项
- 不要依赖 nltk.sent_tokenize 处理脏数据:其训练语料基于规范英文,对 …、—、嵌入 HTML 或缺失标点的文本鲁棒性差;
- 关键词需用正则而非精确匹配:如 "purchase a subscription" 应写为 r"purchase.*subscription",以覆盖 "purchase monthly subscription" 等变体;
- 保留上下文结构:本方案优先保留分隔符(./!/?/…),避免将两段合法内容错误合并;
- Pandas 向量化友好:函数设计为纯字符串操作,可直接用于 Series.apply(),无需 for 循环,性能优于逐句 re.search;
- 扩展性强:通过 keywords 参数可动态增删规则(如新增 "trial period" 或 "unlock full article")。
✅ 总结
清除付费墙文本的本质不是“删词”,而是“删意图句”。本文提供的方案以正则为核心、以句子为粒度、以 Pandas 兼容性为前提,兼顾准确性与工程实用性。它规避了传统方法中因分句不准导致的漏删/误删问题,并天然支持模糊匹配与多模式分隔,是构建健壮新闻文本清洗流水线的关键一环。

















