有关于多线程、生产者与消费者设计模式,可以参考我写的另一篇博客: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()