【问题标题】:How to force my app to use Goutte instead of Symfony?如何强制我的应用使用 Goutte 而不是 Symfony?
【发布时间】:2021-09-01 10:42:51
【问题描述】:

我正在尝试使用 Laravel、Goutte 和 Guzzle 对网页进行翻页。我正在尝试将一个 guzzle 实例传递给 Goutte,但我的 Web 服务器一直在尝试使用 Symfony\Contracts\HttpClient\HttpClientInterfac。这是我得到的确切错误:

Argument 1 passed to Symfony\Component\BrowserKit\HttpBrowser::__construct() must be an instance of Symfony\Contracts\HttpClient\HttpClientInterface or null, instance of GuzzleHttp\Client given, called in /opt/bitnami/apache/htdocs/app/Http/Controllers/ScrapeController.php on line 52

line 52 指的是这一行:$goutteClient = new Client($guzzleclient);

这是我的课。如何强制它使用 Goutte 而不是 Symfony?

将行更改为:$goutteClient = new \Goutte\Client($guzzleclient); 不会修复它。

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Goutte\Client;
use GuzzleHttp\Cookie;
use GuzzleHttp\Client as GuzzleClient;

class ScrapeController extends Controller
{
    public function index()
    {
        return view(‘index’);
    }
    public function scrape() {
        $url = ‘www.domain.com;
        $domain = ‘www.domain.com’;


        $cookieJar = new \GuzzleHttp\Cookie\CookieJar(true);

        // get the cookie from www.domain.com
        $cookieJar->setCookie(new \GuzzleHttp\Cookie\SetCookie([
            'Domain'  => “www.domain.com”,
            'Name'    => ‘_name_session',
            'Value'   => ‘value’,
            'Discard' => true
        ]));
        $guzzleClient = new \GuzzleHttp\Client([
            'timeout' => 900,
            'verify' => false,
            'cookies' => $cookieJar
        ]);
        $goutteClient = new Client($guzzleClient);

        $crawler = $goutteClient->request('GET', $url);
        $crawler->filter('table')->filter('tr')->each(function ($node) {
            dump($node->text());
        });
    }
}

【问题讨论】:

    标签: laravel web-scraping goutte guzzle


    【解决方案1】:

    这是一个有趣的小观察,Gouette\Client 现在只是Symfony\Component\BrowserKit\HttpBrowser 的一个精简扩展,因此您可以基于此修改您的scrape 函数为:

    use Symfony\Component\BrowserKit\Cookie;
    use Symfony\Component\BrowserKit\CookieJar;
    use Symfony\Component\BrowserKit\HttpBrowser;
    use Symfony\Component\HttpClient\HttpClient;
    
    ...
    
    public function scrape() {
      $url = 'http://www.example.com/';
      $domain = 'www.example.com';
    
      $jar = new CookieJar();
      $jar->set(new Cookie('_name_session', 'value', null, null, $domain));
      $client = HttpClient::create([
        'timeout' => 900,
        'verify_peer' => false
      ]);
      $browser = new HttpBrowser($client, null, $jar);
    
      $crawler = $browser->request('GET', $url);
      $crawler->filter('div')->filter('h1')->each(function ($node) {
        dump($node->text());
      });
    }
    

    在您的composer.json 中,您需要有类似于以下内容的要求:

    "symfony/browser-kit": "^5.3",
    "symfony/css-selector": "^5.3",
    "symfony/http-client": "^5.3"
    

    但是fabpot/goutte 无论如何都需要它们,所以除了你已经拥有的库之外,不会下载任何库。

    【讨论】:

    • 哇,这是一个更好的解决方案!只是向我展示了一个空白屏幕。有什么想法吗?
    • 确保爬虫过滤器符合您的预期(例如 tabletr 而不是我的代码中的 divh1),并且 dump 也可以满足您的要求预计。如果您将其用作路由方法(类似于index),我认为您需要从scrape 返回正文?
    • 这很困难。绝对必须删除转储stackoverflow.com/a/53660016/10373009 只是澄清这适用于会话cookie?我正在尝试使用我自己的会话 cookie 抓取登录锁定页面
    • 可能有一些相关的事情,目标服务器可能会由于用户代理而有所不同,或者 cookie 可能会映射到目标服务器上的 IP 等等。你能发出请求吗从命令行使用 curl?如果是这样,请尝试在托管 Laravel 站点的服务器上重复以确认。至于会话 cookie,据我了解它应该可以工作,由于每个请求都会创建一个新的 jar,因此客户端上任何长期存在的 cookie 存储都会被丢弃。
    • 因此,在使用我当前的会话生成有效 cookie 并发出请求后,返回的 HTML 是来自“您必须登录才能查看此页面”的 HTML。就像你说的,也许它与每次刷新或请求页面时网站生成一个新的 cookie 有关。无论如何,我设法使用 HttpBrowser 手动填写和提交表单,而不是使用会话 cookie
    【解决方案2】:

    您不能将 GuzzleClient 传递给它,它不支持接受它。

    错误很明显,告诉您Goutte\Client 必须采用Symfony\Contracts\HttpClient\HttpClientInterfacenull 的实例;你不能给它GuzzleHttp\Client

    在 Symfony 客户端中处理 Cookie 需要遵循这一点; https://symfony.com/doc/current/http_client.html#cookies.

    【讨论】:

      猜你喜欢
      • 2021-02-10
      • 1970-01-01
      • 1970-01-01
      • 2012-09-20
      • 1970-01-01
      • 1970-01-01
      • 2013-09-09
      • 2014-10-17
      • 1970-01-01
      相关资源
      最近更新 更多