How to load and parse whole content of a dynamic page that use infinity scroll

别等时光非礼了梦想. 提交于 2021-01-27 21:12:40

问题


I am trying to solve my problems making searches, reading documentations.

The problem

I want to get all youtube titles from an youtube channel using python beautiful soup. Youtube loads dynamically, i think with JavaScript, without pyqt5 I just can not get any title, So i used the pyqt5 I was able to get titles from youtube channel. The problem is that i need to load all the videos. I can just load the 29 ou 30 first ones. I am thinking on simulating a scroll down or somthing like that. I can not find how to do this on beatiful soup without selenium...

Version and libraries used:

  • Python 3.7.4
  • BeautifulSoup4
  • riverbankcomputing.com

I am trying not using selenium or scrapy

  • I want to understand what i can and what i can not do with BeautifulSoup on dynamic pages.

The code

from bs4 import BeautifulSoup
import sys
import urllib.request
from PyQt5.QtWebEngineWidgets import QWebEnginePage
from PyQt5.QtWidgets import QApplication
from PyQt5.QtCore import QUrl


class Page(QWebEnginePage):
    def __init__(self, url):
        self.app = QApplication(sys.argv)
        QWebEnginePage.__init__(self)
        self.html = ''
        self.loadFinished.connect(self._on_load_finished)
        self.load(QUrl(url))
        self.app.exec_()

    def _on_load_finished(self):
        self.html = self.toHtml(self.Callable)
        print('Load finished')

    def Callable(self, html_str):
        self.html = html_str
        self.app.quit()


def main():
    page = Page(
        'https://www.youtube.com/channel/UCY50YjnaeI7ezvRagFWeWmw/videos')
    soup = BeautifulSoup(page.html, 'html.parser')
    what_i_search = soup.find('div', class_='style-scope ytd-grid-renderer')
    youtube_titles = what_i_search.find_all('h3')
    line = 0
    for youtube_title in youtube_titles:
        line = line + 1
        print(str(line) + ". " + youtube_title.text)


if __name__ == '__main__':
    main()

Output:

Load finished
1. Plants vs Zombies 2 - FUTURO DISTANTE - dias 09, 10, 11 e 12 - Parte 48
2. Marisa ou M�nica - Turma da M�nica
3. Jogo PET DOLL - Parte 02
4. A Magali n�o mora mais aqui - Turma da M�nica
5. MOY'S WORLD (parte 03) - Mundo 01 - N�vel 6 - Gameplay
6. M�nica e Cebolinha em "uma pedra no meio do caminho" - Turma da M�nica
7. Plants vs Zombies 2 - FUTURO DISTANTE - dia 08 e Terror do Amanh� - Parte 47
8. Magali em "N�o Sou Boneca" - Turma da M�nica
9. Talking Tom HERO DASH - Terminamos todas os mundos!!! - Parte 13
10. M�nica em Maternidade Saud�vel - Turma da M�nica
11. Rotina Matinal da Beb� Reborn da Luisa - Cuidando da boneca
12. Bloop Go! Jogo/Game - Parte 1
13. Chico Bento em "se n�o fosse a fei�ra" - Turma da M�nica
14. Luisa cuidando do gatinho BUBBU - parte 3
15. Turma da M�nica em "as tr�s letrinhas" - Feliz dia das m�es!!!
16. Plants vs Zombies 2 - FUTURO DISTANTE - dias 05, 06 e 07 - Parte 46
17. A Turma em "fregu�s tem sempre raz�o" - Turma da M�nica
18. Dollify - parte 4 - Brincando de fazer caricaturas! Fazendo o boneco da prima Julia
19. Casc�o em "o maior bode" - Turma da M�nica
20. Jogo Hotel Transilv�nia Adventures - parte 12 - Terminamos a COZINHA - Fases 55 e 56
21. Turma do Penadinho em "sexta-feira 14" - Turma da M�nica
22. Plants vs Zombies 2 - iniciamos FUTURO DISTANTE - dias 01, 02, 03 e 04 - Parte 45
23. Chico Bento e o Nome - Turma da M�nica
24. Talking Angela - Jogando com a Gatinha Angela - N�vel 20 (parte 9)
25. Magali e a Turma em "OS ADOLESCENTES" - Turma da M�nica
26. Cortando o cabelo (franjinha) da Luisa em casa! #m�eefilha
27. Jogo Gardenscapes - Parte 11 - Cuidando do Jardim e do Tot� - N�vel 48
28. Cebolinha em "a caveira dentu�a" - Turma da M�nica
29. Plants vs Zombies 2 - TERMINAMOS A CIDADE PERDIDA - dias 30, 31 e 32 - Parte 44
30. Magali em Comida Falante - Turma da M�nica


