多线程爬虫----批量下载小说,实现小说自由

在上一个案例中实现了单线程爬取整本小说,这里给大家展示一下多线程爬取下载小说,可以大大提升下载速度,主要代码修改也简单。

先简单理解一下什么是多线程爬虫:一种高效的网络爬虫实现方式,通过并发执行多个任务,可以显著提高爬取效率。

这是代码示例:

import requests
import re
import os
import time

import concurrent.futures
# 导入线程池模块
def get_response(html_url):
    """
    :param html_url: 请求链接
    :return: 响应数据
    """
    headers = {
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36 Edg/134.0.0.0',
    }
    print(f"Attempting to access URL: {html_url}")
    try:
        response = requests.get(url=html_url, headers=headers, timeout=10)
        response.raise_for_status()  # 如果响应状态码不是200,将引发HTTPError异常
        return response
    except requests.exceptions.RequestException as e:
        print(f"Error accessing URL {html_url}: {e}")
        return None


def get_url_list(html_url):
    """
    :param html_url: 小说目录页
    :return: 章节链接列表和书名
    """
    response = get_response(html_url)
    if response is None:
        return [], ""

    html_data = response.text
    url_list = re.findall(r'<dd><a href ="(.*?)">', html_data)
    book_name = re.findall(r'<h1>(.*?)</h1>', html_data)
    if book_name:
        book_name = book_name[0]
    else:
        book_name = "Unknown"
    return url_list, book_name


def get_content(html_url):
    """
    :param html_url: 章节链接
    :return: 章节标题和内容
    """
    response = get_response(html_url)
    if response is None:
        return "", ""

    html_data = response.text
    title = re.findall(r'<h1 class="wap_none">(.*?)</h1>', html_data)
    text = re.findall(r'<div id="chaptercontent" class="Readarea ReadAjax_content">(.*?)</div>', html_data, re.DOTALL)

    if title and text:
        title = title[0]
        text = text[0]
        text = re.sub(r'<br /><br /> ', '\n', text)
        text = re.sub(r'<p class="readinline">.*?</p>', '', text, flags=re.DOTALL)
        print(f"成功获取内容: {title}")
        return title, text
    else:
        print(f"未能从指定链接中提取标题或内容{html_url}")
        return "", ""


def save_content(book_name, title, text):
    """
    :param book_name: 书名
    :param title: 章节标题
    :param text: 章节内容
    """
    file_path = f'{book_name}\\'
    if not os.path.exists(file_path):
        os.makedirs(file_path)

    filename = f"{title}.txt"

    with open(file_path + filename, mode='w', encoding='utf-8') as file:
        file.write(title)
        file.write('\n')
        file.write(text)
        file.write('\n')
    print(f"{title} 下载完成")


def main(home_url):


    title, text = get_content(html_url=home_url)
    save_content(book_name=book_name, title=title, text=text)
    time.sleep(1)  # 添加延迟,避免请求过于频繁


if __name__ == '__main__':
    url = 'https://www.qu05.cc/html/43958/'
    url_list, book_name = get_url_list(html_url=url)
    exe= concurrent.futures.ThreadPoolExecutor(max_workers=7)
    for url in url_list:
        index_url  = 'https://www.qu05.cc' + url
        exe.submit(main,index_url)
        time.sleep(1)
    exe.shutdown()


接下来是一些代码流程解释,方便各位新手理解代码

1.get_response这个函数作用是发送请求获取响应,这里的html_url参数会被调用的那个函数传入

2.get_url_list函数---先调用.get_response获取响应再提取响应里的章节链接列表

3..get_content函数提取每个章节链接里的标题和文本

4..save_content函数创建以小说名字为名称的目录并保存数据

5.main函数---获取标题和文本,调用save_content函数保存数据。

大致流程就这些,代码与单线程的主要区别是添加了一个线程池模块并将线程最大数量设置为7。

相比于单线程,多线程在获取数据的速度得到了很大的提升

结果展示:

也许在这里看不出爬取的速度,大家可以自己复制代码实验一下,它与单线程相比速度以及大大提升了,这里理解之后就方便实现多本小说的爬取了 。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值