Youtube用硒刮:没有得到所有评论

Ane*_*esh 0 python selenium python-3.x

我试图使用selenium与python刮取youtube评论.下面是只删除一个注释并抛出错误的代码

driver = webdriver.Chrome()
url="https://www.youtube.com/watch?v=MNltVQqJhRE"
driver.get(url)

wait(driver, 5500)

driver.execute_script("window.scrollTo(0, document.body.scrollHeight + 500);")
driver.implicitly_wait(5000)

#content = driver.find_element_by_xpath('//*[@id="contents"]')
comm=driver.find_element_by_xpath('//div[@class="style-scope ytd-item-section-renderer"]')
comm1=comm.find_elements_by_xpath('//yt-formatted-string[@id="content-text"]')
#print(comm.text)
for i in range(50):
    print(comm1[i].text,end=' ')
Run Code Online (Sandbox Code Playgroud)

这是我得到的输出.如何获得该页面上的所有评论??? 谁能帮我这个.

 Being a sucessful phyton freelancer really mean to me because if I able to make $2000 in month I can really help my family financial, improve my skill, and have a lot of time to refreshing. So thanks Qazi, you really help me :D 

Traceback (most recent call last):
  File "C:\Python36\programs\Web scrap\YT_Comm.py", line 19, in <module>
    print(comm1[i].text,end=' ')
IndexError: list index out of range
Run Code Online (Sandbox Code Playgroud)

Ian*_*nce 5

一个IndexError意味着你试图访问不存在的列表中的位置.您正在遍历元素列表(comm1)正好50次,但列表中的元素少于50个,因此最终您尝试访问不存在的索引.

从表面上看,您可以通过更改迭代来解决您的问题,以完全覆盖列表中存在的元素 - 不多也不少:

for element in comm1:
    print(element.text, end=‘ ‘)
Run Code Online (Sandbox Code Playgroud)

但是,留给你的问题,为什么你的列表中有超过50个元素少.你正在搜索的视频有超过90条评论.为什么你的清单没有全部?

如果您查看浏览器中的页面,您将看到注释使用无限滚动技术逐步加载:当用户滚动到文档的底部时,将获取并呈现另一个"页面"注释,增加文件的长度.要加载更多注释,您需要触发此行为.

但是根据评论的数量,一次提取可能还不够.为了触发获取和呈现所有内容,您需要:

  1. 试图触发获取额外的内容,然后
  2. 确定是否提取了其他内容,如果是,
  3. 重复(因为可能会有更多).

触发获取

我们已经知道通过滚动到内容容器的底部(带有元素id #contents)来获取其他内容,所以让我们这样做:

driver.execute_script(
    "window.scrollTo(0, document.querySelector('#contents').scrollHeight);")
Run Code Online (Sandbox Code Playgroud)

(注意:因为内容位于一个absolute位置元素中,所以document.body.scrollHeight将始终0并且不会触发滚动.)

等待内容容器

但与任何浏览器自动化一样,我们正在与应用程序竞争:如果内容容器尚未呈现,该怎么办?我们的卷轴会失败.

Selenium提供WebDriverWait()帮助您等待应用程序处于特定状态.它还通过其expected_conditions模块提供一组等待的常见状态,例如元素的存在.我们可以使用这两个来等待内容容器存在:

from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait

TIMEOUT_IN_SECONDS = 10

wait = WebDriverWait(driver, TIMEOUT_IN_SECONDS)
wait.until(
    EC.presence_of_element_located((By.CSS_SELECTOR, "#contents")))
Run Code Online (Sandbox Code Playgroud)

确定是否提取了其他内容

在较高级别,我们可以确定是否通过以下方式获取其他内容:

  1. 我们触发获取之前计算内容,
  2. 我们触发获取计算内容,然后
  3. 比较两者.

计算内容

在我们的容器(with id "#contents")中,每个内容都有id #content.要计算内容,我们可以简单地获取每个元素并使用Python的内置len():

count = len(driver.find_elements_by_css_selector("#contents #content")
Run Code Online (Sandbox Code Playgroud)

处理慢渲染

但同样,我们正在与应用程序竞争:如果获取或渲染其他内容的速度慢,会发生什么?我们不会马上看到它.

我们需要给Web应用程序时间来做它的事情.为此,我们可以使用WebDriverWait()自定义条件:

def get_count():
    return len(driver.find_elements_by_css_selector("#contents #content"))

count = get_count()
# ...
wait.until(
    lambda _: get_count() > count)
Run Code Online (Sandbox Code Playgroud)

不处理其他内容

但是,如果没有任何其他内容怎么办?我们等待计数增加将超时.

只要我们的超时足够高以允许有足够的时间来显示其他内容,我们就可以假设没有其他内容并忽略超时:

try:
    wait.until(
        lambda _: get_count() > count)
except TimeoutException:
    # No additional content appeared. Abort our loop.
    break
Run Code Online (Sandbox Code Playgroud)

把它们放在一起

from selenium.common.exceptions import TimeoutException
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait

TIMEOUT_IN_SECONDS = 10

wait = WebDriverWait(driver, TIMEOUT_IN_SECONDS)

driver.get(URL)

wait.until(
    EC.presence_of_element_located((By.CSS_SELECTOR, "#contents")))

def get_count():
    return len(driver.find_elements_by_css_selector("#contents #content"))

while True:
    count = get_count()
    driver.execute_script(
        "window.scrollTo(0, document.querySelector('#contents').scrollHeight);")
    try:
        wait.until(
            lambda _: get_count() > initial_count)
    except TimeoutException:
        # No additional content appeared. Abort our loop.
        break

elements = driver.find_elements_by_css_selector("#contents #content")
Run Code Online (Sandbox Code Playgroud)

额外奖励:用capybara-py简化

使用capybara-py,这变得有点简单:

import capybara
from capybara.dsl import page
from capybara.exceptions import ExpectationNotMet

@capybara.register_driver("selenium_chrome")
def init_selenium_chrome_driver(app):
    from capybara.selenium.driver import Driver
    return Driver(app, browser="chrome")

capybara.current_driver = "selenium_chrome"
capybara.default_max_wait_time = 10

page.visit(URL)

contents = page.find("#contents")

elements = []
while True:
    try:
        elements = contents.find_all("#content", minimum=len(elements) + 1)
    except ExpectationNotMet:
        # No additional content appeared. Abort our loop.
        break

    page.execute_script(
        "window.scrollTo(0, arguments[0].scrollHeight);", contents)
Run Code Online (Sandbox Code Playgroud)