ОК, вот код, который показывает, как это сделать с помощью WMC.Еще раз спасибо @ikegami за идею и код, чтобы показать, как это можно сделать с помощью JavaScript, используя Selenimum, на котором основан этот код.Это гениальный маленький обходной путь.
Приведенный ниже код немного модифицирует его пример кода js, позволяя создавать несколько файлов, и добавляет элемент, который становится видимым, так что $ mech может обнаружить, когда данные готовы для его захвата иsave.
Шаг 0: добавьте необходимые пакеты Perl
use MIME::Base64;
use WWW::Mechanize::Chrome;
# etc.
Шаг 1: Создайте подпрограмму в Perl для вывода функций js:
sub js_here {
return <<'JS'
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, number) {
let code_node = document.createElement('input');
code_node.setAttribute('type', 'hidden');
code_node.setAttribute('id', 'code-' + number);
code_node.setAttribute('value', code);
let msg_node = document.createElement('input');
msg_node.setAttribute('type', 'hidden');
msg_node.setAttribute('id', 'msg-' + number);
msg_node.setAttribute('value', msg);
let vis_node = document.createElement('span');
vis_node.setAttribute('id', 'vis-' + number);
vis_node.setAttribute('value', '');
let form_node = document.createElement('form');
form_node.setAttribute('id', 'exit-' + number);
form_node.appendChild(code_node);
form_node.appendChild(msg_node);
form_node.appendChild(vis_node);
document.body.appendChild(form_node);
}
var request = function(url, number) {
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), number),
reason => set_response("error", reason),
);
};
JS
}
Шаг 2: Вставьте код в веб-страницу, уже загруженную mech, примерно следующим образом:
$mech->eval_in_page(js_here());
Шаг 3: Создайте подпрограмму Perl вызывающей стороны, которая будет вызывать js, вставленный на шаге 1.
sub js_download {
my ($url, $number) = @_;
return "request('$url', $number)";
}
Обратите внимание, что для этого нужны два аргумента.URL-адрес файла и произвольное число, идентифицирующее файл.
Шаг 4: Добавьте код для фактической загрузки и сохранения файлов.
Здесь он находится в цикле длязагрузка нескольких файлов:
my $count = 1;
foreach my $file (@files) {
$mech->clear_js_errors;
# throw contents of file into a hidden field on the web page
$mech->eval_in_page( js_download($file, $count));
# check for javascript errors
if ($mech->js_errors) {
warn "A javascript error encountered while fetching $file. Skipping file.\n";
foreach my $err ( $mech->js_errors() ) {
my $msg = $err->{message} || '';
warn "\t" . $msg . "\n";
}
++$count;
next;
}
# check for download errors
$mech->wait_until_visible(selector => "#vis-$count");
$mech->form_id( "exit-$count" );
my $ret_code = $mech->value("#code-$count", one => 1);
if ( $ret_code eq 'error' ) {
warn "Unable to download $file: \n";
warn $mech->value("#msg-$count") . "\n";
++$count;
next;
}
# get the file's content and save it to the directory
my $value = $mech->value("#msg-$count", one => 1);
my $content = decode_base64($value);
_save_file ($content, $file); # up to you how to implement
$count++;
}
Вот и все.