源码深度解读:bypass-paywalls-clean-filters 用户脚本的核心实现原理
【免费下载链接】bypass-paywalls-clean-filters项目地址: https://gitcode.com/gh_mirrors/by/bypass-paywalls-clean-filters
想免费阅读新闻网站上的付费文章?bypass-paywalls-clean-filters 就是一套开源的"绕过付费墙"方案,它由广告拦截过滤规则与用户脚本双引擎组成。本文不讨论怎么"偷内容",而是带你从源码层面看懂它如何精准识别并解除新闻网站的付费墙(Paywall)限制——这套实现原理对任何想理解前端反爬、DOM 操作与油猴脚本(UserScript)开发的开发者,都是一份极佳的学习样本。
项目整体架构:过滤器 + 用户脚本的双引擎设计
这个仓库的结构非常清晰,只有两个核心部分:
| 文件 | 作用 |
|---|---|
bpc-paywall-filter.txt | uBlock Origin / AdGuard 兼容的广告拦截规则,负责"堵":拦截计费脚本、删除 Cookie、剥离锁定样式 |
userscript/目录下的 7 个脚本 | 负责"疏":深度修复特定站点的 DOM、重建被隐藏的文章正文 |
为什么需要两套机制?因为很多网站的付费墙是纯前端实现——正文明明已经加载到 HTML 里,只是被 CSS、class 或 JS 锁住了。过滤规则负责"外科手术式"的拦截,用户脚本则负责更精细的"器官移植"。
仓库内按语言分出了 7 个用户脚本:userscript/bpc.en.user.js(英语)、bpc.de.user.js(德语)、bpc.fr.user.js(法语)、bpc.it.user.js(意大利语)、bpc.nl.user.js(荷兰语)、bpc.fi.se.user.js(芬兰语/瑞典语)、bpc.es.pt.user.js(西班牙语/葡萄牙语),针对不同语系媒体做定制修复。
用户脚本的运行环境:元数据里的玄机
打开userscript/bpc.en.user.js开头,你会看到一段标准的 UserScript 元数据块,这是理解整个脚本的钥匙:
@match *://*.com/*等规则:声明脚本在哪些域名下运行,相当于"上岗许可证";@connect archive.fo、@connect webcache.googleusercontent.com等:授权脚本跨域请求存档站点,这是后面"兜底方案"能工作的前提;@grant GM.xmlHttpRequest:申请油猴的高级跨域请求权限。
元数据之后,整个脚本被包在一个 IIFE(立即执行函数)里,并开启'use strict'严格模式,避免污染全局作用域。
核心机制一:域名路由分发——if/else 的优雅暴力
脚本最"朴素"也最核心的设计,是一个超长的if / else if链,按域名把世界媒体分组处理:
if (matchDomain('nzherald.co.nz')) { // 新西兰先驱报:把 isPremium 标记改为 false } else if (matchDomain(['thehindu.com', 'thehindubusinessline.com'])) { // 印度教报系:清掉 Adblock 检测与订阅状态 }其中matchDomain是路由分发的核心函数(见userscript/bpc.en.user.js3911 行附近):
function matchDomain(domains, hostname) { var matched_domain = false; if (!hostname) hostname = window.location.hostname; if (typeof domains === 'string') domains = [domains]; domains.some(domain => (hostname === domain || hostname.endsWith('.' + domain)) && (matched_domain = domain)); return matched_domain; }它既支持单域名字符串,也支持域名数组,还能通过endsWith匹配子域名——比如thestar.com与www.thestar.com都能命中。脚本中还预定义了大量的媒体集团域名组,如usa_gannett_domains(甘尼特报团)、usa_tribune_domains(论坛报集团)等,同一集团站点往往共用同一套付费墙技术,因此可以合并处理,这也是代码能保持精简的秘诀。
核心机制二:Cookie 清理——重置"阅读计数"
最常见的付费墙是"计量墙"(Metered Paywall):免费读者可读 N 篇文章,超出即锁定。原理就是靠 Cookie 或 localStorage 计数。脚本的反制手段简单粗暴——直接删 Cookie:
function setCookie(names, value, domain = '', path = '/', days = 0) { var max_age = days * 24 * 60 * 60; // 支持字符串、数组与正则三种匹配方式 // ... 写入空值 + max-age=0 使 Cookie 立即过期 window.localStorage.clear(); // 顺带清空本地存储 }比如对澳洲 Crikey 系网站,一行setCookie('blaize_session', '', domain, '/', 0)就把计量会话重置了。在过滤规则文件bpc-paywall-filter.txt里,同类操作由 uBlock 的 scriptlet 完成,例如:
artforum.com##+js(cookie-remover, /^/) apollo-magazine.com##+js(cookie-remover, blaize_session)cookie-remover是 uBlock Origin 内置的脚本注入器,等价于在页面里执行删除 Cookie 的 JS。这展示了"规则文件 + 用户脚本"两条腿走路的协同方式。
核心机制三:DOM 清洗——剥掉锁定层的"衣服"
很多付费墙并不删除正文,而是给正文容器加一个锁定 class(如content-locked),再配一个遮罩层。脚本要做的是把"衣服"脱掉:
removeDOMElement(...elements):直接移除遮罩、横幅、广告容器;hideDOMElement(...elements):给元素强加display:none !important;removeClassesByPrefix(el, prefix)/removeClassesList(list):按前缀批量剥离锁定 class;clearPaywall(paywall, paywall_action):按配置选择删元素还是删 class/attribute。
规则文件里的对应写法更简洁,直接用 uBlock 的 cosmetic filtering:
citywire.com##+js(rc, article-locked, .article-locked) bloomberg.com##+js(ra,>function waitDOMElement(selector, tagName = '', callback, multiple = false) { new window.MutationObserver(function (mutations) { for (let mutation of mutations) { for (let node of mutation.addedNodes) { if (node.matches(selector)) { callback(node); if (!multiple) this.disconnect(); } } } }).observe(document, { subtree: true, childList: true }); }只要目标节点一出现就立刻执行回调,处理完自动断开监听,性能开销极小。这是处理 SPA(单页应用)和延迟渲染站点(如纽约时报、Medium)的关键技术。
核心机制五:页面级注入——绕过页面自己的反制
某些站点会检测"脚本是否运行在页面上下文",比如通过window.Adblock之类的全局标记。此时用户脚本的沙箱环境反而成了障碍,insert_script应运而生(userscript/bpc.en.user.js4414 行):
function insert_script(func, insertAfterDom) { let script = document.createElement('script'); script.setAttribute('id', 'bpc_script'); script.appendChild(document.createTextNode('(' + func + ')();')); (insertAfterDom || document.body || document.head).appendChild(script); }它把函数序列化为字符串,动态创建<script>标签插入页面,让代码在页面自身的 JS 上下文中执行——比如直接改写window.Fusion.globalContent.isPremium = false,从数据源头解除锁定,比操作 DOM 更彻底。
核心机制六:内容重建——从 JSON 里"捞"回正文
最硬核的一招:当正文被彻底移除时,脚本直接从页面内嵌的 JSON 数据里把文章内容重新解析出来。getArticleJsonScript会查找application/ld+json类型的脚本标签;getArticleQuintype则针对 Quintype 内容平台(印度多家媒体使用)解析#static-page中的结构化数据,把 text、title、image、tweet、YouTube 视频等元素逐一重建为 HTML。
对于使用 WordPress REST API 的站点,getJsonUrlText会直接fetch文章的 JSON 接口:
let json_url = window.location.origin + '/wp-json/wp/v2/posts/' + article_id; fetch(json_url).then(response => { /* 解析 json.content.rendered 并注入页面 */ });拿到 JSON 后用DOMParser解析,再通过getJsonUrlAdd把重建的正文替换进文章容器。这一整套"数据层恢复"逻辑(见userscript/bpc.en.user.js4425 至 4560 行),展示了如何绕过 UI 层直接从数据源取回内容——堪称整份源码最精彩的部分。
核心机制七:兜底方案——外部存档链接
当以上手段全部失效,脚本会在文章顶部插入一个红色提示条,提供外部镜像链接:archive.today 存档(getArchive/archiveLink)、Google 网页快照(googleWebcacheLink)、Freedium / ReadMedium(Medium 专用)等。archiveRandomDomain还会随机挑选archive.fo / archive.is / archive.li等镜像域名,规避单点封禁。
有趣的是randomIP函数——它生成随机 IP 字符串,用于配合某些对请求频率敏感的存档服务。这些细节体现了项目对"反反爬"生态的深入理解。
附加能力:AMP 页面重定向
AMP(加速移动页面)经常被当作付费墙的"后门"——AMP 版文章往往不带计量限制。脚本的amp_redirect会检测 AMP 页面并跳转到对应的 canonical(原始)地址;ampToHtml则反向操作,把某些站点重定向回非 AMP 版本。amp_images_replace/amp_iframes_replace还会把<amp-img>、<amp-iframe>替换为标准 HTML 标签,保证内容完整渲染。
过滤规则里的宝藏:scriptlet 用法速查
bpc-paywall-filter.txt虽然只有 700 多行,却浓缩了 uBlock Origin scriptlet 的各种实战用法:
| scriptlet | 作用 | 示例 |
|---|---|---|
cookie-remover | 删除指定 Cookie | adweek.com##+js(cookie-remover, blaize_session) |
rc | 移除 class | elespanol.com##+js(rc, content-not-granted-paywall, ...) |
ra | 移除属性 | bizjournals.com##+js(ra, style, .paywalled-content[style], stay) |
set-local-storage-item | 清空 localStorage 键值 | csmonitor.com##+js(set-local-storage-item, /^/, $remove$) |
json-prune | 删除 JSON 响应字段 | gadget.pico.tools##+js(json-prune, locked) |
set | 覆盖全局变量 | dagsavisen.no##+js(set, window.Fusion.globalContent..., 0) |
配合||piano.io/xbuilder/experience/execute$xmlhttprequest,third-party这类网络请求拦截规则,可以在请求层面直接掐断计费系统的数据上报。
总结:一套值得反复研读的前端反制范本
回看整个 bypass-paywalls-clean-filters 项目,它的核心实现原理可以浓缩为四句话:
- 匹配:用
matchDomain做域名路由,按媒体集团批量适配; - 重置:删 Cookie、清 localStorage,让计量墙"失忆";
- 剥离:移除锁定 class/属性/遮罩元素,把正文从"牢笼"里放出来;
- 重建:从 JSON 数据层或外部存档恢复完整内容。
对普通用户而言,只需在 Tampermonkey 中安装对应语言的用户脚本(如userscript/bpc.en.user.js),并在 uBlock Origin 中订阅bpc-paywall-filter.txt即可体验;对开发者而言,这份源码是学习 MutationObserver、DOM 重建、scriptlet 注入、跨域请求授权等前端高级技巧的绝佳教材。理解原理不是鼓励绕过付费,而是让你在面对任何"前端限制"时,都能多一种优雅的解决思路。
【免费下载链接】bypass-paywalls-clean-filters项目地址: https://gitcode.com/gh_mirrors/by/bypass-paywalls-clean-filters
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考