wapys 发表于 2022-11-20 13:15

优化了一下坛友的多线程爬取小说的代码

本帖最后由 wapys 于 2022-11-20 16:49 编辑

连续采集一万多章节,基本无错误
原贴链接:【Python爬虫】用多线程爬取小说,下载速度快了N倍! - 『编程语言区』 - 吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

只是测试了程序里的这个网站,其他的没做测试!
小改了一下,代码如下:
importrequests
import shutil
import re,time
from lxml import etree
from concurrent.futures import ThreadPoolExecutor
import os
# ---------------------------------------------------------------------------------
# 支持站点:
# 八一中文网(81zw.com)
# 顶点小说(23usp.com)
#笔趣阁(bqg.org,qbiqu.com,52bqg.net等全部站点)
#天籁小说(xs.23sk.com)
# --------------------------------------------------------------------------------
if not os.path.exists('./缓存'): #创建缓存文件夹来存放抓取的每一章节文件
    os.mkdir('./缓存')
    # 下面这三行如果下载一部分,没下载完那就可以 注释掉 再运行!下面有已下载检查,下载过的章节不用重复下载         
else:#如不存在则创建文件夹,如存在则清空再创建
    shutil.rmtree('./缓存')
    os.mkdir('./缓存')
url='https://www.23usp.com/xs_1511/'
# url='https://www.81zw.com/book/40352/'
# url='https://www.bqg.org/2_2977/'
# url='https://www.qbiqu.com/0_1/'
# url='https://www.52bqg.net/book_99524/'
# url='https://xs.23sk.com/files/article/html/22/22295/'
reg='(https://.*?)\/'
if '23usp' in url or '81zw' in url or '23sk' in url:
    homeUrl=re.findall(reg,url,re.S)
else:
    homeUrl=url
headers={
    'user-agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:82.0) Gecko/20100101 Firefox/82.0'
}
def choiceCode(homeUrl):
    if '23usp' in homeUrl or '23sk' in homeUrl: #转码,否则有乱码
      return 'gbk'
    elif '81zw' in homeUrl:
      return 'utf-8'
    else:
      return 'GB2312'
homePage=requests.get(url=url,headers=headers) #抓取主页面html数据
homePage.encoding=choiceCode(homeUrl)          #转码
tree=etree.HTML(homePage.text)
zhangJie_list=tree.xpath('//dd//a/@href') #获取每一章的页面相对地址
title=tree.xpath('//h1/text()') #获取小说名字
zjNameList=[]
zhangJie_list=list(set(zhangJie_list)) #去重
for u in zhangJie_list: #每一章的URL地址中提取一串数字作为存储每一章的文件名
    zhangjietxtname=u.split('/')[-1].split('.')
    zjNameList.append(int(zhangjietxtname))
zjNameList.sort() #章节排序
def downtxt(url): #下载每一章的函数
    zhangjie_url=homeUrl+url
    txtName=url.split('/')[-1].split('.') #获取每一章URL地址中的一串数字作为文件名字
    if os.path.exists('./缓存/{}.txt'.format(txtName)): #这里是查重,如果有重复文件就不继续采集了
      print(zhangjie_url,"\n 已采集,执行下一个")         
    else:
      try:
            zhangjie_sourse=requests.get(url=zhangjie_url,headers=headers)
            zhangjie_true = None#这一句是记录是否采集成功
      except:
            for i in range(6):
                time.sleep(5)    # 采集错误的一次停止5秒再试
                try:                                    
                  zhangjie_sourse=requests.get(url=zhangjie_url,headers=headers)                  
                  zhangjie_true = None #这一句是记录是否采集成功
                  break #如果没出错跳出循环,否则继续循环
                except:
                  i += 1
                  print(url+' '*10+'第%s次下载失败'%i)    # 记录失败了多少次,大于六次就退出               
                  
            if zhangjie_true != None:
                with open('./错误网址.txt','a',encoding='utf-8') as f:
                  f.write(url+'\n')
                print(url+' '*10+'下载失败')          #采集错误的记录在这个文件里
            # pass
      if zhangjie_true == None:
            zhangjie_sourse.encoding = choiceCode(homeUrl) #章节页面内容转码
            zhangjie_sourse=zhangjie_sourse.text
            tree=etree.HTML(zhangjie_sourse)
            title=tree.xpath('//h1/text()') #获取每一章名字
            txt=tree.xpath('//div[@id="content"]/text()') #获取每一章文本内容
            with open('./缓存/{}.txt'.format(txtName),'w',encoding='UTF-8') as f:
                f.write('\n'+title+'\n') #保存章节名字到文本文件
                for line in txt: #保存章节内容到文本文件,循环保存每一行
                  f.write(line)
                print(title+' '*10+'下载成功')
      else:
            print(url+' '*10+'下载失败')
def combine_txt():#合并所有章节文件函数
    with open('./{}.txt'.format(title),'a',encoding='utf-8') as f:
      for txt in zjNameList: #循环打开缓存中每一章的内容保存到新的文件中
            path='./缓存/{}.txt'.format(txt)#设置存放路径
            content=open(path,'r',encoding='utf-8').read() #打开每章节文件
            f.write(content)
            os.remove(path)
def mistake_txt(): # 这个函数把错误网址在合并文件前再重新采集一遍
    with open('./错误网址.txt','w+',encoding='utf-8') as f:
      ff = f.readlines()
      ii = len(ff)
      print("共{}条数据。".format(ii))
      print("-"*30)
      if ii>0:
            i = 1
            for line in ff:
                print("下面采集第 {} 条数据。".format(i))
                downtxt(line)
                i += 1
            print("错误网址已经采集完毕!")
      else:
            
            print("你没有、没有出错网址!")
      print("-"*30)
with ThreadPoolExecutor(15) as Pool: #使用线程池,设置15个线程,可修改
    Pool.map(downtxt,zhangJie_list)
print('!!!下载完毕,开始检查有没有错漏章节,请稍等。。。!!!')
mistake_txt()
print('!!!下载完毕,开始合并,请稍等。。。!!!')
combine_txt() #执行合并函数
os.removedirs('./缓存')
print('!!!全部完成!!!!')
重新修改了一下注释!方便调用!

wapys 发表于 2023-3-12 10:45

聚散流沙 发表于 2023-3-11 22:36
纯小白 突然想找点小说看就研究研究

for line in txt: #保存章节内容到文本文件,循环保存每一行
                  f.write('\n'+line)

这里加个换行就可以了!

ok667 发表于 2023-4-5 09:43

请教,http://www.dpxq.com/hldcg/search/view_u_1837066.html
这样的页面怎么爬取里面的UBB代码?
网页只需换数字。可以加微信请教吗?

Javajpa 发表于 2022-11-20 15:17

强啊,有学到了

lilovehistory 发表于 2022-11-20 15:37

快快学习

qq327594197 发表于 2022-11-20 15:37

强啊,有学到了

hotzhangany 发表于 2022-11-20 15:42

大佬NB,感谢分享

zjxuan 发表于 2022-11-20 15:54

免费,强悍PY代码。。

wapys 发表于 2022-11-20 16:52

重新加了注释!其实这样感觉用协程加异步会更快!

ccxxqq 发表于 2022-11-21 00:04

收到,好好学习,谢谢楼主

kevinchenyuan 发表于 2022-11-21 00:08

强啊,有学到了

ywsl 发表于 2022-11-21 02:42

感谢大佬的修改{:1_899:}
页: [1] 2 3 4
查看完整版本: 优化了一下坛友的多线程爬取小说的代码