【问题标题】:Recursive crawling with BeautifulSoup really slow使用 BeautifulSoup 进行递归爬行真的很慢
【发布时间】:2022-01-05 10:56:07
【问题描述】:

我正在构建一个爬虫,它可以下载给定网站及其子页面的所有 .pdf 文件。为此,我围绕以下简化的递归函数使用了内置功能,该函数检索给定 URL 的所有链接。

但是这会变得很慢,它抓取给定网站的时间越长(每个 URL 可能需要 2 分钟或更长时间)。 我不太清楚是什么原因造成的,非常感谢有关需要更改哪些内容以提高速度的建议。

import re
import requests
from bs4 import BeautifulSoup

pages = set()

def get_links(page_url):
  global pages
  pattern = re.compile("^(/)")
  html = requests.get(f"https://www.srs-stahl.de/{page_url}").text
  soup = BeautifulSoup(html, "html.parser")
  for link in soup.find_all("a", href=pattern):
    if "href" in link.attrs:
      if link.attrs["href"] not in pages:
        new_page = link.attrs["href"]
        print(new_page)
        pages.add(new_page)
        get_links(new_page)
        
get_links("")

【问题讨论】:

  • 你可能会陷入一些无限递归,不确定它是否与你的问题有关,但你必须统一你的页面列表 (pages = list(set(pages)) 否则如果页面 A 带你到页面 B 和页面 B 带你到页面 A 你会永远卡在那里
  • 如果 link.attrs["href"] 不在页面中,这与我所做的不一样吗?
  • 可能只是服务器问题
  • 添加时间打印机,可能是服务器延迟你的请求越来越多的情况。

标签: python beautifulsoup web-crawler


【解决方案1】:

要弄清楚是什么主动减慢了您的抓取速度并不容易 - 这可能是您抓取的方式、网站的服务器......

在您的代码中,您请求一个 URL,获取链接并在第一次迭代中调用函数本身,因此您只附加请求的 URL。

您可能希望使用“队列”来保持流程更加透明。

一个优点是,如果脚本中止,您可以存储此信息,并可以从您已经收集的要访问的 URL 开始访问它。与你的 for 循环完全相反,它可能必须从更早的点开始以确保它获取所有 url。

另一点是,您请求 PDF 文件,但没有以任何方式使用响应。直接下载并保存它们或跳过请求并至少将链接保留在单独的“队列”中以进行后期处理不是更有意义吗?

比较收集的信息 - 基于迭代

有问题的代码:

pages --> 24

示例代码(无延迟):

urlsVisited --> 24
urlsToVisit --> 87 
urlsToDownload --> 67

示例

只是为了演示,您可以根据自己的需要随意创建定义、类和结构。注意添加了一些延迟,但如果您愿意,可以跳过它。演示流程的“队列”是列表,但应该是文件、数据库……以安全地存储您的数据。

import requests, time
from bs4 import BeautifulSoup
baseUrl = 'https://www.srs-stahl.de'
urlsToDownload = []
urlsToVisit = ["https://www.srs-stahl.de/"]
urlsVisited = []

def crawl(url):
    html = requests.get(url).text
    soup = BeautifulSoup(html, "html.parser")
    for a in soup.select('a[href^="/"]'):
        url = f"{baseUrl}{a['href']}"
        if '.pdf' in url and url not in urlsToDownload:
            urlsToDownload.append(url)
        else:
            if url not in urlsToVisit and url not in urlsVisited:
                urlsToVisit.append(url)
                
while urlsToVisit:
    url = urlsToVisit.pop(0)
    try:
        crawl(url)
    except Exception as e:
        print(f'Failed to crawl: {url} -> error {e}')
    finally:
        urlsVisited.append(url)
        time.sleep(2)

【讨论】:

  • 目前仍在围绕这个进行构建,这是一个非常有帮助的答案!非常感谢。
  • 很高兴为您提供帮助,欢迎来到 Stack Overflow。如果此答案或任何其他答案对您有帮助或解决了您的问题,请将其标记为已接受 - someone-answers - 会很棒。
猜你喜欢
  • 2018-08-13
  • 1970-01-01
  • 2020-12-28
  • 1970-01-01
  • 2021-01-17
  • 2015-03-19
  • 2017-10-12
  • 1970-01-01
  • 2013-04-12
相关资源
最近更新 更多