Веб-соскоб и обещания - PullRequest
0 голосов
/ 04 мая 2018

Я использую cheerio и node для просмотра веб-страниц, но у меня проблема с обещаниями. Я могу удалить список статей со страницы, но в этом списке у нас есть больше ссылок для отдельных страниц. Мне нужно также удалить отдельные страницы для каждого элемента в списке. Я покажу вам свой код для лучшего решения.

import rp from 'request-promise'
import cheerio from 'cheerio'
import conn from './connection'

const flexJob = `https://www.flexjobs.com`
const flexJobCategory = ['account-management', 'bilingual']

class WebScrapping {

    //list of article e.g for page 2
    results = [] // [[title], [link for page],...]
    contentPage = [] //content for each page

    scrapWeb(link) {
        let fullLink = `${link}/jobs/${flexJobCategory[1]}?page=2`
        const options = {
            uri: fullLink,
            transform(body) {
                return cheerio.load(body)
            }
        }
        rp(options)
            .then(($) => {
                console.log(fullLink)
                $('.featured-job').each((index, value) => {

                    //html nodes
                    let shortDescription = value.children[1].children[1].children[3].children[1].children[1].children[0].data
                    let link = value.children[1].children[1].children[1].children[1].children[1].children[0].attribs.href
                    let pageLink = flexJob + '' + link
                    let title = value.children[1].children[1].children[1].children[1].children[1].children[0].children[0].data
                    let place = value.children[1].children[1].children[1].children[1].children[3].children[1].data
                    let jobType = value.children[1].children[1].children[1].children[1].children[3].children[0].children[0].data
                    this.results.push([title, '', pageLink.replace(/\s/g, ''), '', shortDescription.replace(/\n/g, ''), place, jobType, 'PageContent::: '])
                })
            })
            .then(() => {
                this.results.forEach(element => {
                    console.log('link: ', element[2])
                    this.scrapPage(element[2])
                });
            })
            .then(() => {
                console.log('print content page', this.contentPage)
            })
            .then(() => {
                //this.insertIntoDB()
                console.log('insert into db')
            })
            .catch((err) => {
                console.log(err)
            })

    }

    /**
     * It's going to scrap all pages from list of jobs
     * @param {Any} pageLink 
     * @param {Number} count 
     */
    scrapPage(pageLink) {
        let $this = this
        //console.log('We are in ScrapPage' + pageLink + ': number' + count)
        //this.results[count].push('Hello' + count)
        let content = ''
        const options = {
            uri: pageLink,
            transform(body) {
                return cheerio.load(body)
            }
        }
        rp(options)
            .then(($) => {
                //this.contentPage.push('Hello' + ' : ');
                console.log('Heloo')
            })
            .catch((err) => {
                console.log(err)
            })
    }
    /**
     * This method is going to insert data into Database
    */
    insertIntoDB() {
        conn.connect((err) => {
            var sql = "INSERT INTO contact (title, department, link, salary, short_description, location, job_type, page_detail) VALUES ?"
            var values = this.results
            conn.query(sql, [values], function (err) {
                if (err) throw err
                conn.end()
            })
        })
    }
}
let webScrapping = new WebScrapping()
let scrapList =  webScrapping.scrapWeb(flexJob)

Итак, в методе scrapWeb, во втором «.then», я вызываю метод scrapPage, однако третье обещание было выполнено перед обещанием внутри метода scrapPage.

Ответы [ 2 ]

0 голосов
/ 04 мая 2018

У вас проблема с расой.

Первый трюк, который вам понадобится, - это scrapPage, возвращающий Promise.

scrapPage(pageLink) {
        let $this = this
        let content = ''
        const options = {
            uri: pageLink,
            transform(body) {
                return cheerio.load(body)
            }
        }
        return rp(options);
    }

Во втором случае вам нужно вызвать все дочерние страницы, например:

.then(() => {
return Promise.all(this.results.map(childPage => this.scrapPage(childPage)));
})

Это превратит все записки дочерних страниц в обещания, и только если все они разрешены, код будет выполняться.

0 голосов
/ 04 мая 2018

На этой стадии вам нужно немного больше контроля. Вы не хотите, чтобы обещание .then() разрешилось, пока не будут разрешены все вызовы.

Вы можете использовать библиотеку Promise, например bluebird , чтобы сделать Promise.each или Promise.map для всех результатов, которые вы хотите запустить.

Или используйте async / await для настройки как .then(async () => {}), а не используйте .forEach .

for(let element of this.results){
  console.log('link: ', element[2])
  await this.scrapPage(element[2])
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...