Node.js网页抓取问题| 请求| cheerio

我正在使用Node.js和请求模块和cheerio模块写一个相当简单的networking抓取工具。 我的代码不工作,因为我想要它有两个原因:

  1. 当试图抓取图像的url时,我只是多次为每个页面返回一个单一的url。
  2. 每个“href”和“title”的迭代都是以一个看起来随机的顺序进行的(每次都是相同的顺序,但是依然不是,例如1,2,3等)

这是我的代码:

var request = require('request'), cheerio = require('cheerio'); var sqlite3 = require('sqlite3').verbose(); var database = "storage.db" console.log('[+] Creating database: ' + database); var db = new sqlite3.Database(database); var pw_url = "https://primewire.unblocked.ink" console.log('[+] Creating table with rows...'); db.serialize(function() { db.run("CREATE TABLE IF NOT EXISTS main (title TEXT, film_page_links TEXT, img_url TEXT)"); }); var img_urls = {} function iter_pages(page_number) { request(pw_url + '/index.php?sort=featured&page=' + page_number, function(err, resp, body) { if(!err && resp.statusCode == 200) { console.log('[+] The request response status code is: ' + resp.statusCode); var $ = cheerio.load(body); console.log('[+] Inserting values into database.'); $('.index_item a img', '.index_container').each(function() { img_urls.img_url = $(this).attr('src'); }); $('.index_item a', '.index_container').each(function() { var url = $(this).attr('href'); var title = $(this).attr('title'); if(url.startsWith('/watch-')) { //urls.push('https://primewire.unblocked.ink' + url); db.run("INSERT INTO main (title, film_page_links, img_url) VALUES (?, ?, ?)", title.replace("Watch ", ""), pw_url + url, "https:" + img_urls.img_url); }; }); console.log('[+] Processed page:' + page_number); } }); } for (var i = 1; i < 5; i++) { iter_pages(i); } 

这是我的console.log:

 [+] Creating database: storage.db [+] Creating table with rows... [+] The request response status code is: 200 [+] Inserting values into database. [+] Processed page:4 [+] The request response status code is: 200 [+] Inserting values into database. [+] Processed page:1 [+] The request response status code is: 200 [+] Inserting values into database. [+] Processed page:3 [+] The request response status code is: 200 [+] Inserting values into database. [+] Processed page:2 

正如你可以看到,它依次是4,1,3,2,这使我困惑。

它返回的图像url始终是每个页面的第21项。

我是新来的JavaScript,所以请亲切,我已经试图移动的方法获取图像url周围的iter_pages函数,要么破坏代码或返回相同的东西。

即使是一个更高级的教程的链接就足够了,我学习的东西很快,但问题是我发现的所有教程只是非常基本的技术。

第一个问题:

这是你如何设置图像url: img_urls.img_url = ...

发生的事情是,每当你设置,你把它放在同一个属性,并覆盖那里,这就是为什么它总是从页面的最后一个。 你可以尝试通过推入一个数组来解决这个问题,但是由于你有两个循环,这使得事情变得更加复杂,而不是试图在同一个循环中完成:

  $('.index_item a', '.index_container').each(function() { var url = $(this).attr('href'); var title = $(this).attr('title'); var img_url = $('img', this).attr('src'); if(url.startsWith('/watch-')) { //urls.push('https://primewire.unblocked.ink' + url); db.run("INSERT INTO main (title, film_page_links, img_url) VALUES (?, ?, ?)", title.replace("Watch ", ""), pw_url + url, "https:" + img_url); }; }); 

第二个问题:

你必须实现几件事情。 request(...)正在发出asynchronousnetworking请求。 这意味着这个function马上结束,结果还没到。 因此,循环继续进行,所有的networking请求同时开始,但是由于许多不同的variables和运气,一些networking请求在不同的时间完成。 有些可能会更快,有些更慢。 由于他们几乎同时开始,他们开始的顺序并不重要。 这是你简化的问题:

 const request = require('request'); for (let i = 0; i < 5; i++) { makeRequest(i); } function makeRequest(i) { console.log('Starting', i); console.time(i); request('http://google.com', () => console.timeEnd(i)); } 

这里是日志:

 $ node a.js Starting 0 Starting 1 Starting 2 Starting 3 Starting 4 1: 8176.111ms 2: 8176.445ms 3: 8206.300ms 0: 8597.458ms 4: 9112.237ms 

再次运行产生这个:

 $ node a.js Starting 0 Starting 1 Starting 2 Starting 3 Starting 4 3: 8255.378ms 1: 8260.633ms 2: 8259.134ms 0: 8268.859ms 4: 9230.929ms 

所以你可以看到订单是不确定的。 只有一些完成比其他人快。

如果你真的希望它们按顺序发生,我build议使用一个控制stream程库。 async.js是最stream行的之一。