javascript - 使用 Chrome/Chromium 使用 WWW::Mechanize::Chrome 从服务器获取 "raw"jss 和 css 代码

标签 javascript css perl

我正在尝试使用 WWW::Mechanize::Chrome 下载 css/js 文件。是的,还有其他获取文件的方法。但我的要求是使用 WWW::Mechanize::Chrome 完成。我想知道这是否可能。

我可以对 css 或 js 文件执行 $mech->get($url) 操作。然后它会显示在浏览器窗口中,然后我可以使用 $mech->content 获取它。问题是 HTML 实体被编码和解码会导致生成与原始文件不同的文件(我对此进行了测试)。这是js文件的问题。之后它们无法正常运行。

您可以运行此测试脚本以查看正在编码的文件。

use strict;
use warnings;
use WWW::Mechanize::Chrome;

my $mech =  WWW::Mechanize::Chrome->new();

$mech->get('https://www.nytimes.com/vi-assets/static-assets/vendor-454814a0340940dc9b42.js');
my $content = $mech->content;
use Data::Dumper qw(Dumper);
print Dumper $content;

我想知道是否有某种解决方法可以直接从服务器获取这些文件。同样,必须使用 WWW::Mechanize::Chrome

最佳答案

如果不出意外,您可以注入(inject)一个脚本来为您下载文件。

下面使用 Selenium::Chrome 演示了这种方法,但该方法可以适用于 WWW::Mechanize::Chrome。

use strict;
use warnings qw( all );

use FindBin             qw( $RealBin );    
use MIME::Base64        qw( decode_base64 );
use Selenium::Chrome    qw( );
use Time::HiRes         qw( sleep );
use Sub::ScopeFinalizer qw( scope_finalizer );

# nf = Non-fatal.
sub nf_find_element {
   my $web_driver = shift;
   my $node;
   if (!eval {
      $node = $web_driver->find_element(@_);
      return 1;  # No exception.
   }) {
      return undef if $@ =~ /Unable to locate element|An element could not be located on the page using the given search parameters/;
      die($@);
   }

   return $node;
}

sub nf_find_elements {
   my $web_driver = shift;
   my $nodes;
   if (!eval {
      $nodes = $web_driver->find_elements(@_);
      return 1;  # No exception.
   }) {
      return undef if $@ =~ /Unable to locate element|An element could not be located on the page using the given search parameters/;
      die($@);
   }

   return wantarray ? @$nodes : $nodes;
}

sub nf_find_child_element {
   my $web_driver = shift;
   my $node;
   if (!eval {
      $node = $web_driver->find_child_element(@_);
      return 1;  # No exception.
   }) {
      return undef if $@ =~ /Unable to locate element|An element could not be located on the page using the given search parameters/;
      die($@);
   }

   return $node;
}

sub nf_find_child_elements {
   my $web_driver = shift;
   my $nodes;
   if (!eval {
      $nodes = $web_driver->find_child_elements(@_);
      return 1;  # No exception.
   }) {
      return undef if $@ =~ /Unable to locate element|An element could not be located on the page using the given search parameters/;
      die($@);
   }

   return wantarray ? @$nodes : $nodes;
}

# Warning: This clears the log.
sub has_js_failed {
   my ($web_driver) = @_;
   my $log = $web_driver->get_log('browser');
   return 0+grep { no warnings qw( uninitialized ); $_->{level} eq 'SEVERE' && $_->{source} eq 'javascript' } @$log;
}

{
   my $js = <<'__EOS__';
      var array_buffer_to_base64 = function(buf) {
         let binary = '';
         let bytes = new Uint8Array(buf);
         for (let byte of bytes) {
            binary += String.fromCharCode(byte);
         }

         return btoa(binary);
      };

      var set_response = function(code, msg) {
         let code_node = document.createElement('input');
         code_node.setAttribute('type', 'hidden');
         code_node.setAttribute('name', 'code');
         code_node.setAttribute('value', code);

         let msg_node = document.createElement('input');
         msg_node.setAttribute('type', 'hidden');
         msg_node.setAttribute('name', 'msg');
         msg_node.setAttribute('value', msg);

         let form_node = document.createElement('form');
         form_node.setAttribute('id', 'exit');
         form_node.appendChild(code_node);
         form_node.appendChild(msg_node);

         document.body.appendChild(form_node);
      };

      var request = function(url) {
         fetch(url)
            .then(
               response => {
                  if (!response.ok)
                     throw new Error("HTTP error: " + response.status);

                  return response.arrayBuffer();
               }
            )
            .then(
               buffer => set_response("success", array_buffer_to_base64(buffer)),
               reason => set_response("error",   reason),
            );
      };

      request(...arguments);
__EOS__

   my $web_driver;
   my $guard = scope_finalizer {
      if ($web_driver) {
         $web_driver->shutdown_binary();
         $web_driver = undef;
      }
   };

   $web_driver = Selenium::Chrome->new(
      binary => "$RealBin/chromedriver.exe",
   );

   $web_driver->get('https://www.nytimes.com/');

   $web_driver->execute_script($js, 'https://www.nytimes.com/vi-assets/static-assets/vendor-454814a0340940dc9b42.js');

   my $exit_form_node;
   while (1) {
      if (has_js_failed($web_driver)) {
         die("JavaScript error detected.\n");
      }

      $exit_form_node = nf_find_element($web_driver, '/html/body/form[@id="exit"]')
         and last;

      sleep(0.250);
   }

   my $code = nf_find_child_element($web_driver, $exit_form_node, 'input[@name="code"]')->get_value();
   my $msg  = nf_find_child_element($web_driver, $exit_form_node, 'input[@name="msg"]')->get_value();

   if (!defined($code) || $code ne 'success') {
      $msg ||= "Unknown error";
      die("$msg\n");
   }

   my $doc = decode_base64($msg);

   binmode STDOUT;
   print $doc;
}

可能想在轮询循环中添加一个超时,以便在出现问题时不会永远等待。

关于javascript - 使用 Chrome/Chromium 使用 WWW::Mechanize::Chrome 从服务器获取 "raw"jss 和 css 代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55584210/

相关文章:

javascript - window.postMessage 不适用于从 iframe 到父文档

javascript - 模拟点击material-ui切换组件测试

html - 将鼠标悬停在一个 div 上使另一个消失

将从网页复制/捕获 html 内容并将其粘贴/显示在电子邮件中的 javascript 函数

regex - 使用数组时的 Perl 模式匹配

regex - perl 中正则表达式匹配的奇怪问题,替代尝试匹配

mysql - 修改FTP密码的脚本

javascript - 如何在 amCharts 上突出显示所选位置

javascript - 不支持语法

javascript - 反转所有元素的顺序