前言:最近在找一本小说,能在盗版网站上观看,但是体验不佳,于是就有了将网页上的小说内容爬取到本地的想法。刚开始是单线程爬取小说(代码量少,逻辑简单(好吧,是我懒o.O)),后来发现爬个1千多章要差不多10分钟,头皮发麻。于是研究了一下多线程,结果速度是起飞了,但是内容被拆分成了每一个txt文件,且顺序不定(看线程心情的~~(lll¬ω¬)),这怎么看!!((╯‵□′)╯︵┻━┻),于是...↓
正文:欸!老师!(超大声!ฅ>_<)我有个点子! (๑•̀ㅂ•́)و✧)windows系统中文件夹会根据文件名称进行排序,那不妨在保存每一章内容时以章节所在列表的下标来命名(章节列表从网站上爬取下来是有序的),然后使用工具将这些txt文件合并为一个txt文件。马上附上代码和工具!!! ฅ(๑ ̀ㅅ ́๑)ฅ
import requests
import parsel
import os
from concurrent.futures import ThreadPoolExecutor
# 创建Novel类
class Novel:
def __init__(self, url, headers):
self.home_url = url
self.headers = headers
# 获取选择器
def get_selector(self, url, headers):
response = requests.get(url, headers=headers)
response.encoding = 'utf-8'
response = response.text
selector = parsel.Selector(response)
return selector
# 获取小说名称
def get_novel_name(self):
html_selector = self.get_selector(self.home_url, self.headers)
# xpath路径要自己动手喔ฅฅ*~
novel_name = html_selector.xpath('').get()
return novel_name
# 获取小说章节url的id
def get_chapter_ids(self):
html_selector = self.get_selector(self.home_url, self.headers)
# xpath路径要自己动手喔ฅฅ*~
chapter_ids = html_selector.xpath('').getall()
return chapter_ids
# 获取小说章节名和内容
def get_title_content(self, url):
html_selector = self.get_selector(url, self.headers)
# xpath路径要自己动手喔ฅฅ*~
title = html_selector.xpath('').get()
content = html_selector.xpath('').getall()
content = '\n'.join(content)
return title, content
# 保存小说
def save(self, url, chapter_index, save_path):
title, content = self.get_title_content(url)
print(title + '保存中...')
# chapter_index:04这是将下标格式化,为了方便后续使用工具进行合并
# 比如这时的chapter_index为1,那么格式化后就是0001
with open(f'{save_path}\\{chapter_index:04} {title}.txt', 'w', encoding='utf-8') as f:
f.write(title)
f.write('\n')
f.write(content)
f.write('\n')
print(title + '保存完毕')
if __name__ == '__main__':
# 模拟浏览器
# Cookie和User-Agent要自己动手喔ฅฅ*~
headers = {
'Cookie': '',
'User-Agent': ''
}
# 目录页url
home_url = ''
# 实例化一个novel对象
novel = Novel(home_url, headers)
novel_name = novel.get_novel_name()
chapter_ids = novel.get_chapter_ids()
# 创建一个以小说名命名的文件夹,用于保存全部小说章节
os.makedirs(f'{novel_name}', exist_ok=True)
# 设置保存路径
save_path = novel_name + '\\'
# 线程池中的线程数量请根据个人设备进行调整
with ThreadPoolExecutor(max_workers=100) as executor:
for link in chapter_ids:
# 保存该章节的下标
chapter_index = chapter_ids.index(link) + 1
# 章节url的组合需根据具体网页地址进行分析>.<
link = home_url + link
# 使用匿名函数传入多个参数
executor.submit(lambda p:novel.save(*p), (link, chapter_index, save_path))
print(f'{novel_name}保存完毕,共{len(chapter_ids)}章,( ๑╹ ꇴ╹) グッ~~拜拜')
工具:工具-合并多个txt文件