dashed/laravel-seo-scanner

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

资助包维护!
dashed

dev-main 2024-04-09 12:20 UTC

This package is auto-updated.

Last update: 2024-09-09 13:24:28 UTC


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 dashed/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,过渡词将是荷兰语或英语。如果您想添加更多语言环境,可以创建一个 pull request。

元数据

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

性能

✅ 首字节时间(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 Dashed\LaravelSeo\Jobs\Scan;

Scan::dispatch();

扫描单个路由

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

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

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

扫描单页应用(SPA)应用程序中的路由

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

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

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

扫描模型 URL

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

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

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

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

use Dashed\Seo\Traits\HasSeoScore;
use Dashed\Seo\SeoInterface;

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

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

    public function getUrlAttribute(): string
    {
        return 'https://dashed.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 Dashed\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 Dashed\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. 在您的应用程序中创建一个新类,该类实现了Dashed\Seo\Interfaces\Check接口。
  2. Dashed\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 Dashed\Seo\Interfaces\Check;
use Dashed\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' => [
        'Dashed\\Seo\\Checks' => base_path('vendor/dashed/laravel-seo-scanner/src/Checks'),
        'App\\Support\\Seo\\Checks' => base_path('app/Support/Seo/Checks'),
    ],
];

测试

composer test

变更日志

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

贡献

有关详细信息,请参阅贡献指南

安全漏洞

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

致谢

许可协议

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