回答1:


As you point out you have to scroll down until the "spinner" does not appear but for this you need to use a QWebEngineView, and then you can get the text as you have done or use QWebChanel as I implement it in my answer. So that the QWebEngineView is not shown I have activated the attribute Qt::WA_DontShowOnScreen.

import sys
from PyQt5 import QtCore, QtWidgets, QtWebEngineWidgets, QtWebChannel

SCRIPT = """
var timeout = 1 * 1000;

var backend = null;

new QWebChannel(qt.webChannelTransport, function (channel) {
    backend = channel.objects.backend;
});

function try_send_data(){
    if(document.getElementById("spinner")){
        document.documentElement.scrollTo(0, document.body.scrollHeight || document.documentElement.scrollHeight);
        setTimeout(try_send_data, timeout)
        return
    }
    else{
        var titles = []
        for (let item of document.getElementsByClassName("yt-simple-endpoint style-scope ytd-grid-video-renderer")) {
            titles.push(item.innerText);
        }
        backend.set_titles(titles);
    }
}
setTimeout(try_send_data, timeout);
"""


class YTScrapper(QtCore.QObject):
    def __init__(self, url, parent=None):
        super().__init__(parent)

        self._titles = []

        app = QtWidgets.QApplication(sys.argv)
        self._page = QtWebEngineWidgets.QWebEnginePage(self)

        channel = QtWebChannel.QWebChannel(self)
        self.page.setWebChannel(channel)

        self._view = QtWebEngineWidgets.QWebEngineView()
        self._view.setAttribute(QtCore.Qt.WA_DontShowOnScreen, True)
        self._view.setPage(self.page)
        self._view.resize(1920, 1080)
        self._view.show()

        self.page.loadFinished.connect(self.on_load_finished)

        self.page.load(QtCore.QUrl(url))
        app.exec_()

    @property
    def titles(self):
        return self._titles

    @property
    def page(self):
        return self._page

    @QtCore.pyqtSlot(bool)
    def on_load_finished(self, ok):
        if ok:
            file = QtCore.QFile(":/qtwebchannel/qwebchannel.js")
            if file.open(QtCore.QIODevice.ReadOnly):
                content = file.readAll()
                file.close()
                self.page.runJavaScript(content.data().decode())
            self.page.webChannel().registerObject("backend", self)

            self.page.runJavaScript(SCRIPT)
        else:
            QtCore.QCoreApplication.quit()

    @QtCore.pyqtSlot(list)
    def set_titles(self, titles):
        self._titles = titles
        QtCore.QCoreApplication.quit()


def main():
    yt_scrapper = YTScrapper(
        "https://www.youtube.com/channel/UCY50YjnaeI7ezvRagFWeWmw/videos"
    )
    for i, title in enumerate(yt_scrapper.titles, start=1):
        print(f"{i}. {title.encode('utf-8')}")


if __name__ == "__main__":
    main()

Output:

