Поиск в медиавики

Есть ли какой-либо API или другой способ с помощью Javascript для поиска любой медиавики и печати найденной страницы (и, если она не найдена, распечатайте ее).

Я бы предпочел что-то вроде этого:

function searchWiki(wikipage, search) {
    //the function here
    document.write(foundPage);
}

//run it

searchWiki('https://en.wikipedia.org', 'banana');

//it would print 'https://en.wikipedia.org/wiki/Banana'

person PMint    schedule 10.11.2013    source источник
comment
Посетите mediawiki.org/wiki/Api и, в частности, mediawiki.org/wiki/API:Search   -  person IMSoP    schedule 10.11.2013


Ответы (1)


Вот моя реализация такой функции. Он использует MediaWiki API через JSONP и является достаточно гибким. Я думаю, что решение jQuery в порядке. Я создал маленькую скрипку.

searchWiki(сайт, поиск, [обратный вызов], [параметры])

function searchWiki(site, search, callback, opts) {
    if(typeof callback == 'object') {
        opts = callback;
        callback = null;
    } else {
        opts = opts || {};
    }
    // Build the required URLs
    var siteUrl = (opts.ssl ? 'https' : 'http') + '://' + site;
    var apiUrl = siteUrl + (opts.apiBase || '/w/') + 'api.php';
    var queryUrl = apiUrl + '?action=query&list=search&srsearch=' + encodeURIComponent(search) + '&srlimit=' + (opts.maxResults || 1) + '&format=json';
    // Issue the JSONP request
    $.ajax(queryUrl + '&callback=?', {
        dataType: 'jsonp',
        // This prevents warnings about the unrecognized parameter "_"
        cache: true,
        success: function(data) {
            // Get all returned pages
            var titles = [], links = [];
            for(var i = 0; i < data.query.search.length; i++) {
                var title = data.query.search[i].title,
                    link = siteUrl + (opts.wikiBase || '/wiki/') + encodeURIComponent(title);
                titles.push(title);
                links.push(link);
            }
            if(!opts.maxResults) {
                // Single result requested
                if(data.query.search.length == 0) {
                    titles = links = null;
                } else {
                    titles = titles[0];
                    links = links[0];
                }
            }
            // Call the callback
            (callback || opts.success || function(){})(titles, links);
        }
    });
}

Пример 1. Поиск в одной Википедии

searchWiki('en.wikipedia.org', 'banana fruit', {
    ssl: true,
    success: function(title, link) {
        // link is now "https://en.wikipedia.org/wiki/Banana"
        if(title === null) {
            $('#search-msg').text('Not found');
        } else {
            var anchor = $('<a>').text(title).attr('href', link);
            $('#search-msg').append(anchor);
        }
    }
});

В этом примере показана ссылка на страницу википедии с соответствующим заголовком.

Пример 2. Несколько результатов

searchWiki('www.mediawiki.org', 'Release notes', {
    ssl: true,
    maxResults: 5,
    success: function(titles, links) {
        for(var i = 0; i < titles.length; i++) {
            alert('MediaWiki ' + titles[i] + ' at ' + links[i]);
        }
    }
});

В этом примере отображается до пяти ссылок на страницы MediaWiki, соответствующие запросу «Примечания к выпуску».

Параметры:

  • ssl: Используйте HTTPS вместо HTTP
  • maxResults: вернуть несколько (до n) результатов
  • apiBase: каталог API на целевом сайте (по умолчанию /w/)
  • wikiBase: Каталог Wiki на целевом сайте (по умолчанию /wiki/)
  • success: Функция для вызова после получения списка результатов

Вы можете передать обратный вызов как аргумент функции (перед параметрами) или как параметр success.


Обновление: вот чистое решение JS (jQuery не требуется). И еще одна скрипка, на этот раз без jQuery.

function searchWiki(site, search, callback, opts) {
    if(typeof callback == 'object') {
        opts = callback;
        callback = null;
    } else {
        opts = opts || {};
    }
    // Build the required URLs
    var siteUrl = (opts.ssl ? 'https' : 'http') + '://' + site;
    var apiUrl = siteUrl + (opts.apiBase || '/w/') + 'api.php';
    var queryUrl = apiUrl + '?action=query&list=search&srsearch=' + encodeURIComponent(search) + '&srlimit=' + (opts.maxResults || 1) + '&format=json';
    var fnName = '_cb_' + Math.floor(Math.random() * 4294967296);
    window[fnName] = function(data) {
        // Clear references to this function
        window[fnName] = null;
        // Get all returned pages
        var titles = [], links = [];
        for(var i = 0; i < data.query.search.length; i++) {
            var title = data.query.search[i].title,
                link = siteUrl + (opts.wikiBase || '/wiki/') + encodeURIComponent(title);
            titles.push(title);
            links.push(link);
        }
        if(!opts.maxResults) {
            // Single result requested
            if(data.query.search.length == 0) {
                titles = links = null;
            } else {
                titles = titles[0];
                links = links[0];
            }
        }
        // Call the callback
        (callback || opts.success || function(){})(titles, links);
    }
    // Issue the JSONP request
    var scriptTag = document.createElement('script');
    scriptTag.setAttribute('src', queryUrl + '&callback=' + fnName);
    document.head.appendChild(scriptTag);
}

