吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 3085|回复: 64
收起左侧

[Java 原创] java爬取某站整部小说(多线程版)

  [复制链接]
甘霖之霜 发表于 2023-4-15 10:34
本帖最后由 甘霖之霜 于 2023-4-15 11:53 编辑

前言
前几天发一个帖子https://www.52pojie.cn/thread-1773549-1-1.html
各路大佬纷纷提出优化方案

其中@Ashtareve 给提出了并行流解决方案我实装一下 速度也是相当滴快(相比之前蜗牛速度)
决定把源码发出来

程序源码
还是简单介绍一下把
思路
获取目录代码
先获取目录 根据目录到具体的页面爬取对应章节
参数说明 root 网站根路径(不是起始路径) next:下一页 dir:目录
[Java] 纯文本查看 复制代码
private static void getDir(String root,String next,List<String> dir) throws Exception {
     Document document = Jsoup.connect(next).get();
     Elements elements = document.select("a[href$=\".html\"]");
     List<String> list = elements.eachAttr("href");
     list.remove(0);
     if (elements.last().text().equals("下一页")){
         String nextPage = list.get(list.size() - 1);
         nextPage = root +  nextPage.substring(nextPage.lastIndexOf("/") + 1);
         list.remove(list.size() - 1);
         if (elements.get(elements.size() - 2).text().equals("上一页")){
             list.remove(list.size() - 1);
         }
         dir.addAll(list);
         getDir(root,nextPage,dir);
         return;
     }
     if ((elements.last().text().equals("上一页"))){
         list.remove(list.size() - 1);
     }
     dir.addAll(list);
}

单章节获取
参数说明 url该章节地址
[Java] 纯文本查看 复制代码
private static String getDetail(String url){
     try {
         Document document = Jsoup.connect(url).get();
         String title = document.select("h1").text() + "\n";
         System.out.println(title);
         Elements content = document.select("div[id=\"content\"]");
         String text = content.toString();
         int i = text.indexOf("&");
         if (i != -1){
             text = text.substring(i);
         }
         text = text.replaceAll("    ","").replaceAll("<br><br>","").replaceAll("</div>","");
         return title + text;
     } catch (IOException e) {
         throw new RuntimeException(e);
     }
}

使用stream并行流获取全部章节
此为 @Ashtareve 大佬提出的解决方法 还是很有必要说明一下  这种简单高效的处理方式深得我心
参数说明 dir 刚才获取的目录 root 同上 writer输出流用于保存本地
[Java] 纯文本查看 复制代码
private static void getContent(List<String> dir,String root, Writer writer) throws Exception {
     List<String> list = dir.stream().parallel().map(url -> getDetail(root + url)).toList();
     System.out.println("正在写入文件...");
     IOUtils.writeLines(list,"\n",writer);
     writer.close();
     IOUtils.close();
}

程序依赖
[XML] 纯文本查看 复制代码
<dependency>
     <groupId>org.jsoup</groupId>
     <artifactId>jsoup</artifactId>
     <version>1.15.4</version>
</dependency>
&#8203;
<dependency>
     <groupId>commons-io</groupId>
     <artifactId>commons-io</artifactId>
     <version>2.11.0</version>
</dependency>

