四时宝库

程序员的知识宝库

Python 进阶-Day 13:常用第三方库(异步爬虫)

目标

  • 掌握异步请求库 aiohttp,实现并发网络请求。
  • 使用 beautifulsoup4 解析网页数据。
  • 结合 aiofiles 实现异步文件保存,提升效率。
  • 完成一个异步网页爬虫项目,爬取多页名言并保存到文件。

知识点讲解

1. 异步请求:aiohttp

aiohttp 是 Python 的异步 HTTP 客户端/服务器框架,适合高并发网络请求。

  • 核心方法: aiohttp.ClientSession():创建会话,管理请求。 session.get(url):异步发送 GET 请求。 response.text():异步获取响应内容。
  • 异步优势: 并发处理多个请求,减少等待时间。 适合爬取多页或多网站。
  • 注意事项: 使用 async/await 语法。 确保正确关闭会话以释放资源。

2. beautifulsoup4:解析网页

与同步版本相同,beautifulsoup4 用于解析 HTML。

  • 解析过程仍是同步的,但结合异步请求可整体提速。
  • 核心操作:find_all() 提取目标元素,text 获取内容。

3. 异步文件保存:aiofiles

aiofiles 支持异步文件操作,避免阻塞主线程。

  • 核心方法: aiofiles.open(file, mode):异步打开文件。 异步写入:使用 await file.write()。
  • 优势: 与异步请求配合,保持全程非阻塞。 适合高并发场景下的数据保存。

4. 异步爬虫优化

  • 并发控制:使用 asyncio.gather 并行处理多个请求。
  • 异常处理:捕获异步请求和解析错误,确保程序健壮。
  • 礼貌爬虫:限制并发数量(如最大 5 个),避免压垮服务器。

代码示例

项目:异步爬取名言网站多页数据

我们将爬取
http://quotes.toscrape.com/ 的前 3 页名言和作者信息,异步保存到 CSV 文件。

python

import aiohttp
import aiofiles
import asyncio
from bs4 import BeautifulSoup
import csv
from typing import List, Dict

async def fetch_page(session: aiohttp.ClientSession, url: str) -> str:
    """异步获取网页内容"""
    try:
        async with session.get(url) as response:
            if response.status != 200:
                print(f"请求失败:{url},状态码:{response.status}")
                return ""
            return await response.text()
    except aiohttp.ClientError as e:
        print(f"请求错误:{url},{e}")
        return ""

async def parse_quotes(html: str) -> List[Dict[str, str]]:
    """解析网页中的名言数据"""
    if not html:
        return []

    soup = BeautifulSoup(html, 'html.parser')
    quotes = soup.find_all('div', class_='quote')

    data = []
    for quote in quotes:
        try:
            text = quote.find('span', class_='text').text.strip()
            author = quote.find('small', class_='author').text.strip()
            data.append({'text': text, 'author': author})
        except AttributeError as e:
            print(f"解析错误:{e}")
    return data

async def save_to_csv(data: List[Dict[str, str]], filename: str):
    """异步保存数据到 CSV 文件"""
    if not data:
        print("无数据保存")
        return

    async with aiofiles.open(filename, 'w', newline='', encoding='utf-8') as file:
        writer = csv.DictWriter(file, fieldnames=['text', 'author'])
        await file.write('\\ufeff')  # 添加 BOM 以确保 Excel 兼容 UTF-8
        await writer.writeheader()
        for item in data:
            await writer.writerow(item)
    print(f"数据已保存到 {filename}")

async def crawl_quotes(pages: int = 3):
    """主函数:爬取多页名言数据"""
    base_url = "<http://quotes.toscrape.com/page/{}/>"
    urls = [base_url.format(i) for i in range(1, pages + 1)]

    async with aiohttp.ClientSession() as session:
        # 并发获取所有页面
        tasks = [fetch_page(session, url) for url in urls]
        htmls = await asyncio.gather(*tasks, return_exceptions=True)

        # 解析所有页面数据
        all_data = []
        for html in htmls:
            if isinstance(html, str):
                data = await parse_quotes(html)
                all_data.extend(data)

        # 异步保存数据
        await save_to_csv(all_data, 'quotes_async.csv')

def main():
    """同步入口"""
    asyncio.run(crawl_quotes(pages=3))

if __name__ == "__main__":
    main()

代码运行结果

  • 运行后,生成 quotes_async.csv,包含前 3 页的名言数据,格式如下:csv
  • text,author "The world as we have created it is a process of our thinking. It cannot be changed without changing our thinking.","Albert Einstein" ...
  • 控制台输出示例:
  • 数据已保存到 quotes_async.csv
  • 异步请求显著减少总耗时(多页并行处理)。

代码解析

  1. 异步请求: fetch_page:使用 aiohttp.ClientSession 异步获取网页内容。 asyncio.gather:并发执行多个页面请求。
  2. 数据解析: parse_quotes:使用 BeautifulSoup 解析 HTML,提取名言和作者。 保持与同步版本一致的逻辑,但处理空响应。
  3. 异步保存: save_to_csv:使用 aiofiles 异步写入 CSV。 添加 BOM(\ufeff)确保 Excel 正确识别 UTF-8。
  4. 主逻辑: crawl_quotes:协调请求、解析和保存,爬取指定页数。 使用 ClientSession 管理会话,确保资源释放。
  5. 异常处理: 捕获网络错误(aiohttp.ClientError)。 处理解析错误(AttributeError)和空数据。

课后练习

  1. 基础练习: 修改代码,提取每条名言的标签(div.tags a.tag),并保存到 CSV。 将保存格式改为 JSON(使用 aiofiles 异步写入)。
  2. 进阶练习: 添加并发限制(使用 asyncio.Semaphore,最大 5 个并发)。 动态检测总页数(解析分页导航,如 li.next)。
  3. 挑战练习: 扩展为爬取其他公开练习网站(如 http://toscrape.com/ 的书籍数据)。 使用 pandas 异步将数据转为 Excel(结合 pandas.to_excel)。

注意事项

  • 异步语法:确保熟悉 async/await,避免阻塞操作。
  • 服务器压力:大规模爬取时,建议添加延迟或并发限制。
  • 调试技巧:打印响应内容或解析结果,检查数据完整性。
  • 扩展学习: 探索 scrapy 与异步结合。 学习 httpx,另一个异步 HTTP 库。

性能对比(示例)

  • 爬取 3 页: 同步版:约 3-6 秒(取决于网络)。 异步版:约 1-2 秒(并发处理)。
  • 异步版在页面数增加时优势更明显。

如果需要进一步优化(如添加并发限制、动态分页或处理动态网页),请告诉我!

发表评论:

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言
    友情链接