24. 实战:用异步法获取完整的一部小说

目录

前言                URL(在评论区)URL(在评论区)URL(在评论区)URL(在评论区)

目的                URL(在评论区)URL(在评论区)URL(在评论区)URL(在评论区)

思路                URL(在评论区)URL(在评论区)URL(在评论区)URL(在评论区)

代码实现

1. 尝试获取小说内容的URL(在评论区)

2. 查看页面源代码

3. 抓包工具登场

4.  开始写代码,先捋清思路

5. 完善getCatalog函数

6. 完善aiodownload函数

完整代码

运行效果

总结


前言

我们已经学会了异步爬虫的框架和简单的示例,详见23. 异步HTTP请求与aiohttp模块

本节我们通过一个实战来巩固异步爬虫的用法:抓取整部小说的内容。


目的

利用异步爬虫高效爬取整部小说


思路

  1. 获取小说内容的url
  2. 获取网页数据
  3. 保存到本地

代码实现

1. 尝试获取小说内容的URL(在评论区)

打开网页(网页链接放评论区了!!!),发现目录等内容,点击章节就能跳转到对应内容中。我们先检查页面源代码查看数据是否在源代码中。

2. 查看页面源代码

可以看到源代码才不到30行,我们的数据肯定不在这里面...

那我们只能祭出F12大法:抓包工具登场。

3. 抓包工具登场

切换到网络——Fetch/XHR——刷新页面就得到了这三个动态请求。打开getCatalog(获取目录),点击预览,就能看到一大堆名称了,这就是我们要拿的所有章节名称和它的id了。但是内容还没有出现。

切换到下一个getChapterContent(获取章节内容),打开果然发现了文本!这就是我们要的内容。

最后切换到标头,就能获取到我们的目标URL和请求方式等信息。

请求方式:

GET

4.  开始写代码,先捋清思路

"""
1. 同步操作: 访问getCatalog 拿到所有章节的cid和名称
2. 异步操作: 访问getChapterContent 下载所有的文章内容
"""

我们得到的URL最后有一堆“乱码”,但其实我们发现还是有规律的。一般URL后面都会加问号和属性加属性值。但我们现在这个URL不走寻常路,但是仔细观察里面有一堆“%22”,它是什么呢?

其实,它就是ASCII码中的双引号。参阅百度百科。它包含着URL所需要的参数。

思路明确以后先画出一个框架:

async def aiodownload(cid, b_id, title):
    pass


async def getCatalog(url):
    pass


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

5. 完善getCatalog函数

async def getCatalog(url):
    resp = requests.get(url)
    dic = resp.json()
    tasks = []
    for item in dic['data']['novel']['items']:  # item就是对应每一个章节的名称和cid
        title = item['title']
        cid = item['cid']
        # 准备异步任务
        tasks.append(aiodownload(cid, b_id, title))
    await asyncio.wait(tasks)

先把返回值转为json数据,然后从中提取title和cid两项属性,然后把参数传入aiodownload函数。

(中间调试程序、打印出json数据内容、一层层找到要的属性就不多讲了)

6. 完善aiodownload函数

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"http://dushu.????.com/api/pc/getChapterContent?data={data}"

    async with aiohttp.ClientSession() as session:
        async with session.get(url) as resp:
            dic = await resp.json()
            chapter = dic['data']['novel']['chapter_index']
            async with aiofiles.open(f"./Novel_Journey_to_the_West/{chapter}_{title}", mode="w", encoding="GB18030") as f:
                await f.write(dic['data']['novel']['content'])  # 把小说内容写出

我们观察目标URL发现,它需要传入的数据有三项,分别是book_id、cid、need_bookinfo。

这里我们的数据是字典形式,但是我们要想写到URL中就必须转为字符串形式,就要用到dumps这个接口。查看官方文档:

Serialize ``obj`` to a JSON formatted ``str``

它的含义就是把json数据转换为合规的字符串形式。

为了防止输入以后还是乱序,我们再拿出一个chapter_index这个属性,它是数字形式的顺序,这样就可以放在文件名开始,下载完成按名称排序就能按顺序了!


完整代码

import requests
import asyncio
import aiohttp
import aiofiles
import json

"""
1. 同步操作: 访问getCatalog 拿到所有章节的cid和名称
2. 异步操作: 访问getChapterContent 下载所有的文章内容
"""


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"http://dushu.????.com/api/pc/getChapterContent?data={data}"

    async with aiohttp.ClientSession() as session:
        async with session.get(url) as resp:
            dic = await resp.json()
            chapter = dic['data']['novel']['chapter_index']
            async with aiofiles.open(f"./Novel_Journey_to_the_West/{chapter}_{title}", mode="w", encoding="GB18030") as f:
                await f.write(dic['data']['novel']['content'])  # 把小说内容写出


async def getCatalog(url):
    resp = requests.get(url)
    dic = resp.json()
    # print(dic)
    tasks = []
    for item in dic['data']['novel']['items']:  # item就是对应每一个章节的名称和cid
        title = item['title']
        cid = item['cid']
        # 准备异步任务
        tasks.append(aiodownload(cid, b_id, title))
    await asyncio.wait(tasks)


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

运行效果


总结

本节我们学习了异步爬虫的实战,爬取了一整本小说(这里我以西游记为例,大家可以自己爬点别的,换URL就行了)。下面我们将学习视频的抓取(m3u8格式)。

  • 6
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 7
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Vec_Kun

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值