как получить доступ к страницам с помощью querystring с помощью запроса и узла.js

Я написал код для простого веб-скребка, используя Node.js и онлайн-учебник для сбора информации для BuzzFeed викторины. Это прекрасно работает для главной страницы ( https://www.buzzfeed.com/quizzes ) но когда я пытаюсь использовать его на любой из других страниц (т. е. https://www.buzzfeed.com/quizzes?page=4 ), я не получаю результатов. Я не уверен, что не так? Вот мой код:

var request = require('request');
var cheerio = require('cheerio');
var fs = require('fs');
var options = {
    method: 'GET',
    uri: 'https://www.buzzfeed.com/quizzes',
    qs: {
      page: 4
    }
}

request(options, function(error, response, html) {
    if(!error && response.statusCode == 200) {
      var $ = cheerio.load(html);

      $('div.card.js-feed-item').each(function( index ) { 
        var title = $(this).find('h2').text().trim();
        var link = $(this).find('a.link-gray').attr('href');
        var image = $(this).find('a.link-gray > div.js-progressive-image').attr('data-background-src');
        fs.appendFileSync('buzzfeed.txt', title + 'n' + link + 'n' + image + 'nn');
      });
}});

В основном, если я комментирую это:

qs: {
    page: 4
}

работает отлично. Я использую qs неправильно?

2 ответа

  1. Глядя на запрос, сделанный на странице, на самом деле вы можете просто выбросить этот URL : «https://www.buzzfeed.com/quizzes?render_template=0» , он дает вам json с 2 полями: карты ( массив информации ) и nextPage (что-то вроде /quizzes?render_template=0&page=2), вы просто можете использовать эти данные, я думаю, то же самое.

  2. Похоже, сервер BuzzFeed хочет отправить обратно сжатый ответ. Если вы посмотрите документацию для requestмодуля, вы можете найти эту опцию:

    gzip — Если true, добавьте Accept-Encodingзаголовок, чтобы запросить сжатые кодировки содержимого с сервера (если еще нет) и декодировать поддерживаемые кодировки содержимого в ответе.

    Так что в вашем случае просто просто добавление gzip: trueк вашему optionsобъекту должно работать. Будьте предупреждены, хотя, в зависимости от того, насколько страница полагается на JS, чтобы показать свое содержимое, HTML может быть не тем, что вы ожидаете.


    Как мне это удалось? Ну в основном, если вы исследуете возвращаемый responseобъект (вне ifоператора), вы можете получить довольно полезную информацию.

    Например, мы можем проверитьqs, работает ли параметр, проверяя url-адрес запроса с помощью response.request.url(илиresponse.request.href) и видя (через console.logили отладчик ), что он правильно сформировал строку запроса (?page=4), так что это не проблема.

    Копая дальше, мы можем увидеть, что response.statusCodeесть 500и response.body(или htmlпарам) есть {"message": "INTERNAL_ERROR"}. Это, кажется, указывает на «ошибку сервера», однако мы можем посетить страницу просто отлично в нашем браузере, так что на самом деле кажется, что серверу просто не нравится, как мы сформировали наш запрос по какой-то причине.

    В такие моменты стоит проверитьresponse.headers, где мы можем видеть, например, что content-typeесть application/json(что явно не то, что вы хотите). Но более интересно, что есть varyзаголовок, где одно из значений Accept-Encoding— это в основном говорит: «Если вы сделаете этот запрос снова с другим заголовком Accept-Encoding, вы получите другой ответ». Accept-Encoding почти всегда используется для указания типов сжатия, с которыми вы можете иметь дело, из которых gzip наиболее часто поддерживается серверами, поэтому gzip опция, предоставляемая модулем запроса узла. Если вы откроете вкладку Сеть Вашего браузера devtools и перейдите к URL, вы можете увидеть, что тот же заголовок устанавливается (в Chrome, фильтровать запросы «Doc», чтобы найти его легче).

    Edit: ваш исходный код, кажется, работает для меня сейчас, так что, возможно, это была проблема сервера в конце концов.