【问题标题】:How to reduce amount of scraping time when using Requests-HTML?使用 Requests-HTML 时如何减少抓取时间?
【发布时间】:2021-01-05 00:53:05
【问题描述】:

我目前使用 Requests-HTML 版本 0.10.0 和 Selenium 3.141.0。我的项目是刮掉这个网站https://openreview.net/group?id=ICLR.cc/2021/Conference上所有文章的评分。要打开网站的每个页面(网站有 53 个页面,每个页面有 50 篇文章),我使用 Selenium。接下来,要在每个页面上打开文章,我使用 Requests-HTML。我的问题是关于如何减少打开每篇文章并获得评分的时间。在这种情况下,我使用await r_inside.html.arender(sleep = 5, timeout=100),表示休眠时间为5秒,超时时间为100秒。当我尝试将睡眠时间减少到 0.5 秒时,它会导致错误,这是因为它没有足够的时间来抓取网站。但是,如果我将睡眠时间保持为 5 秒,则将 2600 篇文章全部刮掉需要 6 到 13 个小时。此外,等待 13 小时后,我可以抓取所有 2600 篇文章,但代码使用 88 GB 的 RAM,我不喜欢,因为我需要将此代码发送给没有足够 RAM 运行的其他人。我的目的是减少抓取时间和 RAM 内存。下面是我使用的代码。

import csv

link = 'https://openreview.net/group?id=ICLR.cc/2021/Conference'

from requests_html import HTMLSession, AsyncHTMLSession

import time
from tqdm import tqdm
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
id_list = []
keyword_list = []
abstract_list = []
title_list = []
driver = webdriver.Chrome('./requests_html/chromedriver.exe')
driver.get('https://openreview.net/group?id=ICLR.cc/2021/Conference')

cond = EC.presence_of_element_located((By.XPATH, '//*[@id="all-submissions"]/nav/ul/li[13]/a'))
WebDriverWait(driver, 10).until(cond)


for page in tqdm(range(1, 54)):
    text = ''
    elems = driver.find_elements_by_xpath('//*[@id="all-submissions"]/ul/li')
    for i, elem in enumerate(elems):
        try:
            # parse title
            title = elem.find_element_by_xpath('./h4/a[1]')
            link = title.get_attribute('href')
            paper_id = link.split('=')[-1]
            title = title.text.strip().replace('\t', ' ').replace('\n', ' ')
            # show details
            elem.find_element_by_xpath('./a').click()
            time.sleep(0.2)

            # parse keywords & abstract
            items = elem.find_elements_by_xpath('.//li')
            keyword = ''.join([x.text for x in items if 'Keywords' in x.text])
            abstract = ''.join([x.text for x in items if 'Abstract' in x.text])
            keyword = keyword.strip().replace('\t', ' ').replace('\n', ' ').replace('Keywords: ', '')
            abstract = abstract.strip().replace('\t', ' ').replace('\n', ' ').replace('Abstract: ', '')
            text += paper_id+'\t'+title+'\t'+link+'\t'+keyword+'\t'+abstract+'\n'
            title_list.append(title)
            id_list.append(paper_id)
            keyword_list.append(keyword)
            abstract_list.append(abstract)
        except Exception as e:
            print(f'page {page}, # {i}:', e)
            continue



    # next page
    try:
        driver.find_element_by_xpath('//*[@id="all-submissions"]/nav/ul/li[13]/a').click()
        time.sleep(2) # NOTE: increase sleep time if needed
    except:
        print('no next page, exit.')
        break

csv_file = open('./requests_html/bb_website_scrap.csv','w', encoding="utf-8")
csv_writer = csv.writer(csv_file)
csv_writer.writerow(['Title','Keyword','Abstract','Link','Total Number of Reviews','Average Rating','Average Confidence'])
n = 0
for item in range(len(id_list)):
     title = title_list[item]
     keyword = keyword_list[item]
     abstract = abstract_list[item]
     id = id_list[item]

     link_pdf = f'https://openreview.net/forum?id={id}'
     print(id)

     asession_inside = AsyncHTMLSession()
     r_inside = await asession_inside.get(link_pdf)
     print(type(r_inside))
     await r_inside.html.arender(sleep = 5, timeout=100)

     test_rating = r_inside.html.find('div.comment-level-odd div.note_contents span.note_content_value')
     print(len(test_rating))
     check_list = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9','10'}
     total_rating_confidence = []
     total_rating = []
     total_confidence = []
     for t in range(len(test_rating)):
          if any(test_rating[t].text.split(':')[0] in s for s in check_list):
               total_rating_confidence.append(test_rating[t].text.split(':')[0])

     for r in range(len(total_rating_confidence)):
          if (r % 2 == 0):
               total_rating.append(int(total_rating_confidence[r]))
          else:
               total_confidence.append(int(total_rating_confidence[r]))

     average_rating = sum(total_rating) / len(total_rating)
     average_confidence = sum(total_confidence) / len(total_confidence)
     csv_writer.writerow([title, keyword, abstract, link_pdf,len(total_rating),average_rating,average_confidence])
     n = n + 1
     print('Order {}',n)
csv_file.close()

【问题讨论】:

  • 我不确定你为什么必须使用 Selenium。如果您使用 request & BS 提取页面上所有文章的链接,然后遍历它们会更容易。 (除非它是动态的并且您无法提取链接)

标签: selenium selenium-webdriver web-scraping python-requests-html


【解决方案1】:

我不是 Python 专家(事实上,我是初学者),但简单的答案是更好的并行性和会话管理。

有用的答案有点复杂。

您将离开 Chromium 会话,这很可能是您占用所有 RAM 的原因。如果您致电 asession_inside.close(),您可能会看到 RAM 使用率有所改善。

据我所知,您所做的一切都是串行的;您获取每一页并连续提取文章的数据。然后,您也可以连续查询每篇文章。

您正在使用arender 异步获取每篇文章,但您正在等待它并使用标准的for 循环。据我了解,这意味着您没有从异步中获得任何优势;您仍在一次处理每一页(这说明了您的处理时间很长)。

我建议使用 asyncio 将 for 循环转换为自身的并行版本,如 in this article 建议的那样。确保您设置了任务限制,这样您就不会尝试一次加载所有文章;这也将有助于您使用 RAM。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-04-09
    • 1970-01-01
    • 2019-05-18
    • 2010-10-23
    • 2022-01-16
    • 1970-01-01
    • 2022-08-17
    • 1970-01-01
    相关资源
    最近更新 更多