Python-多线程下载小说《校花的贴身高手》

有关于多线程、生产者与消费者设计模式,可以参考我写的另一篇博客:Python-多线程及生产者与消费者

本文仅供学习使用,请勿做出其他不当行为!!!

一、步骤分析

'''
    1. 获取主页页面源码【生产内容】
    2. 解析出所有章节的链接【生产内容】
    3. 获取每一章节的页面源码【生产内容】
    4. 解析出每一章的正文【生产内容】
    5. 下载内容【消费内容】
'''

二、代码

  • 仅设置了两个子线程:生产者线程、消费者线程
  • 如果有错误的地方,欢迎指出,谢谢
import datetime
import os
from queue import Queue
from threading import Thread
import requests
import re
import time
from requests import RequestException
from lxml import etree


# 返回所有章节的链接
def getUrls():
    try:
        # 1. 提供url
        url = 'https://www.soxscc.org/JiuXueLang/'
        # 2. 提供url的参数
        data = {}
        # 3. 提供请求头
        headers = {
            'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36',
        }
        # 4. 提供代理池
        proxise_pool = None
        # 5. 发送请求,获取响应数据
        response = requests.get(url=url, data=data, headers=headers)
        # 6. 设置响应数据的编码格式
        response.encoding = 'utf-8'
        # 7. 获取数据
        con = response.text
        # 8. 处理数据
        urlList = re.finditer(r'<dd><a href="/JiuXueLang/\d+.html">第\d+章.*</a></dd>', con)
        se = set()
        for url in urlList:
            title = re.findall(r'html">(.*?)</a></dd>', url.group())[0]
            url = 'https://www.soxscc.org' + re.sub(r'">第\d+章.*</a></dd>', '',
                                                    url.group().replace(r'<dd><a href="', ''), 1)
            se.add(title + "::" + url)
        urlList = list(se)
        # 9. 打印提示信息
        print('链接提取完成' + '总共提取到:' + str(len(urlList)))
        print('休息5秒\t')
        t = 5
        while t:
            print('还有{}秒\t'.format(t) + '==' * t)
            time.sleep(1)
            t -= 1
        print('休息时间到,开始提取每一章节的内容\n\n')
        # 10. 返回结果
        return urlList
    except RequestException:
        print('出错部分:提取所有章节的链接')


# 根据url,返回对应的文本
def getCount(urlAndTitle):
    # 1. 提供url、标题
    title = urlAndTitle.split('::')[0]
    url = urlAndTitle.split('::')[1]
    try:
        # 2. 提供url的参数
        data = {}
        # 3. 提供请求头
        headers = {
            'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36',
        }
        # 4. 提供代理池
        proxise_pool = None
        # 5. 发送请求,获取响应数据
        response = requests.get(url=url, data=data, headers=headers)
        # 6. 设置响应数据的编码格式
        response.encoding = 'utf-8'
        # 7. 获取数据
        con = response.text
        # 8. 处理数据
        tree = etree.HTML(con)
        id = re.search(r'\d+', tree.xpath('//body/@id')[0]).group()
        con = tree.xpath('//div[@id="con{}"]/text()'.format(id))
        con.pop(0)
        con.insert(0, title)
        # 9. 打印提示信息
        print('==========================================生产者')
        print('{} 的内容已成功获取到\n\n'.format(title))
        # 10. 返回结果
        return con
    except RequestException:
        print('出错部分:获取章节《{}》'.format(title))


# 生产文本内容,添加到队列中
def produceCotent(q):
    urlLists = getUrls()
    for urlAndTitle in urlLists:
        content = getCount(urlAndTitle=urlAndTitle)
        q.put(content)
    pass


# 消费每一章的内容
def consumerContent(content):
    title = content[0]
    with open('data\\{}.txt'.format(title), 'w', encoding='utf-8') as fp:
        fp.write('\t===={}====\n\n\n'.format(title))
        content.pop(0)
        for part in content:
            fp.write(part)
    print('==========================================消费者')
    print('{} 下载成功\n\n'.format(title))
    pass


# 生产者
def produce(q):
    produceCotent(q)
    q.join()


# 消费者
def consumer(q):
    if not os.path.exists('.\\校花的贴身高手'):
        print('目录不存在,创建目录成功!!!')
        os.mkdir('.\\校花的贴身高手')
    else:
        print('目录已存在,不用创建,继续执行下面的内容')
    while True:
        content = q.get()
        consumerContent(content)
        q.task_done()


# 主进程
def main():
    q = Queue()
    pro = Thread(target=produce, args=(q,))
    con = Thread(target=consumer, args=(q,))

    con.setDaemon(True)

    pro.start()
    con.start()

    pro.join()
    print('结束了')


if __name__ == '__main__':
    main()

三、参考

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值