使用Goutte在Laravel中抓取的文件夹结构

时间:2019-11-07 03:13:04

标签: laravel

对于用于抓取代码的文件夹结构,我有些困惑。使用console/commands,而不是controller。因此,在handle function中,我正在编写整个抓取代码。但是我应该这样做吗?或者...什么是最好的方法?

已更新

如果我正确理解以下答案。现在应该看起来像这样。

呼叫服务

class siteControl extends Command
{

    protected $signature = 'bot:scrape {website_id}';

    protected $description = 'target a portal site and scrape';

    public function __construct()
    {
        parent::__construct();
    }

    public function handle()
    {
        $website_id = $this->argument("website_id");
        if ($website_id == 1) {
            $portal = "App\Services\Site1";
        }

        $crawler = new $portal;
        $crawler->run();

    }
}

在处理方法中

class Site1 extends Utility 
{

    public function __construct()
    {
        parent::__construct();
    }

    public function run()
    {        
        echo "method runs";
    }
}

摘要:

use Goutte\Client;

abstract class Utility implements SiteInterfaces
{

    protected $client;

    public function __construct()
    {
        $this->client = new Client();
    }

} 

界面:

namespace App\Services;

interface SiteInterfaces
{
    public function run();
}

最后,我应该在run()方法中编写整个抓取代码?请纠正我。如果对此有误...我正在寻找最佳解决方案。

1 个答案:

答案 0 :(得分:1)

最佳做法是从命令handle()方法中调用单独的服务。这样,您可以在控制器中重用相同的服务。

技术版本:

  1. 您的应用程序有特定的工作要做(如果需要,可以执行命令)。此命令来自应用程序外部,可以是Web控制器,API控制器或CLI应用程序之类的任何内容。在六角形结构方面,这称为port
  2. 一旦应用程序收到这样的命令,它就不必关心它来自哪个端口。通过在一个点(命令处理程序)中处理所有类似的命令,不必担心命令的来源。

因此,给您一个简短的概述:

[Web request]  [CLI command]       <-- these are ports
       \           /
        \         /
         \       /
         [Command]                <--- this is a method call to your service
             |
             |
             |
     [Command handler]            <--- this is the service doing the actual work

更新了我的答案

根据您提供的代码,我实现了上面提到的内容,

app / Console / Command / BotScrapeCommand.php

这是我上面提到的CLI命令。该类要做的所有事情是: 1.收集输入参数; (website_id) 2.将这些参数包装在命令中 3.使用命令处理程序触发命令

namespace App\Console\Commands;

use App\Command\ScrapePortalSiteCommand;
use CommandHandler\ScrapePortalSiteCommandHandler;

class BotScrapeCommand extends Command
{
    protected $signature = 'bot:scrape {website_id}';

    protected $description = 'target a portal site and scrape';

    public function handle(ScrapePortalSiteCommandHandler $handler)
    {
        $portalSiteId = $this->argument("website_id");
        $command = new ScrapePortalSiteCommand($portalSiteId);
        $handler->handle($command);
    }
}

app / Command / ScapePortalSiteCommand.php

这是我上面提到的命令。它的工作是将所有输入参数包装在一个类中,命令处理程序可以使用该类。

namespace App\Command;


class ScrapePortalSiteCommand
{
    /**
     * @var int
     */
    private $portalSiteId;

    public function __construct(int $portalSiteId)
    {
        $this->portalSiteId = $portalSiteId;
    }

    public function getPortalSiteId(): int
    {
        return $this->portalSiteId;
    }
}

app / CommandHandler / ScrapePortalSiteCommandHandler.php

命令处理程序应基于其命令实现逻辑。在这种情况下,需要找出要选择的爬虫,然后将其解雇。

namespace App\CommandHandler;

use App\Command\ScrapePortalSiteCommand;
use App\Crawler\PortalSite1Crawler;
use App\Crawler\PortalSiteCrawlerInterface;
use InvalidArgumentException;

class ScrapePortalSiteCommandHandler
{
    public function handle(ScrapePortalSiteCommand $command): void
    {
        $crawler = $this->getCrawlerForPortalSite($command->getPortalSiteId());
        $crawler->crawl();
    }

    private function getCrawlerForPortalSite(int $portalSiteId): PortalSiteCrawlerInterface {
        switch ($portalSiteId) {
            case 1:
                return new PortalSite1Crawler();
            default:
                throw new InvalidArgumentException(
                    sprintf('No crawler configured for portal site with id "%s"', $portalSiteId)
                );
        }
    }
}

app / Crawler / PortalSiteCrawlerInterface.php

该接口可确保可以以类似方式调用所有搜寻器。此外,它还提供了不错的类型提示。

namespace App\Crawler;


interface PortalSiteCrawlerInterface
{
    public function crawl(): void;

}

app / Crawler / PortalSite1Crawler.php

这是执行实际抓取的地方。

namespace App\Crawler;


class PortalSite1Crawler implements PortalSiteCrawlerInterface
{
    public function crawl(): void
    {
        // Crawl your site here
    }
}

另一个更新

在您有additional questions的情况下,我再次更新了答案。

:void

在方法声明中使用: void意味着该方法将不返回任何内容。以相同的方式public function getPortalSiteId(): int表示此方法将始终返回整数。返回类型提示的使用已添加到PHP 7中,而并非特定于Laravel。可以在the PHP documentation中找到有关返回类型提示的更多信息。

命令和处理程序

使用命令和命令处理程序是一种最佳实践,它是命令总线模式的一部分。此模式描述了处理用户输入(命令)的通用方法。 This post对命令和处理程序提供了很好的解释。此外,this blog post更详细地描述了什么是命令总线,如何使用命令总线以及其优点是什么。请注意,在我提供的代码中,总线实现本身被跳过。我认为您本身并不需要它,但在某些情况下确实可以增加价值。