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

时间:2018-03-10 17:24:00

标签: python python-3.x selenium

我正在尝试使用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=' ')

这是我得到的输出。如何获得该页面上的所有评论???任何人都可以帮助我。

 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

1 个答案:

答案 0 :(得分:5)

IndexError表示您正在尝试访问列表中不存在的位置。您正在迭代元素列表(comm1)50次,但列表中的元素少于50个,因此最终您尝试访问不存在的索引。

表面上,你可以通过改变你的迭代来解决你的问题,以完全循环列表中存在的元素 - 不多也不少:

for element in comm1:
    print(element.text, end=‘ ‘)

但这会让你遇到为什么你的列表少于50个元素的问题。你正在搜索的视频有超过90条评论。为什么你的清单没有全部?

如果您查看浏览器中的页面,您会看到评论使用infinite scroll技术逐步加载:当用户滚动到文档底部时,另一个&#34 ;页面&#34;获取和呈现注释,增加文档的长度。要加载更多注释,您需要触发此行为。

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

  1. 尝试触发其他内容的提取,然后
  2. 确定是否已提取其他内容,如果是,
  3. 重复(因为可能会有更多)。
  4. 触发提取

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

    driver.execute_script(
        "window.scrollTo(0, document.querySelector('#contents').scrollHeight);")
    

    (注意:由于内容位于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")))
    

    确定是否提取了其他内容

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

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

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

      count = len(driver.find_elements_by_css_selector("#contents #content")
      

      处理慢速渲染

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

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

      def get_count():
          return len(driver.find_elements_by_css_selector("#contents #content"))
      
      count = get_count()
      # ...
      wait.until(
          lambda _: get_count() > count)
      

      不处理其他内容

      但如果不是任何其他内容怎么办?我们等待计数增加将会超时。

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

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

      全部放在一起

      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")
      

      奖金:用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)