鱼C论坛

 找回密码
 立即注册
查看: 189|回复: 3

[技术交流] 写了个笔趣阁爬书的小程序

[复制链接]
发表于 2025-9-7 15:09:13 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
如题。笔趣阁的服务器应该挺多,我这个是“https://www.22biqu.com/”,为了把书爬下来放手机里离线看准备的,每个章节1个TXT,用的时候合并到一起,传手机上就可以了。
  1. """
  2. 笔趣阁爬书小程序
  3. python>=3.8
  4. 依赖: pip install playwright tqdm
  5.      playwright install        # 仅需第一次
  6. Author:shadowmage
  7. """
  8. import os
  9. import re
  10. import time
  11. from urllib.parse import urljoin
  12. from playwright.sync_api import sync_playwright

  13. SAVE_DIR  = "output"

  14. # ---------- 工具 ----------
  15. def sanitize_filename(name):
  16.     return re.sub(r'[\\/*?:"<>|]', "_", name)

  17. def get_last_page(base_url):
  18.     with sync_playwright() as p:
  19.         browser = p.chromium.launch(headless=True)
  20.         ctx = browser.new_context(ignore_https_errors=True)
  21.         page = ctx.new_page()
  22.         page.goto(base_url, timeout=60000)
  23.         last_option = page.locator("#indexselect option:last-child").get_attribute("value")
  24.         browser.close()
  25.         return int(last_option.split("/")[-2])

  26. def get_chapter_links(base_url, last_page):
  27.     links = []
  28.     with sync_playwright() as p:
  29.         browser = p.chromium.launch(headless=True)
  30.         ctx = browser.new_context(ignore_https_errors=True)
  31.         page = ctx.new_page()
  32.         for i in range(1, last_page + 1):
  33.             url = f"{base_url.rstrip('/')}/{i}/"
  34.             print(f"正在获取目录页:{url}")
  35.             page.goto(url, timeout=60000)

  36.             # 只拿第二个 section-box 里的章节
  37.             section = page.locator(".section-box").nth(1)
  38.             section.wait_for()
  39.             lis = section.locator("li").all()

  40.             for li in lis:
  41.                 a = li.locator("a")
  42.                 href = a.get_attribute("href")
  43.                 title = a.inner_text()
  44.                 full_url = urljoin("https://www.22biqu.com", href)
  45.                 links.append((title, full_url))
  46.         browser.close()
  47.     return links

  48. def get_chapter_content(url):
  49.     with sync_playwright() as p:
  50.         browser = p.chromium.launch(headless=True)
  51.         ctx = browser.new_context(ignore_https_errors=True)
  52.         page = ctx.new_page()
  53.         page.goto(url, timeout=60000)
  54.         page.wait_for_selector("#content")
  55.         title = page.locator("h1.title").inner_text()
  56.         content = page.locator("#content").inner_text()
  57.         browser.close()
  58.         return title, content

  59. # ---------- 保存txt ----------
  60. def get_output_dir(base_url: str) -> str:
  61.     """
  62.     根据小说首页返回专属输出目录路径:
  63.     1. 先打开页面抓取书名
  64.     2. 生成合法文件夹名
  65.     3. 确保目录存在并返回绝对路径
  66.     """
  67.     with sync_playwright() as p:
  68.         browser = p.chromium.launch(headless=True)
  69.         ctx = browser.new_context(ignore_https_errors=True)
  70.         page = ctx.new_page()
  71.         page.goto(base_url, timeout=60000)
  72.         # 站点如把书名放在 h1,可按实际改选择器
  73.         book_name = page.locator("h1:not(.logo)").inner_text().strip()
  74.         browser.close()

  75.     safe_name = re.sub(r'[\\/:*?"<>|]', "", book_name) or "book"
  76.     out_dir = os.path.join(SAVE_DIR, safe_name)
  77.     os.makedirs(out_dir, exist_ok=True)
  78.     return out_dir

  79. # ---------- 补漏逻辑 ----------
  80. def repair_mode():
  81.     if not os.path.exists("failed.txt"):
  82.         return []                       # 无失败记录,直接回主流程
  83.     with open("failed.txt", "r", encoding="utf-8") as f:
  84.         tasks = [l.strip().split("\t") for l in f if l.strip()]
  85.     if not tasks:
  86.         return []
  87.     print(f"检测到 failed.txt,共 {len(tasks)} 章需要补漏。")
  88.     still_failed = []
  89.     for idx, (title, url) in enumerate(tasks, 1):
  90.         try:
  91.             print(f"[{idx}/{len(tasks)}] 补漏:{title}")
  92.             chapter_title, content = get_chapter_content(url)
  93.             filename = f"{sanitize_filename(chapter_title)}.txt"
  94.             with open(os.path.join("novel_output", filename), "w", encoding="utf-8") as f:
  95.                 f.write(f"{chapter_title}\n\n{content}")
  96.             time.sleep(15)
  97.         except Exception as e:
  98.             print(f"仍失败:{title},{e}")
  99.             still_failed.append((title, url))
  100.     # 重写失败文件
  101.     if still_failed:
  102.         with open("failed.txt", "w", encoding="utf-8") as f:
  103.             for title, url in still_failed:
  104.                 f.write(f"{title}\t{url}\n")
  105.         print(f"还有 {len(still_failed)} 章未成功,可再次运行本脚本补漏。")
  106.         return still_failed
  107.     else:
  108.         os.remove("failed.txt")
  109.         print("补漏完成,failed.txt 已清除。")
  110.         return []

  111. # ---------- 主流程 ----------
  112. def main():
  113.     base_url = input("请输入小说首页地址:").strip()
  114.     if not base_url.startswith("http"):
  115.         print("请输入完整的网址,以 http 或 https 开头")
  116.         return
  117.     base_url = base_url.rstrip("/") + "/"

  118.     # 1. 先进入补漏模式(如果有 failed.txt)
  119.     failed = repair_mode()
  120.     if failed:
  121.         print("请先处理完失败章节再执行完整下载。")
  122.         return

  123.     # 2. 正常流程:获取全部目录
  124.     last_page = get_last_page(base_url)
  125.     print(f"检测到目录共 {last_page} 页")
  126.     chapters = get_chapter_links(base_url, last_page)
  127.     print(f"共获取到 {len(chapters)} 个章节")
  128.     out_dir = get_output_dir(base_url)

  129.     failed = []
  130.     for idx, (title, url) in enumerate(chapters, 1):
  131.         try:
  132.             print(f"[{idx}/{len(chapters)}] 正在下载:{title}")
  133.             chapter_title, content = get_chapter_content(url)
  134.             filename = f"{idx:03}_{sanitize_filename(chapter_title)}.txt"
  135.             with open(os.path.join(out_dir, filename), "w", encoding="utf-8") as f:
  136.                 f.write(f"{chapter_title}\n\n{content}")
  137.             time.sleep(15)
  138.         except Exception as e:
  139.             print(f"下载失败:{title},{e}")
  140.             failed.append((title, url))

  141.     # 3. 把失败记录落盘
  142.     if failed:
  143.         with open("failed.txt", "w", encoding="utf-8") as f:
  144.             for title, url in failed:
  145.                 f.write(f"{title}\t{url}\n")
  146.         print(f"共有 {len(failed)} 章下载失败,已写入 failed.txt,下次运行本脚本将自动补漏。")
  147.     else:
  148.         print("全部下载完成!")

  149. if __name__ == "__main__":
  150.     main()
