python - 如何并行递归进行网站爬网?
问题描述
我正在尝试在 Python 中使用 BeautifulSoup 并行抓取网站。
我给函数一个 url 和一个深度变量,它看起来像这样:
def recursive_crawl(url, depth):
if depth == 0:
return
links = fetch_links(url) # where I use the requests library
print("Level : ", depth, url)
for link in links:
if is_link_valid(link) is True:
recursive_crawl( URL , depth - 1)
输出部分类似于:
Level : 4 site.com
Level : 3 site.com/
Level : 2 site.com/research/
Level : 1 site.com/blog/
Level : 1 site.com/stories/
Level : 1 site.com/list-100/
Level : 1 site.com/cdn-cgi/l/email-protection
等等。
我的问题是这样的:
我正在使用set()
, 来避免访问已经访问过的链接,因此我遇到了共享内存问题。我可以并行实现这个递归网络爬虫吗?
注意:请不要推荐scrapy,我希望使用BeautifulSoup 之类的解析库来完成。
解决方案
我认为您使用的解析库并不重要。看来您要问的是如何管理线程。这是我的一般方法:
- 建立要访问的 URL的共享队列。虽然主要内容是 URL 字符串,但您可能希望用一些补充信息来包装它们:深度、引用链接以及您的蜘蛛想要的任何其他上下文信息。
- 构建一个网关守卫对象,该对象维护一个已访问 URL 的列表。(那个集合就是你提到的那个。)对象有一个方法,它接受一个 URL 并决定是否将它添加到 #1 中的队列中。(提交的 URL 也被添加到集合中。您还可以在添加之前去除 GET 参数的 URL。)在设置/实例化期间,它可能会采用因其他原因限制抓取的参数。根据您选择的队列种类,您还可以在此对象中进行一些优先级排序。由于您使用此网守来包装队列的输入,因此您可能还想包装队列的输出。
- 启动几个工作线程。您需要确保每个线程都使用引用单个网守实例的参数进行实例化。该线程包含一个包含所有页面抓取代码的循环。循环的每次迭代都使用来自网守队列的一个 URL,并将任何发现的 URL 提交给网守。(线程不关心 URL 是否已经在队列中。这个责任属于看门人。)
推荐阅读
- firebase - Firestore Cloud 写入功能不起作用
- python-2.7 - 如何在 NIfi 中配置 ExecuteScript 处理器以使用 JyNI 包启用使用 numpy 的库?
- c# - 尽管发生了 DataGridCell 中的验证错误,如何继续工作?
- java - Webdriver 不会点击“Accept cookies”按钮,抛出“ElementNotInteractable”异常
- wpf - 我可以将区域放在 TabItem 控件中吗?
- sql - SQL Server - 选择每个月的每日值
- appium - 回退到直接的 W3C 远程端连接和 SessionNotCreatedException:无法创建新的远程会话
- reactjs - 如何在 React JS 中访问其他组件或服务中的应用程序组件的方法
- python - 为什么不推断所有静态类型?
- intellij-idea - VScode 相当于 Jetbrains/IntelliJ/Rubymine 划痕(一次性笔记)