> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# Laravel FullFeed

> 面向 feed 阅读器，从网页中提取主内容的 Laravel 包。基于 Laravel 的 Pipeline 模式设计。

## 概览

[revolution/laravel-fullfeed](https://github.com/invokable/laravel-fullfeed) 是一个用于从网页中为 feed 阅读器抽取正文的 Laravel 包。
它通过每个站点的规则（JSON）来提取每篇文章所需的内容。

<Info>
  这个功能原本是在一个私有的 feed 阅读器应用中使用，后来被抽离出来做成了公开的包。
</Info>

## 环境要求

* PHP >= 8.4（使用 `Dom\HTMLDocument`）
* Laravel >= 12.x

## 安装

```bash theme={null}
composer require revolution/laravel-fullfeed
```

要使用开发版：

```bash theme={null}
composer require revolution/laravel-fullfeed:dev-main
```

## 发布配置文件与站点定义

```bash theme={null}
php artisan vendor:publish --tag=fullfeed
```

这条命令会创建：

* `config/fullfeed.php`
* `resources/fullfeed`

## 定义文件的自动更新（composer post-update-cmd）

如果希望在 `composer update` 时自动重新发布站点定义文件，可以在 `composer.json` 中添加：

```json theme={null}
{
  "scripts": {
    "post-update-cmd": [
      "@php artisan vendor:publish --tag=laravel-assets --ansi --force",
      "@php artisan vendor:publish --tag=fullfeed-site --ansi --force"
    ]
  }
}
```

## 基本用法

```php theme={null}
use Revolution\Fullfeed\Facades\FullFeed;

$html = FullFeed::get($url);
```

## 测试

通过 `FullFeed::expects()` 可以对 Facade 进行 stub。

```php theme={null}
use Revolution\Fullfeed\Facades\FullFeed;

FullFeed::expects('get')
    ->with('https://example.com/article/1')
    ->andReturn('<div>Main content</div>');
```

## 站点规则文件

### items\_all.json

`items_all.json` 是用来导入 LDRFullFeed (wedata) 格式规则的基础文件。
Livedoor Reader 曾经是日本很有名的服务，尽管服务本身已经关闭，但其规则数据作为资产被保留了下来。FullFeed 利用了这一历史遗产。

### plus.json

`plus.json` 是用于添加自定义规则的示例。

```json theme={null}
{
  "name": "note",
  "data": {
    "url": "^https://note\\.com/",
    "selector": "div[data-name=\"body\"]",
    "xpath": "//div[@data-name=\"body\"]",
    "enc": "UTF-8",
    "callable": "App\\FullFeed\\CustomExtractor"
  }
}
```

## 规则配置字段

* `url`: 用来匹配目标 URL 的正则表达式
* `selector`: CSS 选择器（优先于 `xpath`）
* `xpath`: XPath 表达式
* `enc`: 需要字符编码转换时指定的编码
* `callable`: 作为前处理执行的自定义 Extractor 类（单个或数组）
* `after_callable`: 最后作为后处理执行的 Extractor 类

## Extractor 的执行顺序（Pipeline 模式）

FullFeed 通过 Laravel 的 **Pipeline 模式**，按顺序调度 Extractor。

1. `callable` 指定的类
2. `XPathExtractor`
3. `SelectorExtractor`
4. `after_callable` 指定的类

这样在简单的 XPath / CSS 抽取前后都可以插入自定义处理，可以很方便地应对不同站点的差异。

## 内置 Extractor

### RemoveElements

删除指定选择器匹配到的元素。

```json theme={null}
{
  "after_callable": ["Revolution\\Fullfeed\\Extractor\\RemoveElements"],
  "remove": ["svg", "button", "script"]
}
```

### ReplaceMatches

用正则表达式替换匹配到的字符串（针对 HTML 字符串处理）。

```json theme={null}
{
  "after_callable": ["Revolution\\Fullfeed\\Extractor\\ReplaceMatches"],
  "replace": [
    {
      "pattern": "/ data-(h-)?index=\"[0-9]+\"/",
      "replace": ""
    }
  ]
}
```

### StripTags

相当于 `strip_tags()`，用来剥离标签。

```json theme={null}
{
  "after_callable": ["Revolution\\Fullfeed\\Extractor\\StripTags:a,img"]
}
```

### Squish

使用 `Str::squish()` 去除多余空白。

```json theme={null}
{
  "after_callable": ["Revolution\\Fullfeed\\Extractor\\Squish"]
}
```

## 添加自定义规则

1. 在 `resources/fullfeed` 中添加 JSON 文件
2. 将其加入 `config/fullfeed.php` 的 `paths`

由于会使用第一个匹配 `data.url` 的规则，建议把新增文件放在 `paths` 的前面。


## Related topics

- [Feed Generator](/zh/packages/laravel-bluesky/feed-generator.md)
- [Feedable](/zh/packages/feedable/index.md)
- [Bot 教程 - Laravel Bluesky](/zh/packages/laravel-bluesky/bot-tutorial.md)
- [支持的站点列表 - Feedable](/zh/packages/feedable/drivers.md)
- [核心包与自定义驱动 - Feedable](/zh/packages/feedable/core.md)
