"""
将就看看吧,写太详细了过不了QAQ
本网站的文件是直接写在页面上的
尝试将线程池和协程连起来用
1.找到章节下载链接
2.下载小说文本(协程异步下载)
3.存放文件
4.执行分页
"""
import os
import requests
import asyncio
import aiohttp
import aiofiles
import time
from bs4 import BeautifulSoup
from concurrent.futures import ProcessPoolExecutor, ThreadPoolExecutor
header={
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36",
"Referer":"https://www.bbiquge.net/"
}
global name # 定义全局变量,用来保存书籍名字方便文件的分类
# 下载小说内容,异步操作下载
async def dowload(down_url):
async with aiohttp.ClientSession() as session:
async with session.get(down_url) as resp:
data = await resp.read()
res = BeautifulSoup(data,"html.parser").find('div',attrs={'id':'content'}).text # 获取文本内容
ress = BeautifulSoup(data,"html.parser").find('h1').text # 获取小说章节名字
print(ress+'下载中')
file_path = f'../file/小说/{name}/{ress}.txt' # 设置保存的路径和文件名及文件格式,这里用的是相对路径
async with aiofiles.open(file_path,'w',encoding='utf-8') as f: # aiofiles 异步文件操作
await f.write(res)
print(ress+'下载完成')
# 传入的是每页的链接,获取章节下载链接
async def getUrl(url):
res = requests.get(url,headers=header,verify=False) # verify=False 将安全模式关闭,这里是因为在我调试过程中访问太多次后上不去了才用的
print(url)
resp = BeautifulSoup(res.text,"html.parser").find('div',attrs={'class':'zjbox'}).findAll('dd')
task=[] # 用于保存异步任务
# 每一个url都是一个异步协程操作
for line in resp:
if line.find('a') is not None:
down_url = url.rsplit('/',1)[0]+'/'+ line.find('a')['href']
# 准备异步任务
task.append(asyncio.create_task(dowload(down_url))) # 添加异步任务,添加时要将任务转为task即asyncio.create_task() (旧一点的版本可以直接添加,由系统自动转。这里用的是py3.11版本)
await asyncio.wait(task) # 等待异步添加完成
# 获取小说名字,方便文件管理
def get_name(url):
global name
# split('/')[0].strip() 对名字进行处理,文件夹名不能含有空格,其他字符等
name = BeautifulSoup(requests.get(url,headers=header,verify=False).text,"html.parser").find('h1').text.split('/')[0].strip()
path = f'../file/小说/{name}'
os.makedirs(path, exist_ok=True) # 若文件不存在则创建,存在则跳过
print(name)
def bq(url):
asyncio.run(getUrl(url))
if __name__ == '__main__':
t1 = time.time() # 检测用时
url = input("输入要下载书籍的首页:")
ye = int(input("请输入该书籍的页数:"))
get_name(url)
# 这里开了线程池,具体有没有用就不大清楚了。我只测了一组,快了50秒左右,也有可能是网络原因,各位可以去多测几组看看
with ThreadPoolExecutor(50) as t:
for i in range(1,ye + 1):
if(i==1):
t.submit(bq,url)
else:
durl = url + f"index_{i}.html"
t.submit(bq,durl)
t2 = time.time()
print(t2-t1)
爬虫案例-01
于 2023-07-05 09:08:15 首次发布