复制代码
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2025-9-8 20:25:46 | 显示全部楼层
FishC 发表于 2025-9-8 20:04
当然可以!将代码按照功能分层是一个很好的做法,这样不仅提高了代码的可读性和可维护性,还能方便后续 ...

是这样,我想要的效果是:
程序运行后,
1、查找是否有上一次遗留任务;
2、没有或完成上次遗留任务后,提示我输入一个网址;
3、我输入网址后,程序根据网址自动解析目录,获取章节名(同时作为txt文件名)、获取章节内容(填充到对应章节名.txt中),没下载好的放在数据库中,预备下次下载;

这里以网址【https://www.22biqu.com/biqu73070/】举例,该网址对应网页代码如下:
  1. <!DOCTYPE html><head>
  2.   <meta charset="UTF-8" />
  3.     <title>箱子里的旧日(云上麒麟)_箱子里的旧日无错完整版_箱子里的旧日最新章节_笔趣阁</title>
  4.     <meta name="keywords" content="箱子里的旧日无错版,箱子里的旧日最新章节,箱子里的旧日全文免费阅读,云上麒麟">
  5.     <meta name="description" content="箱子里的旧日是云上麒麟创作的玄幻魔法类小说,笔趣阁(22biqu.com)提供箱子里的旧日无错版以及最新章节在线阅读。">
  6.     <meta name="mobile-agent" content="format=html5;url=https://m.22biqu.com/biqu73070/"/>
  7.     <meta name="mobile-agent" content="format=xhtml;url=https://m.22biqu.com/biqu73070/"/>
  8.     <meta property="og:type" content="novel">
  9.     <meta property="og:title" content="箱子里的旧日">
  10.     <meta property="og:description" content="《箱子里的旧日》 箱子,但是机箱。 周晓收到了一套迷你机箱,可以从电脑窗口俯瞰到另一个世界。 电脑上的任何文件,都能拖进那个世界化作实体。 而那个世界的任何祭品,也都能返还回现实。 第一天,他放下暗夜精灵的世界之树,拥护信徒。 第二天,他拖入经典的大嘴花坚果墙,守卫家园。 第五天,他拷贝混沌血神的恐虐军团,毁灭王国。 第十天,他导入天灾的模型直面众神,建立称霸海洋的庞大帝国,被称为旧日的神明。 他将另一个世界的力">
  11.     <meta property="og:image" content="https://img.22biqu.com/73/73070/73070s.jpg"/>
  12.     <meta property="og:novel:category" content="玄幻魔法">
  13.     <meta property="og:novel:author" content="云上麒麟">
  14.     <meta property="og:novel:author_link" content="https://www.22biqu.com/author/%E4%BA%91%E4%B8%8A%E9%BA%92%E9%BA%9F/">
  15.     <meta property="og:novel:book_name" content="箱子里的旧日">
  16.     <meta property="og:novel:read_url" content="https://www.22biqu.com/biqu73070/">
  17.     <meta property="og:novel:url" content="https://www.22biqu.com/biqu73070/">
  18.     <meta property="og:novel:status" content="连载">
  19.     <meta property="og:novel:update_time" content="2025-08-17 07:25:03">
  20.     <meta property="og:novel:lastest_chapter_name" content="第545章 我想跟你谈谈!">
  21.     <meta property="og:novel:lastest_chapter_url" content="https://www.22biqu.com/biqu73070/43038399.html">
  22.       <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" />
  23.     <meta name="renderer" content="webkit|ie-comp|ie-stand" />
  24. <link rel="shortcut icon" type="image/x-icon" href="/static/22biqu/favicon.ico" media="screen">
  25.     <link rel="stylesheet" href="/static/22biqu/style.css" />
  26.         <script src="/js/jquery.min.js"></script>
  27.         <script src="/js/jquery.cookie.min.js"></script>
  28.     <script src="/static/22biqu/common.js"></script>
  29.     <script src="/static/22biqu/user.js"></script>
  30. <script>
  31.       if (navigator.userAgent.toLowerCase().match(/(ipod|iphone|android|coolpad|mmp|smartphone|midp|wap|xoom|symbian|j2me|blackberry|wince)/i) != null) {
  32.         let url = window.location.href;
  33.         window.location = url.replace("//www", "//m");
  34.       }
  35.     </script>
  36. </head>

  37. <body>
  38.    <div class="topbar">
  39.     <div class="topbar-con">
  40.       <div class="topbar-sethome">
  41.         <a onclick="myFunction1()">将本站设为首页</a>
  42.       </div>
  43.       <div class="topbar-addfavorite">
  44.         <a onclick="myFunction()" >收藏笔趣阁</a>
  45.       </div>
  46.       <div class="topbar-right">
  47. <ul><script>login();</script></ul>
  48. </div>
  49.     </div>
  50.   </div>

  51.   <div class="header">
  52.     <h1 class="logo"><a href="/">笔趣阁</a></h1>
  53.      <script>search();</script>
  54.     <div class="m-user" style="color:#fff">
  55.     </div>
  56.   </div>

  57.   <ul class="nav">
  58.     <li><a href="/">首页</a></li>
  59.                     <li><a href="/fenlei/1_1.html">玄幻小说</a></li>
  60.                             <li><a href="/fenlei/2_1.html">武侠小说</a></li>
  61.                             <li><a href="/fenlei/3_1.html">都市小说</a></li>
  62.                             <li><a href="/fenlei/4_1.html">历史小说</a></li>
  63.                             <li><a href="/fenlei/6_1.html">科幻小说</a></li>
  64.                             <li><a href="/fenlei/5_1.html">游戏小说</a></li>
  65.                             <li><a href="/fenlei/7_1.html">女生小说</a></li>
  66.                             <li><a href="/fenlei/8_1.html">其他小说</a></li>
  67.                 <li><a href="/quanben/fenlei/">完本小说</a></li>
  68.     <li><a rel="nofollow" href="/history.html">阅读记录</a></li>
  69.   </ul>
  70. <style>
  71. .MjYwMQ{position:relative;box-sizing:border-box;height:3.76rem;padding:.76rem 6rem 0 4rem;margin:0px 0;border-top:#DDD 1px solid;border-bottom:#DDD 1px solid;background-color: #FFFFFF;}
  72. .MjYwMQ .icon-app-logo{position:absolute;top:.6rem;left:1rem;font-size:1.5rem;color:#fff;border-radius:.38rem;background-color:#68aac2;padding:3px}
  73. .MjYwMQ .btn-primary-small{position:absolute;top:0;right:1rem;bottom:0;height:1.6rem;margin:auto;font-size:.88rem;line-height:1.6rem;padding-right:2ch;padding-left:2ch;text-align:center;color:#fff;border-radius:1.6rem;background-color:#68aac2}
  74. #center_tip{text-align: center;margin: 5px 0;color:red;font-size: larger;}
  75. #content_tip{text-align: center;margin: 5px 0;color:red;font-size: medium;}
  76. .icon-app-logo > svg {
  77.     width: 32px;
  78.     height: 32px;
  79.     vertical-align: -.25ex;
  80.     fill: currentColor;
  81. }
  82. .lnr {
  83.     width: 24px;
  84.     height: 24px;
  85.     fill: currentColor;
  86. }
  87. .footer-app-h {
  88.     font-size: .88rem;
  89. }
  90. .footer-app-p {
  91.     font-size: .76rem;
  92.     color: #969ba3;
  93. }
  94. </style>
  95. <div id="center_tip"><b>最新地址:www.22biqu.com</b></div>  
  96. <div class="container">
  97.         <div class="row row-detail">
  98.             <div class="layout layout-col1">
  99.                 <h2 class="layout-tit"><a href="/">笔趣阁</a> > 箱子里的旧日最新章节列表</h2>
  100.                 <div class="detail-box">
  101.                     <div class="imgbox">
  102.                         <img alt="箱子里的旧日" src="https://img.22biqu.com/73/73070/73070s.jpg"  onerror="this.src='/static/22biqu/nocover.jpg'"  />
  103.                         
  104.                                 <i class="flag xs-hidden"></i>
  105.                         
  106.                     </div>
  107.                     <div class="info">
  108.                         <div class="top">
  109.                             <h1>箱子里的旧日</h1>
  110.                             <div class="fix">
  111.                                 <p>作&nbsp;&nbsp;者:云上麒麟</p>
  112.                                 <p class="xs-show">类&nbsp;&nbsp;别:玄幻魔法</p>
  113.                                 <p class="xs-show">状&nbsp;&nbsp;态:连载</p>
  114.                                 <p class="opt"> <span class="xs-hidden"> 动&nbsp;&nbsp;作:</span>
  115.                                   <a  href="https://m.22biqu.com/biqu73070/" class="btn-tobtm">手机阅读</a>
  116.                                  
  117.                                 </p>
  118.                                 <p>最新章节:<a href="/biqu73070/43038399.html">第545章 我想跟你谈谈!</a></p>
  119.                                 <p>更新时间:2025-08-17 07:25:03 </p>
  120.                             </div>
  121.                         </div>
  122.                         <div class="desc xs-hidden" >
  123.                            箱子,但是机箱。 周晓收到了一套迷你机箱,可以从电脑窗口俯瞰到另一个世界。 电脑上的任何文件,都能拖进那个世界化作实体。 而那个世界的任何祭品,也都能返还回现实。 第一天,他放下暗夜精灵的世界之树,拥护信徒。 第二天,他拖入经典的大嘴花坚果墙,守卫家园。 第五天,他拷贝混沌血神的恐虐军团,毁灭王国。 第十天,他导入天灾的模型直面众神,建立称霸海洋的庞大帝国,被称为旧日的神明。 他将另一个世界的力                        </div>
  124. <div class="hotcmd-box">同类热门:<a href="https://www.22biqu.com/biqu5251/" title="宿命之环">宿命之环</a> <a href="https://www.22biqu.com/biqu5456/" title="请公子斩妖">请公子斩妖</a> <a href="https://www.22biqu.com/biqu6586/" title="乱世书">乱世书</a> <a href="https://www.22biqu.com/biqu3969/" title="混沌幽莲空间">混沌幽莲空间</a> <a href="https://www.22biqu.com/biqu6562/" title="混沌武神">混沌武神</a> <a href="https://www.22biqu.com/biqu5396/" title="择日飞升">择日飞升</a> <a href="https://www.22biqu.com/biqu57875/" title="重生商纣,开局怒怼圣人女娲">重生商纣,开局怒怼圣人女娲</a> <a href="https://www.22biqu.com/biqu5708/" title="刚成仙神,子孙求我出山">刚成仙神,子孙求我出山</a> <a href="https://www.22biqu.com/biqu1415/" title="小妖养成记">小妖养成记</a> <a href="https://www.22biqu.com/biqu5712/" title="仙子,请听我解释">仙子,请听我解释</a> </div>
  125.                     </div>
  126.                 </div>
  127.             </div>
  128.         </div>
  129.   <div class="row row-section">
  130.             <div class="layout layout-col1">
  131.                 <h2 class="layout-tit">《箱子里的旧日》最新章节</h2>
  132.                 <div class="section-box">
  133.                     <ul class="section-list fix">
  134.                                  <li><a href="/biqu73070/43038399.html">第545章 我想跟你谈谈!</a></li>
  135.                                  <li><a href="/biqu73070/42960335.html">第544章 代表绝望的黑龙,尼德霍格</a></li>
  136.                                  <li><a href="/biqu73070/42123295.html">第543章 魔改的融合战士军团</a></li>
  137.                                  <li><a href="/biqu73070/42009522.html">第542章 爱的化身,箱子玩家果然没一个正常</a></li>
  138.                                  <li><a href="/biqu73070/41999370.html">第541章 玉界的终章,神战的开端</a></li>
  139.                                  <li><a href="/biqu73070/41947199.html">第540章 被岁月考验过的种族</a></li>
  140.                                  <li><a href="/biqu73070/41820926.html">第539章 向所有人宣战!</a></li>
  141.                                  <li><a href="/biqu73070/41799054.html">第538章 MOSS:我回来了,但没完全回来</a></li>
  142.                                  <li><a href="/biqu73070/41777374.html">第537章 第三位玩家的意图</a></li>
  143.                                  <li><a href="/biqu73070/41660073.html">第536章 有内鬼,终止交易!</a></li>
  144.                                  <li><a href="/biqu73070/41660072.html">第535章 不受控制的人形核武器</a></li>
  145.                                  <li><a href="/biqu73070/41654524.html">第534章 秘密的女儿</a></li>
  146.                           </ul>
  147.                 </div>
  148. <h2 class="layout-tit">《箱子里的旧日》正文</h2>
  149.                 <div class="section-box">
  150.                     <ul class="section-list fix">
  151.                                                                 <li><a href="/biqu73070/36301096.html">第1章 新建文本文档</a></li>
  152.                                             <li><a href="/biqu73070/36301097.html">第2章 世界之树的祝福</a></li>
  153.                                             <li><a href="/biqu73070/36301098.html">第3章 祭品兑现</a></li>
  154.                                             <li><a href="/biqu73070/36301099.html">第4章 村庄的外来者</a></li>
  155.                                             <li><a href="/biqu73070/36301100.html">第5章 是 是坚果墙!</a></li>
  156.                                             <li><a href="/biqu73070/36301101.html">第6章 敌人非但不投降,还胆敢还击</a></li>
  157.                                             <li><a href="/biqu73070/36301102.html">第7章 这次的有字!</a></li>
  158.                                             <li><a href="/biqu73070/36301103.html">第8章 赞美伟大的旧日之子</a></li>
  159.                                             <li><a href="/biqu73070/36301104.html">第9章 我很快的</a></li>
  160.                                             <li><a href="/biqu73070/36301105.html">第10章 谁人丢的大拇指?</a></li>
  161.                                             <li><a href="/biqu73070/36301106.html">第11章 待机快进模式</a></li>
  162.                                             <li><a href="/biqu73070/36301107.html">第12章 王国又来了</a></li>
  163.                                             <li><a href="/biqu73070/36301108.html">第13章 65亿年前的雪暴</a></li>
  164.                                             <li><a href="/biqu73070/36301109.html">第14章 高坚果大嘴花</a></li>
  165.                                             <li><a href="/biqu73070/36301110.html">第15章 轻松获胜</a></li>
  166.                                             <li><a href="/biqu73070/36301111.html">第16章 这里不归战神管</a></li>
  167.                                             <li><a href="/biqu73070/36301112.html">第17章 诡异的王国</a></li>
  168.                                             <li><a href="/biqu73070/36301113.html">第18章 给的还不够多</a></li>
  169.                                             <li><a href="/biqu73070/36301114.html">第19章 大漩涡的世界之树</a></li>
  170.                                             <li><a href="/biqu73070/36301115.html">第20章 深潜精灵</a></li>
  171.                                             <li><a href="/biqu73070/36301116.html">第21章 窗口使用的注意事项</a></li>
  172.                                             <li><a href="/biqu73070/36301117.html">第22章 蓬勃发展的深潜者</a></li>
  173.                                             <li><a href="/biqu73070/36301118.html">第23章 半杯黄金</a></li>
  174.                                             <li><a href="/biqu73070/36301119.html">第24章 王国的秘密</a></li>
  175.                                             <li><a href="/biqu73070/36301120.html">第25章 雪伦小姐</a></li>
  176.                                             <li><a href="/biqu73070/36301121.html">第26章 开分矿了</a></li>
  177.                                             <li><a href="/biqu73070/36301122.html">第27章 隐刀探路</a></li>
  178.                                             <li><a href="/biqu73070/36301123.html">第28章 通往死亡的路</a></li>
  179.                                             <li><a href="/biqu73070/36301124.html">第29章 菜市口问斩</a></li>
  180.                                             <li><a href="/biqu73070/36301125.html">第30章 已经准备上核弹了</a></li>
  181.                                             <li><a href="/biqu73070/36301126.html">第31章 起了一枪秒了有什么好说的</a></li>
  182.                                             <li><a href="/biqu73070/36301127.html">第32章 水中的幻象</a></li>
  183.                                             <li><a href="/biqu73070/36301128.html">第33章 SAN值掉光了</a></li>
  184.                                             <li><a href="/biqu73070/36301129.html">第34章 暴风雨前夕</a></li>
  185.                                             <li><a href="/biqu73070/36301130.html">第35章 扫雷,启动!</a></li>
  186.                                             <li><a href="/biqu73070/36301131.html">第36章 从未存在过的幻象</a></li>
  187.                                             <li><a href="/biqu73070/36301132.html">第37章 最后的抚摸,最后的覆没</a></li>
  188.                                             <li><a href="/biqu73070/36301133.html">第38章 它终于蚌埠住了</a></li>
  189.                                             <li><a href="/biqu73070/36301134.html">第39章 史诗级会面</a></li>
  190.                                             <li><a href="/biqu73070/36301135.html">第40章 圣女大人和神使小姐</a></li>
  191.                                             <li><a href="/biqu73070/36301136.html">第41章 撑死胆大的,饿死胆小的</a></li>
  192.                                             <li><a href="/biqu73070/36301137.html">第42章 神力之间的对抗</a></li>
  193.                                             <li><a href="/biqu73070/36301138.html">第43章 窗口的代价</a></li>
  194.                                             <li><a href="/biqu73070/36301139.html">第44章 初次收获</a></li>
  195.                                             <li><a href="/biqu73070/36301140.html">第45章 神选冠军</a></li>
  196.                                             <li><a href="/biqu73070/36301141.html">第46章 东诺斯王国的终章</a></li>
  197.                                             <li><a href="/biqu73070/36301142.html">第47章 从来没打过这么富裕的仗</a></li>
  198.                                             <li><a href="/biqu73070/36301143.html">第48章 你可真是个天才!</a></li>
  199.                                             <li><a href="/biqu73070/36301144.html">第49章 团队扩充了</a></li>
  200.                                             <li><a href="/biqu73070/36301145.html">第50章 猩红球体</a></li>
  201.                                             <li><a href="/biqu73070/36301146.html">第51章 变异从未离开过</a></li>
  202.                                             <li><a href="/biqu73070/36301147.html">第52章 有请下一位受害者</a></li>
  203.                                             <li><a href="/biqu73070/36301148.html">第53章 海湾侵袭</a></li>
  204.                                             <li><a href="/biqu73070/36301149.html">第54章 这个场子我来罩</a></li>
  205.                                             <li><a href="/biqu73070/36301150.html">第55章 两个重量级项目</a></li>
  206.                                             <li><a href="/biqu73070/36301151.html">第56章 大海的回答</a></li>
  207.                                             <li><a href="/biqu73070/36301152.html">第57章 有贼来了</a></li>
  208.                                             <li><a href="/biqu73070/36301153.html">第58章 就是那种半人半鱼的美人鱼明白吗?</a></li>
  209.                                             <li><a href="/biqu73070/36301154.html">第59章 大意了没有闪</a></li>
  210.                                             <li><a href="/biqu73070/36301155.html">第60章 陛下何故谋反</a></li>
  211.                                             <li><a href="/biqu73070/36301156.html">第61章 十二生肖里有没有哥总?</a></li>
  212.                                             <li><a href="/biqu73070/36301157.html">第62章 送船来了</a></li>
  213.                                             <li><a href="/biqu73070/36301158.html">第63章 融合的幽灵魔舰</a></li>
  214.                                             <li><a href="/biqu73070/36301159.html">第64章 三大国联合送人头船队</a></li>
  215.                                             <li><a href="/biqu73070/36301160.html">第65章 浓雾里,大的要来了</a></li>
  216.                                             <li><a href="/biqu73070/36301161.html">第66章 一面倒的胜利</a></li>
  217.                                             <li><a href="/biqu73070/36301162.html">第67章 你们搞科研的都这么狂热?</a></li>
  218.                                             <li><a href="/biqu73070/36301163.html">第68章 我,哥斯拉,打钱</a></li>
  219.                                             <li><a href="/biqu73070/36301164.html">第69章 泄露了,但没完全泄露</a></li>
  220.                                             <li><a href="/biqu73070/36301165.html">第70章 迷雾之门号</a></li>
  221.                                             <li><a href="/biqu73070/36301166.html">第71章 我们之中有内鬼</a></li>
  222.                                             <li><a href="/biqu73070/36301167.html">第72章 移民开始</a></li>
  223.                                             <li><a href="/biqu73070/36301168.html">第73章 我的血肉,我的兄弟</a></li>
  224.                                             <li><a href="/biqu73070/36301169.html">第74章 神性污染</a></li>
  225.                                             <li><a href="/biqu73070/36301170.html">第75章 王国的现代化开始</a></li>
  226.                                             <li><a href="/biqu73070/36301171.html">第76章 地里长矿石了</a></li>
  227.                                             <li><a href="/biqu73070/36301172.html">第77章 搞科研的也要朝圣</a></li>
  228.                                             <li><a href="/biqu73070/36301173.html">第78章 逐渐接近了真相</a></li>
  229.                                             <li><a href="/biqu73070/36301174.html">第79章 物竞天择,适者进化</a></li>
  230.                                             <li><a href="/biqu73070/36301175.html">第80章 预言已经向我揭示了一切</a></li>
  231.                                             <li><a href="/biqu73070/36301176.html">第81章 生气了</a></li>
  232.                                             <li><a href="/biqu73070/36301177.html">第82章 来了,这次真的来了</a></li>
  233.                                             <li><a href="/biqu73070/36301178.html">第83章 我附庸的附庸不是我的附庸</a></li>
  234.                                             <li><a href="/biqu73070/36301179.html">第84章 都是豌豆射手的锅</a></li>
  235.                                             <li><a href="/biqu73070/36301180.html">第85章 吞噬神性,夺取权柄</a></li>
  236.                                             <li><a href="/biqu73070/36301181.html">第86章 雷神托尔已关注了你</a></li>
  237.                                             <li><a href="/biqu73070/36301182.html">第87章 恐虐军团,专业大扫除</a></li>
  238.                                             <li><a href="/biqu73070/36301183.html">第88章 该来的始终还是来了</a></li>
  239.                                             <li><a href="/biqu73070/36301184.html">第89章 上架感言</a></li>
  240.                                             <li><a href="/biqu73070/36301185.html">第90章 请假条!</a></li>
  241.                                             <li><a href="/biqu73070/36301186.html">第91章 是你在偷看我么?</a></li>
  242.                                             <li><a href="/biqu73070/36301187.html">第92章 诸神之间的算计</a></li>
  243.                                             <li><a href="/biqu73070/36301188.html">第93章 海洋权“饼”,分而食之</a></li>
  244.                                             <li><a href="/biqu73070/36301189.html">第94章 统一北海</a></li>
  245.                                             <li><a href="/biqu73070/36301190.html">第95章 爆 爆水管了!</a></li>
  246.                                             <li><a href="/biqu73070/36301191.html">第96章 请叫我水神</a></li>
  247.                                             <li><a href="/biqu73070/36301192.html">第97章 加入光荣的进化吧!</a></li>
  248.                                             <li><a href="/biqu73070/36301193.html">第98章 讨债的来了</a></li>
  249.                                             <li><a href="/biqu73070/36301194.html">第99章 什么叫大国外交</a></li>
  250.                                             <li><a href="/biqu73070/36301195.html">第100章 给外乡人一些小小的科技震撼</a></li>
  251.                                             <li><a href="/biqu73070/36301196.html">第101章 开始进入高级战场</a></li>
  252.                                             <li><a href="/biqu73070/36301197.html">第102章 少女勇闯欧陆,前进!</a></li>
  253.                                             <li><a href="/biqu73070/36301198.html">第103章 让人不安的靠近</a></li>
  254.                                             <li><a href="/biqu73070/36301199.html">第104章 谨防诈骗搭讪</a></li>
  255.                                             <li><a href="/biqu73070/36301200.html">第105章 四分五裂的信仰</a></li>
  256.                                             <li><a href="/biqu73070/36301201.html">第106章 你再说一遍你是谁?</a></li>
  257.                                             <li><a href="/biqu73070/36301202.html">第107章 我踏马吃吃吃!</a></li>
  258.                                             <li><a href="/biqu73070/36301203.html">第108章 以信徒为棋子的战争</a></li>
  259.                                             <li><a href="/biqu73070/36301204.html">第109章 写书人和神经病</a></li>
  260.                                             <li><a href="/biqu73070/36301205.html">第110章 路见不平的白发女侠</a></li>
  261.                                             <li><a href="/biqu73070/36301206.html">第111章 各方的异动</a></li>
  262.                                             <li><a href="/biqu73070/36301207.html">第112章 神王奥丁的半神血脉</a></li>
  263.                                             <li><a href="/biqu73070/36301208.html">第113章 找上门来了</a></li>
  264.                                             <li><a href="/biqu73070/36301209.html">第114章 原来是来上门送菜的</a></li>
  265.                                             <li><a href="/biqu73070/36301210.html">第115章 菜已收,勿念</a></li>
  266.                                             <li><a href="/biqu73070/36301211.html">第116章 神力指针模式</a></li>
  267.                                             <li><a href="/biqu73070/36301212.html">第117章 新章节:旧日之子</a></li>
  268.                                             <li><a href="/biqu73070/36301213.html">第118章 篝火狐鸣,打入内部</a></li>
  269.                                             <li><a href="/biqu73070/36301214.html">第119章 大战前夜</a></li>
  270.                                             <li><a href="/biqu73070/36301215.html">第120章 全家老少都带过来了</a></li>
  271.                                             <li><a href="/biqu73070/36301216.html">第121章 比尔吉沃特之怒!</a></li>
  272.                                             <li><a href="/biqu73070/36301217.html">第122章 成分复杂的深海泰坦</a></li>
  273.                                             <li><a href="/biqu73070/36301218.html">第123章 两个家贼</a></li>
  274.                                             <li><a href="/biqu73070/36301219.html">第124章 半神之夜,王神相见</a></li>
  275.                                             <li><a href="/biqu73070/36301220.html">第125章 以身为剑,斩尽雨幕</a></li>
  276.                                             <li><a href="/biqu73070/36301221.html">第126章 你别过来啊!</a></li>
  277.                                             <li><a href="/biqu73070/36301222.html">第127章 糟糕!我吃错东西了!</a></li>
  278.                                             <li><a href="/biqu73070/36301223.html">第128章 深海职场也需要背锅侠</a></li>
  279.                                             <li><a href="/biqu73070/36301224.html">第129章 糟糕!吃错东西的我被吃掉了!</a></li>
  280.                                             <li><a href="/biqu73070/36301225.html">第130章 无间道的说话艺术</a></li>
  281.                                             <li><a href="/biqu73070/36301226.html">第131章 快把人忽悠瘸了</a></li>
  282.                                             <li><a href="/biqu73070/36301227.html">第132章 开局一条鲲,是兄弟就来吞我</a></li>
  283.                                             <li><a href="/biqu73070/36301228.html">第133章 似曾相识的名场面</a></li>
  284.                                             <li><a href="/biqu73070/36301229.html">第134章 有些事永远都不会被遗忘</a></li>
  285.                                             <li><a href="/biqu73070/36301230.html">第135章 大陆型海上移动堡垒</a></li>
  286.                                             <li><a href="/biqu73070/36301231.html">第136章 带着大陆一起流浪</a></li>
  287.                                             <li><a href="/biqu73070/36301232.html">第137章 坏了,我成替身了!</a></li>
  288.                                             <li><a href="/biqu73070/36301233.html">第138章 史上最夸张的支援</a></li>
  289.                                             <li><a href="/biqu73070/36301234.html">第139章 领域展开的魔鬼海域</a></li>
  290.                                             <li><a href="/biqu73070/36301235.html">第140章 我要看到血流成河!</a></li>
  291.                                             <li><a href="/biqu73070/36301236.html">第141章 船鲲,海鲲,你没玩过的全新版本!</a></li>
  292.                                             <li><a href="/biqu73070/36301237.html">第142章 发动机喷射口:此面向敌</a></li>
  293.                                             <li><a href="/biqu73070/36301238.html">第143章 这位更是重量级</a></li>
  294.                                             <li><a href="/biqu73070/36301239.html">第144章 买一送二的神明惊喜大礼包</a></li>
  295.                                             <li><a href="/biqu73070/36301240.html">第145章 死亡为谁而来?</a></li>
  296.                                             <li><a href="/biqu73070/36301241.html">第146章 看好了,哥斯拉是这么打的</a></li>
  297.                                             <li><a href="/biqu73070/36301242.html">第147章 不可改变的命运</a></li>
  298.                                             <li><a href="/biqu73070/36301243.html">第148章 我们都是命运的奴隶</a></li>
  299.                                             <li><a href="/biqu73070/36301244.html">第149章 幻影斧哥斯拉联动连招</a></li>
  300.                                             <li><a href="/biqu73070/36301245.html">第150章 我们取得了辉煌的胜利</a></li>
  301.                                             <li><a href="/biqu73070/36301246.html">第151章 但,代价是什么?</a></li>
  302.                                             <li><a href="/biqu73070/36301247.html">第152章 内鬼开始行动了</a></li>
  303.                                             <li><a href="/biqu73070/36301248.html">第153章 扎心了老铁</a></li>
  304.                                             <li><a href="/biqu73070/36301249.html">第154章 父之仇,子之报</a></li>
  305.                                             <li><a href="/biqu73070/36301250.html">第155章 汇聚死亡的超级模型</a></li>
  306.                                             <li><a href="/biqu73070/36301251.html">第156章 苍天已死,黄天当立!</a></li>
  307.                                             <li><a href="/biqu73070/36301252.html">第157章 十字路口的抉择</a></li>
  308.                                             <li><a href="/biqu73070/36301253.html">第158章 泰因的选择是?</a></li>
  309.                                             <li><a href="/biqu73070/36301254.html">第159章 拔剑</a></li>
  310.                                             <li><a href="/biqu73070/36301255.html">第160章 泰因的答案</a></li>
  311.                                             <li><a href="/biqu73070/36301256.html">第161章 破败王者的霜之哀伤</a></li>
  312.                                             <li><a href="/biqu73070/36301257.html">第162章 深潜血族</a></li>
  313.                                             <li><a href="/biqu73070/36301258.html">第163章 没事,我可以换一只手</a></li>
  314.                                             <li><a href="/biqu73070/36301259.html">第164章 回应我吧,我的爱人!</a></li>
  315.                                             <li><a href="/biqu73070/36301260.html">第165章 双神选,双权柄</a></li>
  316.                                             <li><a href="/biqu73070/36301261.html">第166章 死亡的竞赛才刚刚开始</a></li>
  317.                                             <li><a href="/biqu73070/36301262.html">第167章 谁是猪?猪是我?我是谁?</a></li>
  318.                                             <li><a href="/biqu73070/36301263.html">第168章 谁还没点背景了</a></li>
  319.                                             <li><a href="/biqu73070/36301264.html">第169章 预言者之梦</a></li>
  320.                                             <li><a href="/biqu73070/36301265.html">第170章 修车?修车也算时间啊!</a></li>
  321.                                             <li><a href="/biqu73070/36301266.html">第171章 狠人话不多</a></li>
  322.                                             <li><a href="/biqu73070/36301267.html">第172章 你们惊扰了午夜军团</a></li>
  323.                                             <li><a href="/biqu73070/36301268.html">第173章 来自侏罗纪的呼唤</a></li>
  324.                                             <li><a href="/biqu73070/36301269.html">第174章 超凡神器也要吃我狗粮!</a></li>
  325.                                             <li><a href="/biqu73070/36301270.html">第175章 我叫克拉肯,畏惧我吧!</a></li>
  326.                                             <li><a href="/biqu73070/36301271.html">第176章 我叫拉莱耶,别吃掉我!</a></li>
  327.                                             <li><a href="/biqu73070/36301272.html">第177章 晋升?升魔!</a></li>
  328.                                             <li><a href="/biqu73070/36301273.html">第178章 只负责灌满,不负责吸收</a></li>
  329.                                             <li><a href="/biqu73070/36301274.html">第179章 已经没有可以回去的家了</a></li>
  330.                                             <li><a href="/biqu73070/36301275.html">第180章 拉莱耶的克拉肯之怒</a></li>
  331.                                             <li><a href="/biqu73070/36301276.html">第181章 战火的开端</a></li>
  332.                                             <li><a href="/biqu73070/36301277.html">第182章 您好,你可以叫我MOSS</a></li>
  333.                                             <li><a href="/biqu73070/36420525.html">183.第183章 神明世界里的数字生命</a></li>
  334.                                             <li><a href="/biqu73070/36420526.html">184.第184章 我人工智能信教了,这很合理吧</a></li>
  335.                                             <li><a href="/biqu73070/36420527.html">185.第185章 大陆苦弱,机械飞升!</a></li>
  336.                                             <li><a href="/biqu73070/36420528.html">186.第186章 数字生命,不忘初心</a></li>
  337.                                             <li><a href="/biqu73070/36420529.html">187.第187章 圣战,我要看到圣战!</a></li>
  338.                                             <li><a href="/biqu73070/36420530.html">188.第188章 小样,还能闹翻天不成?</a></li>
  339.                                             <li><a href="/biqu73070/36420531.html">189.第189章 陌生眷族们的聚首</a></li>
  340.                                             <li><a href="/biqu73070/36420532.html">190.第190章 小小雪伦担当大旗</a></li>
  341.                                             <li><a href="/biqu73070/36448161.html">191.第191章 就是那种上人下马的半人马明白</a></li>
  342.                                             <li><a href="/biqu73070/36448162.html">192.第192章 来自六千五百万年前的咆哮</a></li>
  343.                                             <li><a href="/biqu73070/36448163.html">193.第193章 驯服死亡的骑士们</a></li>
  344.                                             <li><a href="/biqu73070/36458931.html">194.第194章 敌人的敌人就是我的朋友</a></li>
  345.                                             <li><a href="/biqu73070/36467527.html">195.第195章 海神们的最后挣扎</a></li>
  346.                                             <li><a href="/biqu73070/36467528.html">196.第196章 美少女就应该用EX咖喱棒</a></li>
  347.                                             <li><a href="/biqu73070/36493817.html">197.第197章 来自触手娘的呼唤</a></li>
  348.                                             <li><a href="/biqu73070/36493818.html">198.第198章 舰娘,没错,我说的是舰娘</a></li>
  349.                                             <li><a href="/biqu73070/36493819.html">199.第199章 舰娘漂移,技惊四座!</a></li>
  350.                                             <li><a href="/biqu73070/36493820.html">200.第200章 海之死神穷途末路</a></li>
  351.                     </div>
  352.     <div  class="index-container"><a class="index-container-btn disabled-btn" href="javascript:void(0);">没有了</a><select id="indexselect" onchange="self.location.href=options[selectedIndex].value"><option value="/biqu73070/" selected="selected">1 - 200章</option><option value="/biqu73070/2/">201 - 400章</option><option value="/biqu73070/3/">401 - 547章</option></select><a class="index-container-btn" href="/biqu73070/2/">下一页</a></div>

  353.     </div>
  354.                         <div class="clr"></div>
  355.                                 </dl>
  356.                         </div>
  357.    
  358.     </section>

  359. </div>
  360. <div align="center"><p>相邻小说: <a href="https://www.22biqu.com/biqu73071/">离婚后我成了山神</a>  <a href="https://www.22biqu.com/biqu73072/">穿越永生从大心魔术开始</a>  <a href="https://www.22biqu.com/biqu73073/">凡人之造化长生</a>  <a href="https://www.22biqu.com/biqu73074/">四合院之惬意人生</a>  <a href="https://www.22biqu.com/biqu73075/">四合院之我的东北农家小院</a>  <a href="https://www.22biqu.com/biqu73076/">重回1981从退婚开始</a>  <a href="https://www.22biqu.com/biqu73077/">假面骑士极狐之双子星</a>  <a href="https://www.22biqu.com/biqu73078/">斗罗:觉醒堕落血天使,神挡杀神</a>  <a href="https://www.22biqu.com/biqu73079/">全民神祇:我被土著当成NPC?</a>  <a href="https://www.22biqu.com/biqu73080/">斗罗:悟性逆天,震惊比比东!</a> </p></div>
  361. <script>
  362.            (function () {
  363.                                         var bp = document.createElement('script');
  364.                                         var curProtocol = window.location.protocol.split(':')[0];
  365.                                         if (curProtocol === 'https') {
  366.                                                 bp.src = 'https://zz.bdstatic.com/linksubmit/push.js';
  367.                                         }
  368.                                         else {
  369.                                                 bp.src = 'http://push.zhanzhang.baidu.com/push.js';
  370.                                         }
  371.                                         var s = document.getElementsByTagName("script")[0];
  372.                                         s.parentNode.insertBefore(bp, s);
  373.                                 })();
  374. </script>
  375. <div class="footer" id="footer">
  376.     <div class="pc-footer">
  377.         <p>《箱子里的旧日》情节跌宕起伏、扣人心弦,是一本情节与文笔俱佳的玄幻魔法,笔趣阁转载收集箱子里的旧日最新章节。</p>
  378.     </div>
  379. </div>
  380. <script>
  381. function myFunction(){
  382.         alert("加入收藏失败,请使用Ctrl+D进行添加,或手动在浏览器里进行设置!");
  383. }
  384. function myFunction1(){
  385.         alert("浏览器不支持此操作, 请手动设为首页!");
  386. }
  387. </script>
  388. <script src="/js/jquery.lazyload.min.js"></script>
  389. <script>
  390. var _hmt = _hmt || [];
  391. (function() {
  392.   var hm = document.createElement("script");
  393.   hm.src = "https://hm.baidu.com/hm.js?b1f1cdea3b4cf4604cb8940d5d2ce1a7";
  394.   var s = document.getElementsByTagName("script")[0];
  395.   s.parentNode.insertBefore(hm, s);
  396. })();
  397. </script>
  398. </body></html>
复制代码
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2025-9-8 20:04:59 | 显示全部楼层
shadowmage 发表于 2025-09-08 20:03
@FishC
我想要提高代码效率,想重新把上面代码重构, ...


当然可以!将代码按照功能分层是一个很好的做法,这样不仅提高了代码的可读性和可维护性,还能方便后续扩展和优化。下面我将为你提供一个基于 crawler / parser / store / scheduler 四层架构的简单示例,使用 Python 实现。


  1. import requests
  2. from bs4 import BeautifulSoup
  3. import sqlite3
  4. import os
  5. from urllib.parse import urljoin, urlparse
  6. import time
  7. from queue import Queue
  8. from threading import Thread

  9. # ==================== Crawler 层 ====================
  10. class Crawler:
  11.     def fetch(self, url):
  12.         try:
  13.             response = requests.get(url, timeout=10)
  14.             response.raise_for_status()
  15.             return response.text
  16.         except requests.RequestException as e:
  17.             print(f"抓取失败: {url}, 错误: {e}")
  18.             return None

  19. # ==================== Parser 层 ====================
  20. class Parser:
  21.     def parse(self, html, base_url):
  22.         if not html:
  23.             return None
  24.         soup = BeautifulSoup(html, 'html.parser')
  25.         # 示例:提取标题和所有链接
  26.         title = soup.title.string if soup.title else "无标题"
  27.         links = [urljoin(base_url, a.get('href')) for a in soup.find_all('a', href=True)]
  28.         return {
  29.             'title': title,
  30.             'links': links
  31.         }

  32. # ==================== Store 层 ====================
  33. class Store:
  34.     def __init__(self, db_path='data.db', storage_dir='pages'):
  35.         self.db_path = db_path
  36.         self.storage_dir = storage_dir
  37.         os.makedirs(storage_dir, exist_ok=True)
  38.         self.init_db()

  39.     def init_db(self):
  40.         conn = sqlite3.connect(self.db_path)
  41.         cursor = conn.cursor()
  42.         cursor.execute('''
  43.             CREATE TABLE IF NOT EXISTS pages (
  44.                 url TEXT PRIMARY KEY,
  45.                 title TEXT,
  46.                 file_path TEXT,
  47.                 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
  48.             )
  49.         ''')
  50.         conn.commit()
  51.         conn.close()

  52.     def save_page(self, url, title, content):
  53.         # 生成文件名
  54.         parsed_url = urlparse(url)
  55.         file_name = f"{parsed_url.netloc}{parsed_url.path}".replace('/', '_')
  56.         if not file_name:
  57.             file_name = 'index'
  58.         file_path = os.path.join(self.storage_dir, file_name + '.html')
  59.         
  60.         # 保存HTML内容到文件
  61.         with open(file_path, 'w', encoding='utf-8') as f:
  62.             f.write(content)
  63.         
  64.         # 存储元数据到SQLite
  65.         conn = sqlite3.connect(self.db_path)
  66.         cursor = conn.cursor()
  67.         cursor.execute('''
  68.             INSERT OR REPLACE INTO pages (url, title, file_path)
  69.             VALUES (?, ?, ?)
  70.         ''', (url, title, file_path))
  71.         conn.commit()
  72.         conn.close()

  73. # ==================== Scheduler 层 ====================
  74. class Scheduler:
  75.     def __init__(self, max_workers=3):
  76.         self.queue = Queue()
  77.         self.visited = set()
  78.         self.crawler = Crawler()
  79.         self.parser = Parser()
  80.         self.store = Store()
  81.         self.max_workers = max_workers

  82.     def add_url(self, url):
  83.         if url not in self.visited:
  84.             self.queue.put(url)
  85.             self.visited.add(url)

  86.     def worker(self):
  87.         while True:
  88.             url = self.queue.get()
  89.             if url is None:
  90.                 break
  91.             
  92.             # 1. 抓取
  93.             html = self.crawler.fetch(url)
  94.             if not html:
  95.                 self.queue.task_done()
  96.                 continue
  97.             
  98.             # 2. 解析
  99.             parsed_data = self.parser.parse(html, url)
  100.             if parsed_data:
  101.                 # 3. 存储
  102.                 self.store.save_page(url, parsed_data['title'], html)
  103.                
  104.                 # 4. 将新链接加入队列
  105.                 for link in parsed_data['links']:
  106.                     self.add_url(link)
  107.             
  108.             self.queue.task_done()
  109.             time.sleep(1)  # 礼貌性延迟

  110.     def start(self, start_url):
  111.         self.add_url(start_url)
  112.         threads = []
  113.         for _ in range(self.max_workers):
  114.             t = Thread(target=self.worker)
  115.             t.start()
  116.             threads.append(t)
  117.         
  118.         self.queue.join()
  119.         
  120.         # 停止工作线程
  121.         for _ in range(self.max_workers):
  122.             self.queue.put(None)
  123.         for t in threads:
  124.             t.join()

  125. # ==================== 使用示例 ====================
  126. if __name__ == "__main__":
  127.     scheduler = Scheduler()
  128.     scheduler.start('[url=https://example.com')]https://example.com')[/url]
复制代码


说明:
  • Crawler 层:只负责通过 HTTP 获取原始 HTML 内容。
  • Parser 层:负责解析 HTML,提取所需的结构化数据(如标题、链接)。
  • Store 层:负责将数据存储到文件系统,并使用 SQLite 维护索引。
  • Scheduler 层:负责任务调度、URL 去重、多线程抓取以及协调其他组件。


你可以根据实际需求进一步扩展每层的功能,例如增加代理支持、异常重试机制、更复杂的数据解析等。希望这个示例能帮助你更好地组织代码!

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2025-9-8 20:03:43 | 显示全部楼层
@FishC
我想要提高代码效率,想重新把上面代码重构,用crawler / parser / store / scheduler这么四层重新编写程序。
crawler层只负责拿原始 HTML
parser层把 HTML 变成结构化数据
store层负责读写磁盘 + sqlite 索引
scheduler层负责编排、差分、重试、进度等。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-9-23 10:16

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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