jasony0 发表于 2021-12-4 19:22

异步加速爬取小说

### 用python爬取小说在同步状态下,下载缓慢,所以用asynio/await写了一个异步的爬取(仅用于学习!)
1. 获取各章节的网址和题目(从12开始取值是为了过滤掉最新章节对顺序的影响,包括**xpath的值**,具体需要对网页结构进行分析,**不能直接套用**)
```
async def get_link(url):
    req = requests.get(url, headers=HEADERS)
    req.encoding = 'gbk'
    Xpath = parsel.Selector(req.text)
    links = Xpath.xpath('/html/body/div/dl/dd/a/@href').extract()
    full_links =
    names = Xpath.xpath('/html/body/div/dl/dd/a/text()').extract()
    name_list =
    name_link = zip(full_links, name_list)
    async with httpx.AsyncClient() as client:
      task = []
      for link, name in name_link:
            task.append(get_text(client, name, link))
      await asyncio.wait(task)
    save_text(name_list)
```
> 这其中使用httpx异步请求,可以加快访问各章节的速度
> 然后将各章节任务添加到任务队列中,交由asynio处理

2. 各章节任务就是获取章节内容,然后保存即可。但是由于asynio的任务的处理是无序的,所有使用一个字典进行缓存返回内容,在缓存完毕时,将字典内容写入到txt中。
```
async def get_text(client, name, link):
    req = await client.get(link, headers=HEADERS, timeout=None)
    html = etree.HTML(req.text)
    text = html.xpath('//*[@id="content"]/text()')
    await save_text_dic(name, text[:-2])
```

3.这个地方最好边缓存边写入,类似与生产者消费者,才疏学浅,没有实现思路)
```
async def save_text_dic(name, texts):
    # TODO:边缓存边写入
    dic = texts
```

4.将字典中内容按照爬取的顺序写入即可。
```
def save_text(name_list):
    # 文件目录
    path = ""
    if not os.path.exists(path):
      os.mkdir(path)
                                #小说名
    f = open(f'{path}/小说名.txt', 'a', encoding='utf-8')
    # async with open(f"./result/{name}.txt", 'w', encoding="utf-8") as f:
    for name in track(name_list):
      f.write(name)
      f.write('\n\n')
      for text in dic:
            # print(text)
            f.write(text)
            f.write('\n\n')
      f.write('\n')
```

5.最后主函数和一些类变量(偷懒没有将所有函数写在类中)
```
#用于拼接章节网址的基础网址
BASEURL = ""
#字典声明
dic = {}
```
```
if __name__ == '__main__':
    #具体某本小说的网址
    url = ''"
    loop = asyncio.get_event_loop()
    loop.run_until_complete(get_link(url))
```

---
写的很简陋,主要是为了学习一下异步和协程。
与同步下载相比,确实快了许多,但是会偶尔因为httpx的连接超时导致中断,想排查的时候结果成功了==

jasony0 发表于 2021-12-5 22:45

本帖最后由 jasony0 于 2021-12-5 22:48 编辑

我是在服务器上运行的,在本地运行可能由于请求过于密集过快被拒绝。如果遇到可以反馈一下,共同学习!
将项目里用到的文件打包出来,运行时保存小说的路径需要按情况调整,其他的文件名按需调整即可。
如果引入tools下的header失败,最简单处理就是将tools下的代码复制到主文件中:lol(由于我是在最外层目录运行的主文件,所以主文件中写的路径是在我环境终的路径,具体需要按需调整)
在调试时最好不要过密集的发起请求,对他人服务器造成损失。{:1_893:}

lykenan 发表于 2021-12-5 08:19

学习了感谢分享

88668921 发表于 2021-12-5 08:23

学习了感谢分享,如果有成品更好:lol

Asy_少洋 发表于 2021-12-5 10:17

这么多段代码,咋样的,小白迷惑

jasony0 发表于 2021-12-5 22:47

Asy_少洋 发表于 2021-12-5 10:17
这么多段代码,咋样的,小白迷惑

可以看一下我新回复的文件{:1_896:}

Asy_少洋 发表于 2021-12-6 09:18

jasony0 发表于 2021-12-5 22:47
可以看一下我新回复的文件

在哪里,没看到呀,大佬

jasony0 发表于 2021-12-6 15:11

Asy_少洋 发表于 2021-12-6 09:18
在哪里,没看到呀,大佬

我置顶了,第一条评论就是
页: [1]
查看完整版本: 异步加速爬取小说