You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Selenium爬取RSC文献时遭遇TimeoutException问题求助

问题:Selenium爬取RSC文献时触发TimeoutException异常

问题详情

使用Selenium爬取RSC corpus文献时,以下代码行始终抛出TimeoutException:

wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '.capsule.capsule--article')))

已尝试EC.presence_of_element_located和EC.visibility_of_element_located两种等待策略,均无效。确认CSS选择器正确,URL可正常加载查询结果,但无法定位到解决异常的方法。

堆栈跟踪信息

Traceback (most recent call last):
  File "rsc.py", line 40, in <module>
    main(url, query, page, location)
  File "rsc.py", line 22, in main
    dois = scraper.get_doi(query=query, page=page)
  File "/home/ssarrouf/Documents/GitHub/WaterRemediationParser/batterydataextractor-main/batterydataextractor/scrape/rsc.py", line 62, in get_doi
    _ = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '.capsule.capsule--article')))
  File "/home/ssarrouf/.pyenv/versions/3.8.16/lib/python3.8/site-packages/selenium/webdriver/support/wait.py", line 95, in until
    raise TimeoutException(message, screen, stacktrace)
selenium.common.exceptions.TimeoutException: Message: 
Stacktrace:
#0 0x55e10fae5d93 <unknown>
#1 0x55e10f8b42d7 <unknown>
#2 0x55e10f8f0caa <unknown>
#3 0x55e10f8f0db1 <unknown>
#4 0x55e10f92e8f4 <unknown>
#5 0x55e10f91461d <unknown>
#6 0x55e10f92c619 <unknown>
#7 0x55e10f914353 <unknown>
#8 0x55e10f8e3e40 <unknown>
#9 0x55e10f8e5038 <unknown>
#10 0x55e10fb398be <unknown>
#11 0x55e10fb3d8f0 <unknown>
#12 0x55e10fb1df90 <unknown>
#13 0x55e10fb3eb7d <unknown>
#14 0x55e10fb0f578 <unknown>
#15 0x55e10fb63348 <unknown>
#16 0x55e10fb634d6 <unknown>
#17 0x55e10fb7d341 <unknown>
#18 0x7f0fad5a9b43 <unknown>

相关代码片段

get_doi方法

def get_doi(self, query, page):
      """
        Get a list of dois from query massages and the exact page.
        :param query: the query text (e.g. battery materials)
        :param page: the number of page
        :return: a list of dois of the relevant query text and page.
        """
        
        if self.driver is None:
            driver = webdriver.Chrome()
        else:
            driver = self.driver

        if self.url is None:
            url = "http://pubs.rsc.org/en/results?searchtext="
            url = url + query
        else:
            url = self.url
        driver.get(url)
        wait = WebDriverWait(driver, self.max_wait_time)
        # To make sure we don't overload the server
        sleep(1)
        next_button = wait.until(EC.visibility_of_all_elements_located((By.CSS_SELECTOR, "a[class^=paging__btn]")))[1]
        page_string = """document.querySelectorAll("a[class^=paging__btn]")[1].setAttribute("data-pageno", \\""""\
                      + str(page) + """\\")"""
        driver.execute_script(page_string)
        next_button.click()
        sleep(1)
        _ = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '.capsule.capsule--article')))
        doi_lists = driver.find_elements(By.PARTIAL_LINK_TEXT, 'https://doi.org')
        dois = [doi.text for doi in doi_lists]
        return dois

文献下载方法

def download_doi(self, doi, file_location):
    """
    Download the html paper of the doi
    :param doi: doi of the paper
    :param file_location: the saving location
    :return:
    """
    doi = doi.split("org/")[-1]
    r = requests.get('http://doi.org/' + doi, headers={'User-Agent': 'Mozilla/5.0'})
    result = re.findall(r'https://pubs.rsc.org/en/content/articlehtml/.*?"', r.text)
    url = result[0][:-1]
    web_content = requests.get(url, headers={"User-Agent": "Mozilla/5.0"}).content

    result = self.get_rsc_abstract(web_content)
    exact_date = result['date'].split("/")
    doi = result['doi'].replace("/", "_")
    if len(exact_date) == 3:
        name = exact_date[0] + exact_date[1] + exact_date[2] + '_' + doi
    else:
        name = result['online_date'].replace("/", "") + '_' + doi

    with open(file_location + name + '.html', 'wb') as f:
        f.write(web_content)
    return

