Node.js请求和Cheerio等待页面完全加载

5

我试图从一个网页上爬取图片,但如果该页面没有完全加载,页面会返回一个占位符源属性。 (需要大约0.5秒才能完全加载) 我该如何使请求等待?

我尝试了以下方法:

function findCommonMovies(movie, callback){

    request('http://www.imdb.com/find?ref_=nv_sr_fn&q='+ movie +'&s=all', function (error, response, body) {
      if (error){
          return
      }else{
          var $ = cheerio.load(body);
          var title = $(".result_text").first().text().split("(")[0].split(" ").join('')
          var commonMovies = []
          // var endurl = $("a[name=tt] .result_text a").attr("href")
          var endurl = $('a[name=tt]').parent().parent().find(".findSection .findList .findResult .result_text a").attr("href");


          request('http://www.imdb.com' + endurl, function (err, response, body) {

              if (err){
                  console.log(err)
              }else{

                  setInterval(function(){var $ = cheerio.load(body)}, 2000)

                  $(".rec_page .rec_item a img").each(function(){


                    var title = $(this).attr("title")
                    var image = $(this).attr("src")

                    commonMovies.push({title: title, image: image})
                  });
              }
              callback(commonMovies)
          });
      }
    });

}
findCommonMovies("Gotham", function(common){
  console.log(common)
})
4个回答

11

Cheerio不是一个网页浏览器。它只是一个HTML解析器。这意味着执行异步请求的JavaScript函数不会被执行。

所以,除非您使用类似于网页浏览器的东西,否则无法实现您想要的功能。例如,Selenium为许多网页浏览器添加了API接口。

您需要下载Selenium客户端,并在需要持续进行包含异步内容加载的请求时保持其运行。

此外,您需要一个基于您正在使用的语言和所需的webdriver的包装程序。Webdriver用于为不同的网页浏览器添加支持。

我假设您正在使用基于JS的NodeJS或类似的东西,所以,请看这里。

并确保查看API文档。

希望能对您有所帮助。

您也可以查看PhantomJS


1
你可以设置超时时间:
var options = {
    url : 'http://www.imdb.com/find?ref_=nv_sr_fn&q='+ movie +'&s=all',
    timeout: 10000 //set waiting time till 10 minutes.
  }
  request(options, function(err, response, body){
    if (err) {
      console.log(err);
    }
   //do what you want here
}

0

setTimeout(function, millseconds to wait) 可以暂停你想要的秒数。 setTimeout(function(){var $ = cheerio.load(body)}, 2000)


你等了2秒钟吗?你试过更长时间吗?这是唯一允许你暂停的JavaScript函数(除了setInterval)。你可以尝试声明一个函数:function cheerio (){ var $ = cheerio.load(body)},然后setTimeout(cheero, 2000)。也许它不喜欢匿名函数。 - Hunter
你能编辑并发布更多的代码吗?请求会立即发生。这里有一个XMLHttpRequest的例子:var xhr1 = new XMLHttpRequest(); xhr1.open('GET', "http://127.0.0.1:80/orgstart", true); xhr1.onreadystatechange = function() { if (this.status == 200 && this.readyState == 4) { if(this.responseText == '') { return;} };//end onreadystate xhr1.send(); - Hunter
好的,所以请注意setInterval会持续运行。在第二个请求中else开始的地方..做一个if语句,根据您所期望从响应体中获取的数据类型,所以如果(response != datayouwant) { setTimeout( yourfunction, 2000)} 如果没有找到想要的数据,则会等待2秒钟才能加载。您知道您想要的数据类型吗?为了编写正确的if语句。 - Hunter
1
我知道你是 SO 的新手。你会给我点赞吗,表示感谢我回答了你关于 setTimeout() 的问题? - Hunter
显示剩余9条评论

0

我觉得你的回调函数放错了位置,也不需要任何计时器。当request()调用它的回调函数时,整个响应已经准备好了,所以不需要计时器。

下面是回调函数在正确位置的代码,并且添加了一个错误参数,以便调用者可以传递和检测错误:

function findCommonMovies(movie, callback){
    request('http://www.imdb.com/find?ref_=nv_sr_fn&q='+ movie +'&s=all', function (error, response, body) {
      if (error) {
          callback(error);
          return;
      } else {
          var $ = cheerio.load(body);
          var title = $(".result_text").first().text().split("(")[0].split(" ").join('')
          var commonMovies = [];
          // var endurl = $("a[name=tt] .result_text a").attr("href")
          var endurl = $('a[name=tt]').parent().parent().find(".findSection .findList .findResult .result_text a").attr("href");
          request('http://www.imdb.com' + endurl, function (err, response, body) {
              if (err) {
                  console.log(err)
                  callback(err); 
              } else {
                  var $ = cheerio.load(body);
                  $(".rec_page .rec_item a img").each(function(){
                    var title = $(this).attr("title");
                    var image = $(this).attr("src");
                    commonMovies.push({title, image});
                  });
                  callback(null, commonMovies);
              }
          });
       }
    });
}

findCommonMovies("Gotham", function(err, common) {
  if (err) {
     console.log(err);
  } else {
     console.log(common)
  }
});

注意:这将仅访问您请求的URL所服务的HTML标记。如果这些页面具有由浏览器Javascript插入的内容,则该内容将不会出现在此处获取的内容中,也无法通过延迟使其出现。这是因为cheerio不运行浏览器Javascript,它只解析服务器最初发送的HTML。要运行浏览器Javascript,您需要比cheerio提供的更完整的浏览器引擎,例如PhantomJS,它将实际运行页面的Javascript。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接