Как заменить ISBN идентификатором Google Книг в файле MARC с помощью Perl?

У меня есть файл с некоторыми данными о книгах в формате MARC, в котором некоторые строки ISBN. Я хочу заменить эти строки идентификатором Google Книг этого ISBN, если он существует. Вот код до сих пор, который просто удаляет строки:

perl -pe "s#ISBN(.*)#$(wget --output-document=- --quiet --user-agent=Mozilla/5.0 \"http://books.google.com/books?jscmd=viewapi&bibkeys=\1\")#mg" < 5-${file} > 6-${file}

PS: Google немного нечетко использует автоматизированные инструменты: Books Data API рекомендует такие инструменты, как curl/wget, но нет инструкций, как избежать блокировки при использовании таких инструментов. Я также почти уверен, что видел пункт в ToS, в котором говорится, что пользователи не могут отправлять автоматические запросы, но я не могу найти его снова. Это обсуждается на их форуме.


person l0b0    schedule 03.11.2009    source источник
comment
Вы настаиваете на однострочнике для этой работы?   -  person innaM    schedule 03.11.2009
comment
Не совсем - я понял, что \1 не заменяется до тех пор, пока команда не будет запущена, поэтому этот подход не работает. Создание Perl-скрипта сейчас.   -  person l0b0    schedule 03.11.2009
comment
рассмотрите возможность использования чего-то вроде LWP::Simple вместо вызова wget.   -  person innaM    schedule 03.11.2009
comment
Как будет выглядеть результирующая строка вашего вывода? Из URL-адреса, который вы используете, я получаю фрагмент кода JavaScript. Ты хочешь всего этого?   -  person brian d foy    schedule 03.11.2009


Ответы (2)


Я думаю, что OP находится на правильном пути и может использовать для этого однострочный код, и ему просто нужно заменить некоторый синтаксис в стиле bash правильным синтаксисом Perl. Я думаю, что это сработает (для удобства чтения добавлены новые строки):

    perl -pe 's#ISBN(\w+)#qx(wget --output-document=- 
        --quiet --user-agent=Mozilla/5.0 
        "http://books.google.com/books\\?jscmd=viewapi\\&bibkeys=$1")#ge' \
        < 5-${file} > 6-${file}

Вы должны экранировать (редактировать: двойное экранирование, похоже, работает) символы $ или & в URL-адресе.

person mob    schedule 03.11.2009
comment
Я думаю, что использование поддельного пользовательского агента является нарушением TOS Google. Без него: HTTP/1.0 401 Unauthorized. - person Sinan Ünür; 03.11.2009
comment
Это заменяет ISBN большим куском JavaScript, не так ли? Я пропустил какую-то магию или что-то в этом роде? - person brian d foy; 03.11.2009

Причина, по которой вам приходится лгать о пользовательском агенте, заключается в том, что вы нарушаете TOS Google: не делайте этого.

Вместо этого используйте API Поиска книг Google.

Приведенному ниже коду немного мешает мое незнание таких модулей, как XML::Atom, Data::Feed, WWW::OpenSearch. Тем не менее, он должен стать хорошей отправной точкой.

#!/usr/bin/perl

use strict;
use warnings;

use Business::ISBN qw( valid_isbn_checksum );
use LWP::Simple;
use XML::Simple;

while ( <> ) {
    s/ISBN:([0-9]+)/'Google Books ID:' . get_google_id_for_isbn($1)/ge;
    print;
}

use Carp;

sub make_google_books_query {
    sprintf 'http://books.google.com/books/feeds/volumes?q=isbn:%s', $_[0];
}

sub get_google_id_for_isbn {
    my ($isbn) = @_;

    my $google_id = eval {
        defined(valid_isbn_checksum $isbn)
            or croak "Invalid ISBN: $isbn";

        my $query = make_google_books_query($isbn);
        my $xml = get $query;

        defined($xml)
            or croak "No response to <$query>";

        my $data = XMLin($xml, ForceArray => 1);
        my @ids = @{ $data->{entry}[0]{'dc:identifier'} };

        unless ("ISBN:$isbn" eq $ids[1]
                or "ISBN:$isbn" eq $ids[2] ) {
            croak "Invalid search results: '@ids'";
        }

        $ids[0];
    };

    defined($google_id) ? $google_id : '';
}

Дан текстовый файл t.txt, содержащий:

ISBN:0060930314
ISBN:9780596520106

он выводит:

Google Books ID:ioXFqlzsmK8C
Google Books ID:lNVHi3TunxsC
person Sinan Ünür    schedule 03.11.2009
comment
Также см. мой модуль Business::ISBN, если вы хотите проверить входящие номера ISBN. Google возвращает результаты даже при неверном вводе. Вы также можете захотеть обернуть eval вокруг @{ ... } в случае отсутствия записи. - person brian d foy; 03.11.2009