ормkracht10/laravel-seo-scanner

Laravel 包用于检查您是否在网站上使用了重要的 SEO 标签。


README

Total Downloads Tests PHPStan GitHub release (latest by date) Packagist PHP Version Support Latest Version on Packagist

提升您网页 SEO 评分的 Laravel 工具

Screenshot 2023-01-05 at 15 02 31

简介

此包是您在搜索引擎上获得更好 SEO 评分的指南。Laravel SEO Scanner 扫描您的代码并爬取应用程序的路由。此包包含 24 项检查,将检查性能、配置、元标签的使用和内容质量。

轻松配置要扫描的路由、排除或包含特定的检查,甚至添加您自己的检查!完成检查将进一步提高 SEO 评分,从而增加在搜索引擎中排名更高的机会。

最低要求

  • PHP 8.1 或更高版本
  • Laravel 9.0 或更高版本

安装

您可以通过 composer 安装此包

composer require vormkracht10/laravel-seo-scanner

如果您想扫描使用 JavaScript 渲染的页面,例如 Vue 或 React,则需要安装 Puppeteer。您可以使用以下命令进行安装

如果您想了解如何扫描使用 JavaScript 渲染的页面,请参阅 在 SPA 应用程序中扫描路由。想了解更多关于 Puppeteer 的信息?请参阅 Puppeteer 文档

npm install puppeteer

运行安装命令以发布配置文件并运行迁移

php artisan seo:install

或者您可以手动发布配置文件并运行迁移

php artisan vendor:publish --tag="seo-migrations"
php artisan migrate
php artisan vendor:publish --tag="seo-config"

点击此处查看 配置文件

可用的检查

这些检查在包中可用。您可以在配置文件中添加或删除检查。这些检查基于 SEO 最佳实践,如果所有检查都是绿色的,则您的网站将具有很好的 SEO 评分。如果您想添加更多检查,可以创建一个 pull request。

配置

✅ 页面未设置 'noindex'。
✅ 页面未设置 'nofollow'。
✅ Robots.txt 允许索引。

内容

✅ 页面有一个 H1 标签,并且如果它只在一个页面上使用一次。
✅ 所有链接都重定向到使用 HTTPS 的 URL。
✅ 每个图片都有一个 alt 属性。
✅ 页面不包含断开链接。
✅ 页面不包含断开图片。
✅ 内容长度至少为 2100 个字符。
✅ 内容中不超过 20% 的内容包含过长的句子(超过 20 个单词)。
✅ 至少 30% 的句子包含过渡词或短语。

注意:要更改过渡词的本地化,您可以发布配置文件并在配置文件中更改本地化。默认本地化为 null,它使用您的 app 配置的语言。如果设置为 nlen,过渡词将使用荷兰语或英语。如果您想添加更多本地化,可以创建一个拉取请求。

元标签

✅ 页面有元描述。
✅ 页面标题不超过 60 个字符。
✅ 页面有一个 Open Graph 图像。
✅ 在 html 标签上设置了 lang 属性。
✅ 标题包含一个或多个关键词。
✅ 第一个段落中有一个或多个关键词。

性能

✅ 首字节时间 (TTFB) 低于 600ms。
✅ 页面响应返回 200 状态码。
✅ HTML 的大小不超过 100 KB。
✅ 图片大小不超过 1 MB。
✅ JavaScript 文件大小不超过 1 MB。
✅ CSS 文件大小不超过 15 KB。
✅ HTML 已 GZIP 压缩。

用法

在本地环境中运行扫描器

如果您在本地开发环境中使用自动签名的 SSL 证书,您可能想要禁用 SSL 证书完整性检查。您可以在配置文件中的 http.options 数组中添加以下选项来完成此操作

'http' => [
    'options' => [
        'verify' => false,
    ],
],

也可以向 HTTP 客户端传递自定义头信息。例如,如果您想设置自定义用户代理,您可以在配置文件中的 http.headers 数组中添加以下选项

'http' => [
    'headers' => [
        'User-Agent' => 'My custom user agent',
    ],
],

扫描路由

默认情况下,所有 GET 路由都将进行 SEO 检查。如果您想检查特定路由的 SEO 评分,您可以将路由名称添加到配置文件中的 routes 数组中。如果您想跳过一个路由,您可以将路由名称添加到配置文件中的 exclude_routes 数组中。如果您不想检查路由的 SEO 评分,您可以在配置文件中将 check_routes 选项设置为 false

