LINUX.ORG.RU

почему не определён экземпляр браузера?

 ,


0

1

есть скрипт, который парсит блог. блог состоит из списка статей и внутренних страниц. соответственно парсер имеет два уровня:

  1. парсинг списка страниц
  2. парсинг содержимого детальной страницы

на втором уровне у меня вываливается ошибка о том, что переменная browser равно undefined. поэтому

await browser.newPage();

для внутренних страниц не срабатывает. помогите пожалуйста понять что нужно исправить чтобы заработало.

const puppeteer = require('puppeteer');
const fs = require('fs');

let firstPageNum = null;
let lastPageNum = null;


const scrape = async () => {
	const allData = [];

    const browser = await puppeteer.launch();
    const page = await browser.newPage();			
    await page.goto('https://pycoder.ru/tags/?tag=python&page=1');

    const result_ = await page.evaluate(() => {
        const firstPageLink = parseInt(document.querySelector('.page-link:first-child').getAttribute('href').slice(-1), 10);
        const lastPageLink = parseInt(document.querySelectorAll('.page-link')[2].getAttribute('href').slice(-1), 10);
        return {
        	firstPageLink,
        	lastPageLink,
        }
    });

    firstPageNum = result_.firstPageLink;
    lastPageNum = result_.lastPageLink;
    browser.close();

    for(let pageNum = firstPageNum; pageNum <= lastPageNum; pageNum++) {
	    const browser = await puppeteer.launch({devtools: true});
	    const page = await browser.newPage();			
	    await page.goto('https://pycoder.ru/tags/?tag=python&page=' + pageNum);

	    const result = await page.evaluate(() => {
	        let data = [];
	        let elements = document.querySelectorAll('.post');

            debugger; 

	        elements.forEach(element => {
	            let linkDetails = element.querySelector('.post_link_next').getAttribute('href');

                let scrapeInerPage = async (linkDetails) => {
                    await browser.newPage();
                    await pageInner.goto(linkDetails);

                    title = element.querySelector('.blog-main h2').innerHTML;
                    date = element.querySelector('.blog-main p.meta').innerHTML;

                    pageInner.close(); 

                    return {
                        title: title,
                        date: date,
                    };                 
                }                

		    	scrapeInerPage(linkDetails).then(res => {
                    data.push('helloWorld');  
                    // data.push({pageInner.title, pageInner.date});
                    return data;
                }).catch(function (err) {
                     console.log("Promise Rejected", err);
                });       
	        });
	    });

	    allData.push(...result);
        // allData.push(...result);
	    // browser.close();
    }

	return allData;
};


scrape().then((results) => {
    console.log(results);
	fs.writeFile('./results.json', JSON.stringify(results), err => err ? console.log(err): null);    
}).catch(function (err) {
     console.log("Promise Rejected2", err);
}); 

кода много, но ошибка конкретно здесь:

                let scrapeInerPage = async (linkDetails) => {
                    await browser.newPage();
                    await pageInner.goto(linkDetails);


Последнее исправление: prozaik (всего исправлений: 2)

Я пользуюсь аналогом на Go github.com/chromedp/chromedp, в вашей портянке кажется подозрительным puppeteer.launch() в цикле. Зачем запускать браузер в цикле? Один раз в начале - и хватит.

anonymous
()
Ответ на: комментарий от anonymous

вы правы по-поводу запуска браузера в цикле. но это проблему не решило

prozaik
() автор топика

page.evaluate() принимает в качестве аргумента функцию, которая будет вычисляться в контексте страницы. В контексте страницы у тебя нет browser.

sjinks ★★★
()

Вместо page.evaluate() тебе нужноо что-то типа

const posts = await page.$$('.post');
const urls = [];
for (const post of posts) {
    const link = await post.$('.post_link_next');
    const href = await link.evaluate((e) => e.getAttribute('href'));
    urls.push(href);
}

В urls у тебя будут относительные пути:

[ '/azamon-interview-tasks/',
  '/monty-hall-problem/',
  '/vpython-sun-system-model/',
  '/how-i-failed/',
  '/unit-testing-with-mock-and-jsonschema/' ]

Из них делаешь абсолютные, и в цикле натравливаешь аналог scrapeIn(n)erPage.

Если тебе не хочется использовать puppeteer API, то в page.evaluate() можно использовать XMLHttpRequest для загрузки страниц (с xhr.responseType = ‘document’) и использовать DOM API над xhr.responseXML.

sjinks ★★★
()
Последнее исправление: sjinks (всего исправлений: 1)

И вообще, вместо puppeteer здесь бы больше подошел какой-нибудь request / node-fetch / … и cheerio.

sjinks ★★★
()
Ответ на: комментарий от sjinks

здесь бы больше подошел какой-нибудь request / node-fetch / … и cheerio.

у них есть какие-нибудь значительные преимущества перед puppeteer?

prozaik
() автор топика
Ответ на: комментарий от prozaik

Легковесность и нетребовательность к ресурсам. puppeteer — это целый Chrome впридачу, а по сути здесь нужно распарсить HTML без выполнения скриптов. Да, с puppeteer это можно сделать, но вот для данной задачи — это стрельба из пушки по воробьям.

sjinks ★★★
()
Ответ на: комментарий от sjinks

Его бота где-то банили, емнип, puppeteer решал проблему. А плодить 9000 кодовых баз на каждый случай жизни, не комильфо.

WitcherGeralt ★★
()
Последнее исправление: WitcherGeralt (всего исправлений: 1)

Я не у компа, нормально всмотреться не могу, но ты бы просто вынес браузер в глобальную область видимости и всё. Закрывай тоько в конце. У тебя же скрипт, он отрабатывает и мрёт.

WitcherGeralt ★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.