【问题标题】:Cannot get the text out of node by using XPath无法使用 XPath 将文本从节点中取出
【发布时间】:2021-07-17 09:55:14
【问题描述】:

我正在尝试使用 XPath 获取我在 Letterboxhd 上评分的最后一部电影/系列,然后将其打印出来。为了获得第一部电影,我在 HTML 中找到了这个:"<span class="frame-title">Magnolia (1999)</span>"。 获取第一部电影的评分:"<span class="rating -tiny -darker rated-6">★★★</span>" 我知道每次运行这段代码都会得到 3 颗星,所以我只写了一半。

这是我所做的:

let data = await page.evaluate(() => {

        let titles = document.evaluate("//span[contains(@class, 'frame-title')]", document, null, XPathResult.ANY_TYPE, null);
        let title = titles.iterateNext();

        let ratings = document.evaluate("//span[contains(@class, ' -tiny')]", document, null, XPathResult.ANY_TYPE, null);
        let rating = ratings.iterateNext(); 


        return{
            title,
            rating
        }
    });

当我运行此代码时,我看到“数据”未定义。我究竟做错了什么?我应该怎么做?

这是我的完整代码:

const puppeteer = require('puppeteer');

(async () => {

    let movieUrl = 'https://letterboxd.com/sdeer/films/';
    
    let browser = await puppeteer.launch({ headless: true });
    let page = await browser.newPage();

    await page.goto(movieUrl, { waitUntil: 'networkidle2'});

    let data = await page.evaluate(() => {

        let titles = document.evaluate("//span[contains(@class, 'frame-title')]", document, null, XPathResult.ANY_TYPE, null);
        let title = titles.iterateNext();

        let ratings = document.evaluate("//span[contains(@class, ' -tiny')]", document, null, XPathResult.ANY_TYPE, null);
        let rating = ratings.iterateNext(); 


        return{
            title,
            rating
        }
    });

    debugger

    console.log(data.title.textContent);
    console.log(data.rating.textContent);

    

    await browser.close();

})();

【问题讨论】:

    标签: javascript html web-scraping xpath


    【解决方案1】:

    就第一个和最后一个标题而言,我认为使用let lastTitle = document.evaluate('descendant::span[contains(@class, "frame-title")][last()]', document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue 是一种更好的方法,可以按文档顺序读出最后一个span,其类为frame-title

    尽管如此,网站看起来好像使用了分页,所以这会给你第一页上的最后一个标题。

    至于传递 DOM 节点,我认为您需要 page.evaluateHandle 而不是 page.evaluate

    我认为对于 evaluate 方法,您可以传递 JSON:

    let data = await page.evaluate(() => {
    
            let title = document.evaluate("//span[contains(@class, 'frame-title')]", document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue.textContent;
            
    
            let rating = document.evaluate("//span[contains(@class, ' -tiny')]", document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue.textContent;
    
    
            return {
                title,
                rating
            }
        });
    

    【讨论】:

    • 它似乎工作。谢谢!我只想再问一件事。它实际上获得了第二部最近的电影及其评级。我应该怎么做才能让它获得最新的电影?
    • 我想,如果我正确理解网站的结构,您想加载movieUrl = "https://letterboxd.com/sdeer/films/by/date/";(而不是movieUrl = 'https://letterboxd.com/sdeer/films/')以获取按审核订单而不是发布日期订购的项目。这似乎比尝试从 JavaScript 更改顺序更容易。
    猜你喜欢
    • 1970-01-01
    • 2016-01-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多