src/Service/Client/HeadlessUtils.php line 51

Open in your IDE?
  1. <?php
  2. namespace App\Service\Client;
  3. use App\Utils\StringUtils;
  4. use App\Utils\Utils;
  5. use Facebook\WebDriver\Chrome\ChromeOptions;
  6. use Facebook\WebDriver\Remote\DesiredCapabilities;
  7. use Symfony\Component\Panther\Client;
  8. /**
  9.  * See Experimental/src/Headless project
  10.  * https://github.com/sjitech/proxy-login-automator
  11.  */
  12. class HeadlessUtils
  13. {
  14.     const BROWSERLESS_IO 'https://4fa7d10a-0a31-405e-87f5-44b58636c682@chrome.browserless.io/webdriver';
  15.     /**
  16.      * Docker installation info in client.md
  17.      */
  18.     const BROWSERLESS_VPS5_WEBDRIVER 'http://madrid75008@51.38.44.123:3000/webdriver'//using selenium
  19.     const BROWSERLESS_VPS5_FN 'http://madrid75008@51.38.44.123:3000/function?ignoreHTTPSErrors'//or ?token=aaaaaa
  20.     /**
  21.      * This is using chrome headless on browserless server using selenium/chromedriver protocol
  22.      * @param $waitFor css selector of the element we are waiting to be displayed to get the DOM. Timeout 30s
  23.      * TODO handle post params
  24.      */
  25.     public static function fetchUsingPanther(string $url, ?array $postParams = [], ?string $waitFor nullbool $isRemote true):string {
  26.         if(count($postParams)) throw new \Exception('POST not implemented');
  27.         if ($isRemote) {
  28.             $client self::createRemoteClient();
  29.         } else {
  30.             // To display chrome, in test, add `PANTHER_NO_HEADLESS=1` in environement variables
  31.             $client Client::createChromeClient();
  32.         }
  33.         $crawler $client->request('GET'$url);
  34.         if ($waitFor)
  35.             $client->waitFor($waitFor); // Wait for an element to be rendered
  36.         $html $crawler->html();
  37. //        $client->takeScreenshot(__DIR__ . '/tmp_panther.png');
  38.         $client->quit(); //before $client->close(); don't know what the difference maybe if remote quit, if local close
  39.         return $html;
  40.     }
  41.     public static function createRemoteClient(): Client {
  42.         return Client::createSeleniumClient(self::BROWSERLESS_VPS5_WEBDRIVERDesiredCapabilities::chrome()
  43.             ->setCapability(ChromeOptions::CAPABILITY, (new ChromeOptions())
  44.                 ->addArguments(['headless''no-sandbox''ignore-certificate-errors'])
  45.             ));
  46.     }
  47.     /**
  48.      * This is using chrome headless on browserless server using directly js
  49.      */
  50.     public static function fetch(string $url, ?string $postQuerystring null, ?string $waitFor nullbool $isRemote true, ?string $proxyUrl null): string {
  51.         $html self::fetchCustom(__DIR__ '/headless_fetch.js', [
  52.             'purl' => $url,
  53.             'post' => $postQuerystring,
  54.             'waitFor' => $waitFor,
  55.         ], $isRemote$proxyUrl);
  56.         if (StringUtils::startsWith($html'Navigation timeout of') || StringUtils::startsWith($html'waiting for selector'))
  57.             throw new \RuntimeException('Browserless says: ' $html);
  58.         return $html;
  59.     }
  60.     // TODO handle when script when in different folder
  61.     /**
  62.      * @param string $pathScript "/foo/bar/fetch.js"
  63.      */
  64.     public static function fetchCustom(string $pathScript, array $params = [], bool $isRemote true, ?string $proxyUrl null) : string {
  65.         if(!file_exists($pathScript)) throw new \RuntimeException("File $pathScript not found");
  66.         if($isRemote) {
  67.             $proxyServer null;
  68.             if ($proxyUrl) {
  69.                 $parse parse_url($proxyUrl);
  70.                 if (isset($parse['user']) && isset($parse['pass'])) {
  71.                     $params['proxyAuth'] = [
  72.                         'username' => $parse['user'],
  73.                         'password' => $parse['pass'],
  74.                     ];
  75.                 }
  76.                 $proxyServer $parse['host'].(isset($parse['port'])?':'.$parse['port']:'');
  77.             }
  78.             // proxy : https://www.browserless.io/docs/chrome-flags#launching-with-a-proxy
  79.             $content ScraperUtil::curl([
  80.                 CURLOPT_URL => self::BROWSERLESS_VPS5_FN.($proxyServer '&--proxy-server='.$proxyServer ''),
  81.                 CURLOPT_POSTFIELDS => json_encode([
  82.                     'code' => file_get_contents($pathScript),
  83.                     'context' => $params,
  84.                 ]),
  85.                 CURLOPT_HTTPHEADER => [
  86.                     'Content-Type: application/json'
  87.                 ],
  88.                 CURLOPT_TIMEOUT => ScraperUtil::TIMEOUT_S 2,
  89.             ]);
  90.             return $content;
  91.         } else { //Proxy not handled when not remote
  92.             //--inspect to be able to inspect/debug with chrome tool or Phpstorm (Run/Debug config > Attach to Node.js/Chrome)
  93.             $str 'node --inspect '__DIR__."/headless_custom_runner.js \"$pathScript\" ";
  94.             foreach ($params as $k=>$v) {
  95.                 $str.="--$k=\"$v\" ";
  96.             }
  97.             return Utils::exec($str); //works when running local server with symfony server:run
  98.         }
  99.     }
  100. }