要检查路由的 SEO 评分,请运行以下命令

php artisan seo:scan

如果您想排队扫描并手动触发它,可以调度 'Scan' 任务

use Vormkracht10\LaravelSeo\Jobs\Scan;

Scan::dispatch();

扫描单个路由

想要获取特定 URL 的评分?运行以下命令

php artisan seo:scan-url https://vormkracht10.nl

注意:该命令将仅检查 URL 的 SEO 评分并在 CLI 中输出评分。它不会将评分保存到数据库中。

在 SPA 应用程序中扫描路由

如果您有一个 SPA 应用程序,您可以启用 JavaScript 渲染。这将使用无头浏览器来渲染内容。要启用 JavaScript 渲染,请将配置文件中的 javascript 选项设置为 true。您也可以通过将 --javascript 选项添加到命令中为单个路由启用 JavaScript 渲染。

php artisan seo:scan-url https://vormkracht10.nl --javascript

注意:此命令将使用 Puppeteer 来渲染页面。请确保您已经在系统上安装了 Puppeteer。您可以通过运行以下命令来安装 Puppeteer:npm install puppeteer目前它仅适用于扫描单个路由。

节流

如果您想限制请求,您可以在配置文件中将 throttle 选项设置为 true。您也可以通过设置配置文件中的 requests_per_minute 选项来设置每分钟的请求数量。

'throttle' => [
    'enabled' => false,
    'requests_per_minute' => 10,
],

扫描模型 URL

当您有一个具有许多与模型相关的页面的应用程序时,您可以将 SEO 评分保存到模型中。这样,您就可以检查特定页面的 SEO 评分并在您的应用程序中显示它。

例如,您有一个 BlogPost 模型,其中每个内容项都有一个页面

  1. 将模型添加到配置文件中的 models 数组中。
  2. 在您的模型中实现 SeoInterface
  3. HasSeoScore 特性添加到您的模型中。

注意:请确保模型有一个 url 属性。此属性将用于检查模型的 SEO 评分。还要检查迁移是否已运行。否则,命令将失败。

use Vormkracht10\Seo\Traits\HasSeoScore;
use Vormkracht10\Seo\SeoInterface;

class BlogPost extends Model implements SeoInterface
{
    use HasFactory,
        HasSeoScore;

    protected $fillable = [
        'title',
        'description',
        'slug',
        // ...
    ];

    public function getUrlAttribute(): string
    {
        return 'https://vormkracht10.nl/' . $this->slug;
    }
}

您可以通过在模型上调用 seoScore()seoScoreDetails() 方法来获取模型的 SEO 评分。这些方法在 HasSeoScore 特性中定义,并且您可以通过在模型中添加修改后的方法来覆盖它们。

要填充数据库中所有模型的评分,请运行以下命令

php artisan seo:scan

要获取模型的 SEO 评分,您有以下几种选择

  1. 从数据库中获取单个模型的 SEO 评分
$scores = Model::withSeoScores()->get();
  1. 对单个模型执行 SEO 评分检查
$model = Model::first();

// Get just the score
$score = $model->getCurrentScore();

// Get the score including the details
$scoreDetails = $model->getCurrentScoreDetails();

将扫描保存到数据库

当您想要将 SEO 评分保存到数据库中时,您需要将配置文件中的 save 选项设置为 true

'database' => [
    'connection' => 'mysql',
    'save' => true,
    'prune' => [
        'older_than_days' => 30,
    ],
],

您还可以在配置文件中指定数据库连接。如果您想将 SEO 评分保存到模型中,您需要将模型添加到配置文件中的 models 数组中。更多关于此的信息可以在检查模型的 SEO 评分部分找到。

修剪数据库

默认情况下,该软件包将修剪数据库中的旧扫描。您可以在配置文件中指定您想要在数据库中保留扫描的天数。默认为 30 天。

如果您想要修剪数据库,您需要在您的 App\Console\Kernel 中添加修剪命令

protected function schedule(Schedule $schedule)
{
    // ...
    $schedule->command('model:prune')->daily();
}

有关修剪数据库的更多信息,请参阅Laravel 文档

监听事件

当您运行 seo:scan 命令时,该软件包将触发一个事件来通知您它已完成。您可以监听这些事件并对数据进行一些操作。例如,当页面的 SEO 评分低于某个阈值时,您可以向管理员发送电子邮件。在您的 EventServiceProvider 中添加以下代码