1. Plants vs Zombies 2 - FUTURO DISTANTE - dias 09, 10, 11 e 12 - Parte 48
2. Marisa ou Mônica - Turma da Mônica
3. Jogo PET DOLL - Parte 02
4. A Magali não mora mais aqui - Turma da Mônica
5. MOY'S WORLD (parte 03) - Mundo 01 - Nível 6 - Gameplay
6. Mônica e Cebolinha em "uma pedra no meio do caminho" - Turma da Mônica
7. Plants vs Zombies 2 - FUTURO DISTANTE - dia 08 e Terror do Amanhã - Parte 47
8. Magali em "Não Sou Boneca" - Turma da Mônica
9. Talking Tom HERO DASH - Terminamos todas os mundos!!! - Parte 13
10. Mônica em Maternidade Saudável - Turma da Mônica
11. Rotina Matinal da Bebê Reborn da Luisa - Cuidando da boneca
12. Bloop Go! Jogo/Game - Parte 1
13. Chico Bento em "se não fosse a feiúra" - Turma da Mônica
14. Luisa cuidando do gatinho BUBBU - parte 3
15. Turma da Mônica em "as três letrinhas" - Feliz dia das mães!!!
16. Plants vs Zombies 2 - FUTURO DISTANTE - dias 05, 06 e 07 - Parte 46
17. A Turma em "freguês tem sempre razão" - Turma da Mônica
18. Dollify - parte 4 - Brincando de fazer caricaturas! Fazendo o boneco da prima Julia
19. Cascão em "o maior bode" - Turma da Mônica
20. Jogo Hotel Transilvânia Adventures - parte 12 - Terminamos a COZINHA - Fases 55 e 56
21. Turma do Penadinho em "sexta-feira 14" - Turma da Mônica
22. Plants vs Zombies 2 - iniciamos FUTURO DISTANTE - dias 01, 02, 03 e 04 - Parte 45
23. Chico Bento e o Nome - Turma da Mônica
24. Talking Angela - Jogando com a Gatinha Angela - Nìvel 20 (parte 9)
25. Magali e a Turma em "OS ADOLESCENTES" - Turma da Mônica
26. Cortando o cabelo (franjinha) da Luisa em casa! #mãeefilha
27. Jogo Gardenscapes - Parte 11 - Cuidando do Jardim e do Totó - Nível 48
28. Cebolinha em "a caveira dentuça" - Turma da Mônica
29. Plants vs Zombies 2 - TERMINAMOS A CIDADE PERDIDA - dias 30, 31 e 32 - Parte 44
30. Magali em Comida Falante - Turma da Mônica
31. Meu Tom 2 (jogo/gameplay) - Parte 11 - O Tom está crescendo novamente: 10 anos!
32. Desencaixotando a Magali - Turma da Mônica
33. Plants vs Zombies 2 - CIDADE PERDIDA - dias 26, 27, 28 e 29 - Parte 43
34. Mônica em "tem alguma coisa escrita no tronco da árvore" - Turma da Mônica
35. CHAVES Adventures (Jogo/Game) - Nível 04
36. Luca e Cebolinha em "devolve minha cadeira" - Turma da Mônica
37. MOY'S WORLD (parte 02) - Mundo 01 - Níveis 4 e 5 - Gameplay
38. Historinha da Magali - Turma da Mônica
39. Quebra-cabeça da Masha e o Urso - Diversão em família!
40. Super Phantom Cat 2 - ÁRVORE ANCIÃ - Nível 3 - parte 13 (Gameplay/Jogo)
41. Mônica em "Pixador Apaixonado" - Turma da Mônica
42. Dentista: Cuidando dos animais (Jogo/Game)
43. PÁSCOA - Turma da Mônica
44. Plants vs Zombies 2 - CIDADE PERDIDA - dias 21, 22, 23, 24 e 25 - Parte 42
45. Chico Bento em 1° de Abril
46. Talking Tom HERO DASH - LIGUE O TURBO! - Parte 12
47. Turma da Mônica em "sobre luzes e balões"
48. Meu Tom 2 (jogo/gameplay) - Parte 10 - O Tom voltou a ter 6 anos
49. Mônica em "correndo atrás do Luca" - Turma da Mônica
....
....
600. Cebolinha tentando fugir da Mônica - Turma da Mônica
601. Mônica brincando de casinha com Cascão e Cebolinha - Turma da Mônica
602. Mônica e Cebolinha na praia - Turma da Mônica
603. Chico Bento sem sono - Turma da Mônica
604. Bidu em uma aventura mal assombrada - Turma da Mônica
605. O aniversário da Magali - Turma da Mônica
606. Cebolinha e o lobisomem - Turma da Mônica
607. Parabéns pra você - Galinha Pintadinha, Pintinho Amarelinho, aniversário do Ursinho, nosso clipe


来源:https://stackoverflow.com/questions/61991229/how-to-load-and-parse-whole-content-of-a-dynamic-page-that-use-infinity-scroll

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!