整体代码
[Java] 纯文本查看 复制代码
public class Demo {
     public static void main(String[] args) throws Exception {
         System.out.println("软件来自:吾爱破解 甘霖之霜");
         Scanner input = new Scanner(System.in);
         System.out.println("书籍搜索地址:https://www.bbiquge.net/");
         System.out.print("请输入书籍编号:");
         String s = input.next();
         long begin = System.currentTimeMillis();
         String url = String.format("https://www.bbiquge.net/book/%s/",s);
         String fileName = Jsoup.connect(url).get().select("h1").text();
         fileName = fileName.replace("/","") + ".txt";
         File file = new File("D:\\" + fileName);
         Writer writer =new FileWriter(file,true);
         List<String> dir = new ArrayList<>();
         System.out.println("正在获取目录中...");
         getDir(url,url,dir);
         System.out.println("正在获取章节内容...");
         getContent(dir,url,writer);
         System.out.println("下载完成,文件已保存至 D:\\" + fileName);
         System.out.printf("花费时间%s秒",(System.currentTimeMillis() - begin) / 1000);
         input.next();
     }
     private static void getDir(String root,String next,List<String> dir) throws Exception {
         Document document = Jsoup.connect(next).get();
         Elements elements = document.select("a[href$=\".html\"]");
         List<String> list = elements.eachAttr("href");
         list.remove(0);
         if (elements.last().text().equals("下一页")){
             String nextPage = list.get(list.size() - 1);
             nextPage = root +  nextPage.substring(nextPage.lastIndexOf("/") + 1);
             list.remove(list.size() - 1);
             if (elements.get(elements.size() - 2).text().equals("上一页")){
                 list.remove(list.size() - 1);
             }
             dir.addAll(list);
             getDir(root,nextPage,dir);
             return;
         }
         if ((elements.last().text().equals("上一页"))){
             list.remove(list.size() - 1);
         }
         dir.addAll(list);
     }
&#8203;
     private static void getContent(List<String> dir,String root, Writer writer) throws Exception {
         List<String> list = dir.stream().parallel().map(url -> getDetail(root + url)).toList();
         System.out.println("正在写入文件...");
         IOUtils.writeLines(list,"\n",writer);
         writer.close();
         IOUtils.close();
     }
&#8203;
     private static String getDetail(String url){
         try {
             Document document = Jsoup.connect(url).get();
             String title = document.select("h1").text() + "\n";
             System.out.println(title);
             Elements content = document.select("div[id=\"content\"]");
             String text = content.toString();
             int i = text.indexOf("&");
             if (i != -1){
                 text = text.substring(i);
             }
             text = text.replaceAll("    ","").replaceAll("<br><br>","").replaceAll("</div>","");
             return title + text;
         } catch (IOException e) {
             throw new RuntimeException(e);
         }
     }
}




使用方式
https://www.bbiquge.net去这个网站搜索点进详情 看地址栏
举个栗子
https://www.bbiquge.net/book/59265/ 其中59265 是书籍编号 输入即可

结果

一千多章 速度我个人还挺满意(可能是之前的蜗牛速度)
下载地址:https://wwi.lanzoup.com/imQLI0t1amra

免费评分

参与人数 6吾爱币 +6 热心值 +6 收起 理由
majspc + 1 + 1 谢谢@Thanks!
tension0 + 1 + 1 谢谢@Thanks!
Qingyedu + 1 + 1 谢谢@Thanks!
ningmng + 1 + 1 谢谢@Thanks!
vaycore + 1 + 1 用心讨论,共获提升!
wanfon + 1 + 1 热心回复!

查看全部评分

本帖被以下淘专辑推荐:

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

话痨司机啊 发表于 2023-4-16 15:17
本帖最后由 话痨司机啊 于 2023-4-16 17:31 编辑

我也写了一个,不知道哪个速度快一些~

我还打包了一份:
https://www.123pan.com/s/E3kbVv-V8RBH.html提取码:UlXn



[Python] 纯文本查看 复制代码
import requests
from lxml import etree
from concurrent.futures import ThreadPoolExecutor, as_completed
import os
from tqdm import tqdm
from queue import PriorityQueue
import time
import re

header = {
    "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36 Edg/112.0.1722.39"
}

QUEUE = PriorityQueue()
every_chapters_list: list = []
nove_title: str = ''


def get_next_page(next_url):
    """获取下一页"""
    global nove_title
    response = requests.get(next_url, headers=header)
    html = etree.HTML(response.text)

    # href="javascript:"
    next_page_url = html.xpath("//a[text()='下一页']/@href")
    _nove_title = html.xpath("//h1/text()")
    if nove_title:
        nove_title = _nove_title[0]
    every_chapters = html.xpath("//dl[@class='zjlist']//dd/a/@href")
    if next_page_url:
        if "javascript:" not in next_page_url[0]:
            if "index" in next_url:
                every_chapters = [next_url.rsplit('/',1)[0] + "/" + e for e in every_chapters]
            else:
                every_chapters = [next_url + e for e in every_chapters]

            every_chapters_list.extend(every_chapters)
            get_next_page("https://www.bbiquge.net" + next_page_url[0])
        else:
            print('章节获取完毕,准备开始下载小说内容')