爬虫主方法

def main(url, query, page, file_location):
    """
    RSC web-scraper runner
    :param url: the scraping url (or default)
    :param query: query text (e.g. battery materials)
    :param page: the page number of the query pages
    :param file_location: saving location
    :return:
    """
    scraper = RSCWebScraper(url=url)
    dois = scraper.get_doi(query=query, page=page)
    for doi in dois:
        try:
            scraper.download_doi(doi, file_location)
        # Some papers don't have html access
        except:
            continue
    return


if __name__ == "__main__":
    # Download papers within a certain date range
    url = "https://pubs.rsc.org/en/results/all?Category=All&AllText=water%20remediation&IncludeReference=false&Select" \
          "Journal=false&DateRange=true&SelectDate=true&DateToYear={}&DateFromYear={}&DateFromMonth={}&DateTo" \
          "Month={}&PriceCode=False&OpenAccess=false".format("2022", "2021", "06", "01")
    query = "water remediation"
    location = r"/home/ssarrouf/Documents/webscrape/to_date_papers/rsc/"
    for page in range(1, 120):
        main(url, query, page, location)

已尝试的无效操作

  • 修改等待方式(presence_of_element_located/visibility_of_element_located)
  • 调整查询条件和日期范围

解决方案

1. 排查iframe嵌套问题

RSC部分页面会通过iframe加载搜索结果,导致目标元素不在主DOM树中。在等待目标元素前执行以下代码切换到对应iframe:

# 遍历所有iframe,尝试切换到包含目标元素的iframe
for iframe in driver.find_elements(By.TAG_NAME, 'iframe'):
    try:
        driver.switch_to.frame(iframe)
        if len(driver.find_elements(By.CSS_SELECTOR, '.capsule.capsule--article')) > 0:
            break
    except Exception:
        driver.switch_to.default_content()
# 若未找到目标iframe,切回主文档
driver.switch_to.default_content()

2. 绕过反爬检测

RSC可能通过浏览器自动化特征识别爬虫,配置ChromeDriver模拟真实浏览器:

from selenium.webdriver.chrome.options import Options

options = Options()
# 禁用自动化检测标志
options.add_argument("--disable-blink-features=AutomationControlled")
options.add_experimental_option("excludeSwitches", ["enable-automation"])
options.add_experimental_option('useAutomationExtension', False)

driver = webdriver.Chrome(options=options)
# 覆盖navigator.webdriver属性
driver.execute_script("Object.defineProperty(navigator, 'webdriver', {get: () => undefined})")

点击分页后触发页面滚动,确保动态内容加载:

next_button.click()
# 滚动至页面底部触发内容加载
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
time.sleep(2)

3. 优化等待策略

延长超时时间并等待多个目标元素出现,提升稳定性:

# 将超时时间调整为30秒
wait = WebDriverWait(driver, 30)
# 等待至少一个结果胶囊加载完成
_ = wait.until(EC.presence_of_all_elements_located((By.CSS_SELECTOR, '.capsule.capsule--article')))

4. 重构分页逻辑

当前修改data-pageno的方式不可靠,直接构造分页URL跳转更稳定:
RSC搜索结果的分页URL通常可通过在原URL后拼接&page=页码实现,替换原分页相关代码:

# 移除原next_button相关操作,直接访问目标分页URL
driver.get(f"{url}&page={page}")
# 等待结果加载
_ = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '.capsule.capsule--article')))

5. 确保页面完全加载

在执行元素定位前,等待页面DOM加载完成:

wait.until(lambda driver: driver.execute_script('return document.readyState') == 'complete')

内容的提问来源于stack exchange,提问作者Chloe C

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 15:40:38