【python爬虫】重温西游——异步获取名著《西游记》思路,代码及优化

提示:本篇代码分为基础代码和优化代码


前言

在这里插入图片描述

为什么《黑神话:悟空》这么火?首先是品质过硬,据了解,这款游戏研发周期在6年左右,每小时游戏时长开发成本超过2000万元;其次是依托《西游记》这一强大文化IP,国风元素满满;更深层的原因,则是满足了无数玩家对国人开发3A级别游戏的渴望,填补了长久以来国产3A级别单机游戏的空白。

本篇文章将通过异步操作深入获取《西游记》的全部内容,在练习代码的同时,我们可以借助阅读重温这部名著的文化精髓。


提示:以下是本篇文章正文内容,下面内容可供参考

一、异步操作及相关库安装

在传统的同步编程中,每个任务都是按照顺序依次执行的。如果一个任务需要等待一些耗时的操作(如网络请求或文件读取),那么整个程序将会被阻塞,导致其他任务无法执行。而异步编程则可以在等待某些任务的同时,继续执行其他任务,从而充分利用系统资源,提高程序的性能。asyncio是Python用于解决异步IO编程的标准库之一,它利用事件循环和协程使得异步编程更加直观和易于理解。

1.1基本概念

异步函数 (async def):
使用 async def 定义异步函数。
异步函数返回一个协程对象,通常需要用 await 关键字来调用异步函数。
协程 (asyncio 库):
协程是可挂起的函数,可以在它执行的过程中让出控制权给其他协程。
asyncio 是 Python 的标准库,用于编写异步代码。
await 关键字:
用于暂停协程的执行,直到某个异步操作完成。
只能在异步函数中使用。
事件循环 (asyncio 的事件循环):
负责调度和管理协程的执行。

1.2 aiohttp,aiofiles介绍及配置

1.2.1 aiohttp库

aiohttp 是一个用于在 Python 中进行异步 HTTP 请求的库。它支持异步 HTTP 客户端和服务器功能,基于 asyncio 实现。通过 aiohttp,你可以在异步编程环境中高效地处理 HTTP 请求和响应。

1.2.2 aiofiles库

aiofiles是一个Python库,它提供了异步文件操作的功能,基于Python的asyncio库。 通过使用aiofiles,我们可以在异步程序中进行文件的读取、写入和操作,而不会阻塞事件循环。 这对于需要处理大量文件或需要与其他异步操作结合的场景非常有用。

1.2.3安装第三方库

在pycharm终端使用pip命令即可安装:

pip install aiohttp
pip install aiofiles

二、思路及代码

1.思路

1.1 分析网页

如下:
1.先找到百度小说《西游记》初始页面的内容:
在这里插入图片描述
进入百度小说中《西游记》对应网页,进入开发者模式,左侧小说页面点击查看全部,右侧抓包工具将接到响应。
在这里插入图片描述
接着,我们点击响应,这里我们可以看到本书的所有章节。title,cid这些数据我们需要获取。
在这里插入图片描述

2.进入第一回章节内容页面:我们需要这个url。
在这里插入图片描述
继续点击响应可以找到“content”,这里是本回的文本内容。
在这里插入图片描述

1.1.2 代码逻辑

1.对初始页面进行requests相关操作,获取“title”,“cid”这些数据
2.对小说每一回页面进行异步asyncio对应操作,获取“content”信息。
3.处理url格式,编写对应方法并调用

2.基础代码

代码如下(示例):

import asyncio
import aiofiles
import aiohttp
import requests
import json


async def getCatalog(url):
    resp = requests.get(url)
    dic = resp.json()
    tasks = []
    for item in dic['data']['novel']['items']:
        title = item['title']
        cid = item['cid']
        tasks.append(aiodownload(b_id, cid, title))
        # Python3.8版本后摒弃了await asyncio.wait(tasks)
    await asyncio.gather(*tasks)


async def aiodownload(b_id, cid, title):
    # https://dushu.baidu.com/api/pc/getChapterContent?data={%22book_id%22:%224306063500%22,%22cid%22:%224306063500|1569782244%22,%22need_bookinfo%22:1}
    # %22 %22 替换为 “”,data 用字典表示更方便
    data = {"book_id": b_id,
            "cid": f"{b_id}|{cid}",
            "need_bookinfo": 1}
    data = json.dumps(data)
    url = f"https://dushu.baidu.com/api/pc/getChapterContent?data={data}"
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as resp:
            dic = await resp.json()
            async with aiofiles.open(title, "w",encoding="utf-8") as f:
                await f.write(dic["data"]["novel"]["content"])


if __name__ == '__main__':
    b_id = "4306063500"
    url = 'https://dushu.baidu.com/api/pc/getCatalog?data={"book_id":' + b_id + '}'
    asyncio.run(getCatalog(url))

2.1运行结果展示

在这里插入图片描述


三、探讨——代码优化

该代码有很多优化空间,我们主要针对以下两各方面进行代码优化:

1.顺序性

因为是异步爬取,所以得到的章回列表是乱序的,但我们可以在aiodownload方法内按照cid大小进行动态排列。
在这里插入图片描述

2.规范性

为了规范操作,我们将爬取的信息以txt文件存入文件夹(注意将文件设置为excluded),另外我们规定txt文件每行信息的长度,以便于提升阅读体验。这些优化均在aiodownload方法中进行(详情见优化代码)
在这里插入图片描述
规范后的小说文件列表以及txt文件展示:
在这里插入图片描述

3.优化代码

这里我们引入了os库方便设置文件存放路径,优化在aiodownload方法中,包括:

1:设置文件path,以cid大小顺序排列章回列表
2:设定每行最大长度,便于读者阅读txt内容

import asyncio
import aiohttp
import requests
import json
import aiofiles
import os


async def aiodownload(cid, b_id, title):
    data = {
        "book_id": b_id,
        "cid": f"{b_id}|{cid}",
        "need_bookinfo": 1
    }
    data = json.dumps(data)
    url = f'https://dushu.baidu.com/api/pc/getChapterContent?data={data}'
    # 优化:设置文件path,以cid大小顺序排列章回列表
    file_path = os.path.join("novel", f"{cid}-{title}.txt")
    
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as resp:
            dic = await resp.json()
            content = dic["data"]["novel"]["content"]
# 优化:设定每行最大长度,便于读者阅读txt内容
            # 设置每行的最大长度
            max_line_length = 80

            # 分割长字符串为固定长度的行
            lines = [content[i:i + max_line_length] for i in range(0, len(content), max_line_length)]

            # 将分割后的行写入文件
            async with aiofiles.open(file_path, mode='w', encoding="utf-8") as f:
                for line in lines:
                    await f.write(line + '\n')


async def getCatalog(url):
    resp = requests.get(url)
    dic = resp.json()
    tasks = []
    for item in dic["data"]["novel"]["items"]:
        title = item["title"]
        cid = item["cid"]
        # 不用async修饰也可以用 asyncio.run(asyncio.wait(tasks))
        tasks.append(aiodownload(cid, b_id, title))
    await asyncio.gather(*tasks)


if __name__ == '__main__':
    b_id = "4306063500"
    url = 'https://dushu.baidu.com/api/pc/getCatalog?data={"book_id":"' + b_id + '"}'
    asyncio.run(getCatalog(url))

总结

本篇内容介绍了异步爬取的相关知识,并深入讲解了异步爬取《西游记》完整内容的思路、操作步骤、及代码优化。代码仍有优化空间,读者可以借助本篇内容巩固爬虫异步操作的知识。
参考链接:Python标准库asyncio官方文档

  • 10
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值