protected $listen = [
    // ...
    ScanCompleted::class => [
        // Add your listener here
    ],
];

检索扫描

您可以使用 SeoScan 模型从数据库中检索扫描结果。该模型用于将扫描结果保存到数据库中。您可以使用 SeoScan 模型从数据库中检索扫描结果。例如

use Vormkracht10\Seo\Models\SeoScan;

// Get the latest scan
$scan = SeoScan::latest()->first();

// Get the failed checks
$failedChecks = $scan->failedChecks;

// Get the total amount of pages scanned
$totalPages = $scan->pages;

检索评分

您可以使用 SeoScore 模型从数据库中检索评分。该模型用于将评分保存到数据库中。您可以使用 SeoScore 模型从数据库中检索评分。例如

use Vormkracht10\Seo\Models\SeoScore;

// Get the latest score
$score = SeoScore::latest()->first();

// Or get all scores for a specific scan
$scan = SeoScan::latest()->with('scores')->first();

添加您自己的检查

您可以为该软件包添加自己的检查。为此,您需要在您的应用程序中创建一个 check 类。

  1. 在您的应用程序中创建一个实现 Vormkracht10\Seo\Interfaces\Check 接口的新类。
  2. Vormkracht10\Seo\Traits\PerformCheck 特性添加到您的类中。
  3. 将检查类的基路径添加到配置文件中的 check_paths 数组。

示例

在这个示例中,我使用 symfony/dom-crawler 软件包来爬取页面的 HTML,因为这与使用 preg_match 等方法相比要可靠得多。请随意使用您想要的任何东西。爬虫总是传递到 check 方法中,因此您仍然需要在您的 check 方法中定义 $crawler 参数。

<?php

namespace App\Support\Seo\Checks;

use Illuminate\Http\Client\Response;
use Symfony\Component\DomCrawler\Crawler;
use Vormkracht10\Seo\Interfaces\Check;
use Vormkracht10\Seo\Traits\PerformCheck;

class CanonicalCheck implements Check
{
    use PerformCheck;

    /**
     * The name of the check.
     */
    public string $title = "The page has a canonical meta tag";

    /**
     * The priority of the check (in terms of SEO).
     */
    public string $priority = 'low';

    /**
     * The time it takes to fix the issue.
     */
    public int $timeToFix = 1;

    /**
     * The weight of the check. This will be used to calculate the score.
     */
    public int $scoreWeight = 2;

    /**
     * If this check should continue after a failure. You don't
     * want to continue after a failure if the page is not
     * accessible, for example.
     */
    public bool $continueAfterFailure = true;

    public string|null $failureReason;

    /* If you want to check the actual value later on make sure
     * to set the actualValue property. This will be used
     * when saving the results.
     */
    public mixed $actualValue = null;

    /* If you want to check the expected value later on make sure
     * to set the expectedValue property. This will be used
     * when saving the results.
     */
    public mixed $expectedValue = null;

    public function check(Response $response, Crawler $crawler): bool
    {
        // Feel free to use any validation you want here.
        if (! $this->validateContent($crawler)) {
            return false;
        }

        return true;
    }

    public function validateContent(Crawler $crawler): bool
    {
        // Get the canonical meta tag
        $node = $crawler->filterXPath('//link[@rel="canonical"]')->getNode(0);

        if (! $node) {
            // We set the failure reason here so this will be showed in the CLI and saved in the database.
            $this->failureReason = 'The canonical meta tag does not exist';
            return false;
        }

        // Get the href attribute
        $this->actualValue = $node->getAttribute('href');

        if (! $this->actualValue) {
            // The failure reason is different here because the canonical tag exists, but it does not have a href attribute.
            $this->failureReason = 'The canonical meta tag does not have a href attribute';

            return false;
        }

        // The canonical meta tag exists and has a href attribute, so the check is successful.
        return true;
    }
}

配置文件

return [
    // ...
    'check_paths' => [
        'Vormkracht10\\Seo\\Checks' => base_path('vendor/vormkracht10/laravel-seo-scanner/src/Checks'),
        'App\\Support\\Seo\\Checks' => base_path('app/Support/Seo/Checks'),
    ],
];

测试

composer test

变更日志

有关最近更改的更多信息,请参阅 变更日志

贡献

有关贡献细节,请参阅 贡献指南

安全漏洞

有关如何报告安全漏洞,请参阅我们的安全策略

鸣谢

许可

MIT 许可证 (MIT)。有关更多信息,请参阅 许可文件