Обновление 2: наконец-то найдено решение для node.js. API остается прежним, но предоставляет несколько дополнительных опций:

  • error: Обратный вызов ошибки (это было невозможно в браузерном JS)
  • userAgent: Пользовательская строка агента пользователя, предложенная в документации
  • port: целевой порт (по умолчанию 80/443)
  • encoding: Кодировка ответа (по умолчанию utf8)

Я особо не тестировал, но примеры (см. выше) все равно должны работать.

var http = require('http'),
    https = require('https');

function searchWiki(site, search, callback, opts) {
    if(typeof callback == 'object') {
        opts = callback;
        callback = null;
    } else {
        opts = opts || {};
    }
    // Build the required paths
    var apiPath = (opts.apiBase || '/w/') + 'api.php';
    var queryPath = apiPath + '?action=query&list=search&srsearch=' + encodeURIComponent(search) + '&srlimit=' + (opts.maxResults || 1) + '&format=json';
    // Request options
    var httpOpts = {
        hostname: site,
        port: (opts.port ? opts.port : (opts.ssl ? 443 : 80)),
        method: 'GET',
        path: queryPath,
        agent: false
    };
    // Custom user agent
    if(opts.userAgent) {
        httpOpts.headers = {
            'User-Agent': opts.userAgent
        };
    }
    // Make the request
    var req = (opts.ssl ? https : http).request(httpOpts, function(res) {
        var msgBody = '';
        res.setEncoding(opts.encoding || 'utf8');

        res.on('data', function(chunk) {
            msgBody += chunk;
        });

        res.on('end', function() {
            // Parse response as JSON
            var data;
            try {
                data = JSON.parse(msgBody);
            } catch(err) {
                (opts.error || function(){})(err);
                return;
            }
            // Get all returned pages
            var siteUrl = (opts.ssl ? 'https' : 'http') + '://' + site;
            var titles = [], links = [];
            for(var i = 0; i < data.query.search.length; i++) {
                var title = data.query.search[i].title,
                    link = siteUrl + (opts.wikiBase || '/wiki/') + encodeURIComponent(title);
                titles.push(title);
                links.push(link);
            }
            if(!opts.maxResults) {
                // Single result requested
                if(data.query.search.length == 0) {
                    titles = links = null;
                } else {
                    titles = titles[0];
                    links = links[0];
                }
            }
            // Call the callback
            (callback || opts.success || function(){})(titles, links);
        });
    });
    req.on('error', function(err) {
        (opts.error || function(){})(err);
    });
    req.end();
}
person Tobias    schedule 13.11.2013
comment
Я не должен использовать JQuery, но он выглядит именно так, как я этого хочу, поэтому, возможно, я тоже могу попробовать использовать JQuery, хотя я этого не планировал. - person PMint; 14.11.2013
comment
@PMint Я переписал некоторые части функции, чтобы они работали без jQuery. Он по-прежнему обеспечивает ту же функциональность, что и раньше. - person Tobias; 14.11.2013
comment
Это работает, но есть ли способ заставить это работать с Node.js? Ajax не работает с пакетом jquery, и окно тоже не работает, потому что это Node.js. Я приму ваш ответ, поскольку я не упомянул Node.js, но это то, к чему я действительно стремлюсь. - person PMint; 14.11.2013
comment
@PMint Я знаком с node.js. Я еще раз переписал функцию для использования с node. Этот вариант не очень красивый, но он должен работать. - person Tobias; 14.11.2013
comment
Не сработало, я добавил журналы консоли в определенные моменты, он записал один в // Parse response as JSON, но не в // Get all returned pages. - person PMint; 14.11.2013
comment
@PMint Попробуйте установить обратный вызов ошибки (опция error) и посмотрите, вызывается ли он: error: function(err) { console.log(err); }. Какой сайт/запрос/параметры вы прошли? - person Tobias; 14.11.2013
comment
Вот варианты: pastebin.com/6sH9bNsf bot.say работает правильно, как и msg[1 ], Я проверил это хорошо. Ошибка была SyntaxError: Unexpected token <. - person PMint; 14.11.2013
comment
Я выяснил, что у нашей вики есть API на .com/api.php без /w/, поэтому я установил apiBase: '',, но ошибка все равно появлялась. - person PMint; 14.11.2013
comment
@PMint Возможно, вы захотите использовать параметр apiBase: '/', чтобы сохранить значение по умолчанию. Рад, что помог. - person Tobias; 14.11.2013