机器学习框架Ray -- 2.3 基于Ray的并行化网络爬虫

在这个示例中,我们将快速演示如何使用最少的代码更改在Python中构建一个简单的网页爬虫,并使用Ray Tasks并行化它。

0. 运行环境

本案例的环境为Anaconda建立的名为RayAIR的环境,具体创建过程以下链接的第2节:《机器学习框架Ray -- 2.1 Ray Clusters与Ray AIR的基本使用》

此外,爬虫需要安装beautifulsoup4:

pip install "beautifulsoup4==4.11.1"

完整Anaconda的环境定义为

conda create -n RayAIR python=3.7
conda activate RayAIR
pip install "ray[air]"
pip install xgboost_ray
pip install ipykernel -i https://pypi.tuna.tsinghua.edu.cn/simple 
pip install "beautifulsoup4==4.11.1"

后续操作都是在Linux Anaconda的命名为RayAIR环境中,以.ipynb的形式运行。

1.1 网络爬虫

首先,我们将定义一个名为find_links的函数,该函数接受要爬行的起始页面(start_url),并以Ray文档作为此类起始点的示例。

爬虫只是从起始URL提取包含给定base_url的所有可用链接(例如,在我们的示例中,我们只想跟踪http://docs.ray.io上的链接,而不是任何外部链接)。

以这种方式找到的所有链接将被递归地传递给find_links函数,直到达到一定深度为止。

为了从网站上的HTML元素中提取链接,我们定义了一个名为extract_links的助手函数,它负责正确处理相对URL,并设置从站点返回的链接数量(max_results)上限,以更轻松地控制爬虫的运行时间。

import requests
from bs4 import BeautifulSoup
def extract_links(elements, base_url, max_results=100):
    links = []
    for e in elements:
        url = e["href"]
        if "https://" not in url:
            url = base_url + url
        if base_url in url:
            links.append(url)
    return set(links[:max_results])


def find_links(start_url, base_url, depth=2):
    if depth == 0:
        return set()

    page = requests.get(start_url)
    soup = BeautifulSoup(page.content, "html.parser")
    elements = soup.find_all("a", href=True)
    links = extract_links(elements, base_url)

    for url in links:
        new_links = find_links(url, base_url, depth-1)
        links = links.union(new_links)
    return links

1.2 单线程爬取网页

定义一个起始和基本URL,深度为2爬取Ray文档。

base = "https://docs.ray.io/en/latest/"
docs = base + "index.html"
%time len(find_links(docs, base))

单线程爬虫用时1m4s,爬取了594个页面,运行结果如下:

CPU times: user 25 s, sys: 276 ms, total: 25.3 s
Wall time: 1min 4s
594

2. 并行化网络爬虫

可以以多种方式并行爬取页面。最简单的方法是简单地从多个起始URL开始,并为每个URL并行调用find_links。使用Ray Tasks以简单的方式实现这一点。只需使用ray.remote装饰器将find_links函数包装在名为find_links_task的任务中,如下所示:

import ray

@ray.remote
def find_links_task(start_url, base_url, depth=2):
    return find_links(start_url, base_url, depth)

要使用此任务启动并行调用,您唯一需要做的就是使用find_links_tasks.remote(...),而不是直接调用底层Python函数。

以下是如何并行运行六个爬虫的示例,前三个(冗余地)再次爬取docs.ray.io,另外三个分别爬取Ray RLlib,Tune和Serve库的主要入口点:

links = [find_links_task.remote(f"{base}{lib}/index.html", base)
         for lib in ["", "", "", "rllib", "tune", "serve"]]
%time for res in ray.get(links): print(len(res))

 爬虫结果:

2023-04-06 04:54:58,567	INFO worker.py:1550 -- Started a local Ray instance. View the dashboard at http://127.0.0.1:8265 
594
594
594
101
101
101
CPU times: user 246 ms, sys: 74.9 ms, total: 321 ms
Wall time: 1min 28s

这次并行运行,相比最初的顺序运行要高效得多。

在近似相同的时间内,通过并行化运行爬虫,获得了六组爬虫数据。

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值