自学 python 中的异步编程 asyncio:实战(二)爬虫爬全网

本文介绍了Python的异步编程库asyncio,包括基本概念、核心组件、异步IO编程和线程结合的使用。通过一个实战案例,展示了如何使用asyncio和aiohttp构建一个异步爬虫,解析页面、获取链接并递归爬取多个层级的页面,同时避免了重复访问和超过了最大深度的问题。
摘要由CSDN通过智能技术生成

备注

  • 本文主要用于协程实战,重点用于理解协程,理解异步编程
  • 重点不是爬虫的全流程代码书写,关于爬虫的技能请参考我的爬虫自学专栏

这个异步爬虫的实现方式如下

  1. 首先定义了一个 fetch 函数,用于异步获取指定 url 的页面内容。
    1. 该函数使用 aiohttp 库发送异步 HTTP 请求
    2. 并使用 async with 语句保证资源在使用完成后自动释放,最终返回页面内容。
  2. 然后定义了一个 get_links 函数,用于解析指定页面中的所有链接。
    1. 该函数使用 BeautifulSoup 库解析页面内容,并查找其中所有的 <a> 标签
    2. 然后将其中的 href 属性值作为链接添加到列表中并返回
  3. 接着定义了一个递归的异步函数 crawl,用于异步爬取指定网站的所有页面
    • 该函数接受四个参数:
      1. 当前要爬取的 url
      2. 最大深度
      3. 当前使用的 aiohttp.ClientSession 实例
      4. 已访问过的链接集合以及当前的深度
  4. 函数首先判断是否达到了最大深度或者已经访问过该链接
    1. 如果满足其中任意一个条件,则直接返回。
    2. 否则,将该链接添加到已访问过的集合中,然后获取该页面中的所有链接,使用递归的方式异步爬取其中的页面
      以下是另一种异步爬虫的示例代码:
import asyncio
import aiohttp
from bs4 import BeautifulSoup


# 在 fetch 中实现对 html 的访问和下载
async def fetch(url, session):
    """
    异步获取指定url的页面内容
    """
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 Edge/16.16299",
        "Referer": "https://www.google.com/"
    }
    async with session.get(url, headers=headers) as response:
        return await response.text()


# 解析当前页面的所有 href
async def parse_links(url, session):
    """
    异步解析页面内容,获取其中的所有链接
    """
    html = await fetch(url, session)

    soup = BeautifulSoup(html, 'lxml')

    links = []

    for link in soup.find_all('a'):
        links.append(link.get('href'))

    print(soup.select("head > title")[0].get_text())

    return links


async def crawl(url, max_depth, session, seen_urls, depth=0):
    """
    递归地异步爬取指定网站的所有页面,直到达到最大深度或所有页面都被访问过为止
    """
    if depth == max_depth:
        return

    # 避免重复访问同一个链接
    if url in seen_urls:
        return

    seen_urls.add(url)

    # 获取页面中的所有链接
    links = await parse_links(url, session)

    # 递归地爬取链接中的页面
    tasks = []

    for link in links:
        try:
            if link.startswith('http'):
                task = asyncio.ensure_future(crawl(link, max_depth, session, seen_urls, depth + 1))
                tasks.append(task)
        except BaseException:
            continue

    await asyncio.gather(*tasks)


async def main():
    """
    程序入口,异步启动爬虫
    """
    async with aiohttp.ClientSession() as session:
        seen_urls = set()
        await crawl('https://movie.douban.com/top250', 2, session, seen_urls)


if __name__ == '__main__':
    asyncio.run(main())

流程

  1. 运行协程事件循环
  2. 入口main函数,利用aiohttp创建clientsession对象,传入spider,让spider爬行
  3. 爬行:获取当前网页里面包含的所有地址链接href
    1. 判断当前传入地址是否已经访问过,否则加入 seen_urls 集合中
    2. 获取新地址:利用ClientSession 实例发起请求,得到html
    3. 获取新地址:解析html,findall标签<a>
    4. 提取出标签里面的href属性,添加到links数组返回
  4. 爬行:遍历当前所有链接,将链接创建为任务,加入task列表
  5. 爬行:gather运行所有协程任务
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值