木偶找不到Xpath

时间:2019-12-21 21:01:33

标签: javascript jquery html xpath puppeteer

我正在尝试进行网页抓取,而我手把手放在一个看起来很容易抓取的网站上。但是,该网站具有许多具有相同ID的元素,这使得使用选择器变得很困难。

因此,我试图使用其完整的XPath获取元素。问题是,当我在网站上打开Chrome控制台并输入:

$x("/html/body/div[2]/div[4]/div/table[2]/tbody/tr/td[1]/div[1]/div[1]/table/tbody/tr[1]/td/table/tbody/tr[2]/td[2]")

有时可以,有时不能。我注意到它特别在检查元素之后起作用。我在其他线程上发现它可能与iframe有关,但是chrome控制台的iframe选择在它起作用或不起作用时似乎没有改变。

使用Puppeteer,此表达式始终返回一个空元素。这是我的代码的一部分:

const puppeteer = require('puppeteer');
const URL = "https://www.soccerstats.com/results.asp?league=england_2019&pmtype=bygameweek";
let browser = await puppeteer.launch(properties);

let page = await browser.newPage();
await page.goto(URL, {timeout: 60000, waitUntil: 'domcontentloaded'}).then(() => {
    console.log('success')
});

let match_xpath = "/html/body/div[2]/div[4]/div/table[2]/tbody/tr/td[1]/div[1]/div[1]/table/tbody/tr[1]/td/table/tbody/tr[2]/td[2]";
await page.waitForXPath(match_xpath);
let match = (await page.$x(match_xpath))[0];
let info = await page.evaluate((el) => {
                    return el.innerHTML
           }, match);
console.log(info) //This always returns 'undefined'

为什么会这样?如何获取元素的实际内容?

谢谢!

2 个答案:

答案 0 :(得分:1)

我认为您在操纵up脚本中的代码不会等待元素显示在浏览器(DOM)中。 因此,您可以设置waitUntil: 'networkidle0'以等待XHR(AJAX)请求完成并显示在浏览器中。

下面的这段代码仅刮取第一个表

const puppeteer = require('puppeteer')

const URL = 'https://www.soccerstats.com/results.asp?league=england_2019&pmtype=bygameweek'

;(async () => {

    const browser = await puppeteer.launch({
        headless : true,
        devtools : false
    })
    const [page] = await browser.pages()

    page.setDefaultNavigationTimeout(0)
    page.setRequestInterception(true)

    page.on('request', request => {
        if ( request.resourceType() === 'image' ) {
            request.abort()
        } else {
            request.continue()
        }
    })

    await page.goto(URL, {timeout: 0, waitUntil: 'networkidle0'})

    const teams = await page.evaluate( () => {

        const teams = []
        document.querySelectorAll('.tabbertab:not(.tabbertabhide):not(.tabbertabdefault)  #btable > tbody > tr:not(.even) > td:not([align])').forEach(item => teams.push(item.innerText.trim()) )
        return teams

    })

    console.log (teams)

    await browser.close ()

})()

如果您想让每个#btable内部的所有团队都可以使用此代码。

PS:我不使用xPath,因为它使用起来不容易,而且容易出错。

const puppeteer = require('puppeteer')

const URL = 'https://www.soccerstats.com/results.asp?league=england_2019&pmtype=bygameweek'

;(async () => {

    const browser = await puppeteer.launch({
        headless : true,
        devtools : false
    })
    const [page] = await browser.pages()

    page.setDefaultNavigationTimeout(0)
    page.setRequestInterception(true)

    page.on('request', request => {
        if ( request.resourceType() === 'image' ) {
            request.abort()
        } else {
            request.continue()
        }
    })

    await page.goto(URL, {timeout: 0, waitUntil: 'networkidle0'})

    const allRoundTeams = await page.evaluate( () => {

        var allRoundTeams = []

        document.querySelectorAll('#btable').forEach(item => {
            if (item.querySelector('tbody > tr > td > b') !== null) {

                var title = item.querySelector('tbody > tr > td > b').innerText.trim().replace(/(\r\n|\n|\r)/gm,"");

                var teams = []
                item.querySelectorAll('tbody > tr:not(.even) > td:not([align])').forEach(team => {
                    teams.push(team.innerText.trim())
                })
                allRoundTeams.push({
                    title : title,
                    teams : teams
                })
            }
        })

        return allRoundTeams

    })

    allRoundTeams.forEach(round => {
        console.log(round.title)
        console.log('========')
        round.teams.forEach(team => {
            console.log (team)
        })
        console.log('\n')
    })

    await browser.close ()

})()

答案 1 :(得分:0)

尝试将xpath表达式与您的代码一起使用;它应返回第1轮的日期,球队名称和得分,例如:

//div[2]//table[2]//td[1]/div[1]/div[1]/table[1]/tr[1]/td[1]