Можно ли прервать HTTP-запрос в зависимости от «Content-Type» при использовании Perl LWP?

Я хочу, чтобы мой скрипт загружал только текстовый/html-контент, а не двоичный файл или изображения, загрузка которых может занять значительно больше времени. Я знаю о параметре max_size, но я хотел бы добавить проверку заголовка Content-Type. Это выполнимо?


person mbonnin    schedule 30.07.2012    source источник


Ответы (3)


Как указывали другие, вы можете выполнить запрос HEAD перед вашим запросом GET. Вы должны сделать это как способ быть вежливым с сервером, потому что на самом деле вам легко разорвать соединение, но не обязательно легко для веб-сервера прервать отправку набора данных и выполнить кучу работы на его конце. .

Есть несколько разных способов сделать это в зависимости от того, насколько изощренным вы хотите быть.

  1. Вы можете отправить заголовок Accept с вашим запросом, в котором перечислены только text/html. Хорошо реализованный HTTP-сервер вернет статус 406 Not Acceptable, если вы скажете, что не принимаете файл, каким бы он ни был. Конечно, они могут отправить его вам в любом случае. Вы также можете сделать это как свой HEAD запрос.

  2. При использовании последней версии LWP::UserAgent можно использовать подпрограмму-обработчик для прерывания остальная часть запроса после заголовков и перед телом содержимого.

    use LWP::UserAgent;
    use Try::Tiny; 
    
    my $ua = LWP::UserAgent->new;
    $ua->add_handler( response_header => sub {
        my($response, $ua, $h) = @_;
    
        die "Not HTML" unless $response->content_type eq 'text/html';
    });
    
    my $url = "http://example.com/foo";
    
    my $html;
    my $head_response = $ua->head($url, Accept => "text/html");
    if ($head_response->is_success) {
        my $get_response = $ua->get($url, Accept => "text/html");
        if ($get_response->is_success) {
            $html = $get_response->content;
        }
    } 
    

Подробнее об обработчиках см. в разделе Обработчики документации LWP::UserAgent.

Я не поймал выброшенное исключение и не позаботился о том, чтобы тщательно обработать ответы 406 здесь. Я оставляю это в качестве упражнения для читателя.

person zostay    schedule 30.07.2012
comment
Я полагаю, что некоторые серверы также могут отправить вам содержимое файла по запросу HEAD. Возможно, вам также потребуется проверить ответы 405 Method Not Allowed на запрос HEAD и посмотреть, сможете ли вы в любом случае отправить запрос GET, если HEAD не сработает с этим ответом. - person zostay; 30.07.2012
comment
HEAD ненадежен, и мне кажется, что все, что правильно обрабатывает запрос HEAD, также будет правильно обрабатывать заголовок Accept. Я бы пропустил запрос HEAD и использовал только два других механизма (Accept и обратный вызов). - person ikegami; 30.07.2012
comment
Функция add_handler() делает именно то, что я искал. Спасибо ! - person mbonnin; 30.07.2012

Вы можете использовать запрос HEAD для запроса информации заголовка URI. Если сервер отвечает на головы, вы получите все, что вернул бы GET, за исключением этого надоедливого тела.

Затем вы можете решить, что делать, основываясь на типе MIME.

в противном случае вам придется полагаться на расширение файла, прежде чем запрашивать его.

person Len Jaffe    schedule 30.07.2012
comment
Это действительно будет работать, но немного неоптимально, так как удваивает количество запросов в номинальном случае. Я получаю очень мало бинарных ссылок, поэтому я бы предпочел прервать их, а не добавлять тест для каждой ссылки. - person mbonnin; 30.07.2012
comment
Итак, почему вы не можете определить тип файла по расширению файла до выдачи GET? - person Len Jaffe; 30.07.2012
comment
ну... у меня есть несколько случаев, когда нет ни одного расширения. Особенно скрипты cgi, которые отправляют двоичные данные... Так что это не очень надежно. - person mbonnin; 30.07.2012
comment
Вы не можете сказать по тегу, откуда пришел URI? - person Len Jaffe; 30.07.2012
comment
какой тег? То, что я делаю, — это бот, который исследует содержимое веб-страниц, с которыми сталкивается. У меня нет контроля над тем, в какие ссылки он может попасть. - person mbonnin; 30.07.2012
comment
Обычно вы можете отличить изображения от ссылок ( ‹IMG› против ‹A› ). - person Len Jaffe; 30.07.2012
comment
да, но ссылки вырваны из контекста, поэтому у меня нет ‹img› или ‹a›. Во всяком случае, add_handler() работает нормально :-) - person mbonnin; 30.07.2012

Если вы используете минимальный LWP::Simple подкласс LWP, то функция head возвращает тип контента в качестве первого элемента списка.

Итак, вы можете написать

use strict;
use warnings;

use LWP::Simple;

for my $url ('http://www.bbc.co.uk') {
  my ($ctype) = head $url;
  my $content = get $url if $ctype eq 'text/html';
}
person Borodin    schedule 30.07.2012