def every_chapter(index, chapter_url):
    """请求单个章节内容"""
    response = requests.get(chapter_url, headers=header)
    html = etree.HTML(response.text)

    # title
    title: list = html.xpath("//h1/text()")

    # content
    content: list = html.xpath('//div[@id="content"]//text()')
    QUEUE.put((index, title + ['\n'] + content + ['\n']))
  


def get_novel_chapters():
    """多线程下载"""
    with ThreadPoolExecutor(max_workers=os.cpu_count() + 4) as executor,tqdm(total=len(every_chapters_list)) as pbar:
        futures = [executor.submit(every_chapter, index, url)
                   for index, url in enumerate(every_chapters_list)]
        for future in as_completed(futures):
            if future.done():
                pbar.update(1)

def filter_content(strings:str):
    return strings.replace(r"笔趣阁 www\.bbiquge\.net,最快更新宇宙职业选手最新章节!",'').replace(r'\*\*\*\*\*\*','')

def save_chapters(filename):
    with open(filename + '.txt','a',encoding='utf8') as f:
        while True:
            if QUEUE.empty():
                break
            novel_chapter = QUEUE.get()[1]
            if novel_chapter:
                f.write(filter_content(''.join(novel_chapter)))

if __name__ == "__main__":
    regex = r"^https:\/\/www.bbiquge.net\/book/\d+\/$"
    download_url = input(
        '请输入要下载的小说地址(ex:\"https://www.bbiquge.net/book/133312/\"):')
    if isinstance(download_url, str) and re.match(regex,download_url):
        download_url = download_url.strip()
        print('正在获取章节,请稍等...')
        get_next_page(download_url)
        get_novel_chapters()
        save_chapters(nove_title)
    else:
        raise ValueError("输入有误")

免费评分

参与人数 1吾爱币 +1 热心值 +1 收起 理由
ztianlan + 1 + 1 我很赞同!

查看全部评分

newsafestone 发表于 2023-4-15 11:41
甘霖之霜 发表于 2023-4-15 11:33
交互这块确实没怎么去优化  还是只分享源码得了我

移动到D盘目录后,可以下载了。
很快,很强大!
 楼主| 甘霖之霜 发表于 2023-4-15 11:45
xhygf 发表于 2023-4-15 11:40
但是软件自己直接退出了!

估计是jre的问题 自己构建吧 源码在 打包这块确实没怎么研究过 我把1万多章的校花贴身高手都下载下来了
xiliangjingmach 发表于 2023-4-15 10:43
多线程和单线程的优缺点是什么?
 楼主| 甘霖之霜 发表于 2023-4-15 10:44
xiliangjingmach 发表于 2023-4-15 10:43
多线程和单线程的优缺点是什么?

之前下载1千章大概需要半个小时还多 现在100多秒搞定
水上凌波 发表于 2023-4-15 11:07
如何获悉书籍编号
 楼主| 甘霖之霜 发表于 2023-4-15 11:08

看下帖子下半部分 有说明的
水上凌波 发表于 2023-4-15 11:12
无故退出,用不了
 楼主| 甘霖之霜 发表于 2023-4-15 11:16

输入编号不存在 会直接退出 主要分享源码,打包这块并不经常干
newsafestone 发表于 2023-4-15 11:29
我可能是不太会用。
能看到它找到了目录,但是最后文件是0K
 楼主| 甘霖之霜 发表于 2023-4-15 11:33
newsafestone 发表于 2023-4-15 11:29
我可能是不太会用。
能看到它找到了目录,但是最后文件是0K

交互这块确实没怎么去优化  还是只分享源码得了我
xhygf 发表于 2023-4-15 11:36
目录都是显示出来,但是下载后text文件里没有内容,是什么情况?
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-24 22:08

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表