ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

owllook 小说榜单爬虫实战:基于 Ruia 异步框架爬取起点与纵横排行榜数据

2026/10/4 15:50:32 拓冰建站 浏览量
owllook 小说榜单爬虫实战:基于 Ruia 异步框架爬取起点与纵横排行榜数据 后端搜索引擎网页爬虫【免费下载链接】owllookowllook-小说搜索引擎项目地址https://gitcode.com/gh_mirrors/ow/owllook点击查看免费下载owllook 是一款开源的小说搜索引擎其 owllook/spiders 目录承载着整个项目的榜单与书籍数据采集层。本文聚焦其中专门负责小说榜单爬虫的实现围绕官方文档 owllook/spiders/README.md 中记录的起点中文网qidian榜单抓取方案结合仓库内真实源码排名爬虫、全站小说爬虫、书籍详情爬虫、定时调度与代理中间件系统讲解如何用异步爬虫框架Ruia完成榜单数据的抓取、解析、清洗与入库并给出可直接复用的分类参数表与运行方式。阅读完本文你将掌握起点榜单 URL 的分类参数含义与构造方式、Ruia 中Item/TextField/AttrField/HtmlField的字段提取与clean_*清洗方法、榜单 Top10 截取与 MongoDBupsert入库的完整链路以及如何通过定时任务把榜单数据持续同步进 owllook 的检索体系。一、榜单爬虫在 owllook 中的定位owllook 的整体数据流是爬虫采集 → 结构化入库 → 搜索引擎召回 → 页面展示。榜单爬虫负责持续抓取各大小说站的排名数据为首页榜单、小说热度排序等场景提供原始素材属于整个项目的数据采集入口之一。从源码结构看owllook/spiders 目录内的爬虫按数据形态分为两类榜单/排名爬虫抓取榜单页的排名列表产出榜单标题 书名 Top N 榜单入口链接书籍信息爬虫抓取全站小说列表页与单本书详情页产出书名、作者、封面、简介、最新章节等结构化字段。榜单爬虫的代表实现是 qidian_ranking.py起点榜单与 zh_ranking.py纵横人气榜单二者共用同一套 Ruia 异步框架与同一张 MongoDB 集合novels_ranking而官方 README 记录的正是起点的榜单抓取方案接下来以此为线索展开。二、起点榜单目标 URL 与分类参数全表owllook/spiders/README.md 明确给出起点的榜单入口为http://r.qidian.com/?chn-1chn参数决定榜单展示的小说分类完整参数表如下该表直接继承自项目文档是编写起点榜单爬虫的关键配置依据参数 URL分类说明http://r.qidian.com/?chn-1全部分类http://r.qidian.com/?chn21玄幻http://r.qidian.com/?chn1奇幻http://r.qidian.com/?chn2武侠http://r.qidian.com/?chn22仙侠http://r.qidian.com/?chn4都市http://r.qidian.com/?chn15职场http://r.qidian.com/?chn6军事http://r.qidian.com/?chn5历史http://r.qidian.com/?chn7游戏http://r.qidian.com/?chn8体育http://r.qidian.com/?chn9科幻http://r.qidian.com/?chn10灵异http://r.qidian.com/?chn12二次元2.1 分类参数在源码中的落地这份参数表并非孤立存在它被完整落到了 qidian_ranking.py 的QidianRankingSpider中start_urls通过列表推导式批量生成 14 个分类榜单 URL[fhttps://www.qidian.com/rank/?chn{key} for key in [-1, 21, 1, 2, 22, 4, 15, 6, 5, 7, 8, 9, 10, 12]]注意生产代码使用的域名是www.qidian.com/rank/README 中记录的是早期入口r.qidian.com二者chn参数语义一致抓取时以当前源码为准qidian_type字典将chn参数值映射为中文分类名解析结果最终会写入数据库的type字段例如-1: 全部类别、21: 玄幻concurrency 3控制并发请求数为 3避免对榜单接口造成过大压力。也就是说若要扩展榜单分类只需修改start_urls与qidian_type两处即可参数表与代码一一对应方便维护。三、榜单爬虫的 Ruia 实现剖析Ruia 是 owllook 使用的轻量异步爬虫框架其核心思想是用Item声明字段提取规则CSS 选择器用Spider声明抓取入口与解析逻辑配合asyncio实现并发抓取。qidian_ranking.py 与 zh_ranking.py 都遵循这一模式。3.1 榜单 Item四级 CSS 选择器定位起点榜单页的 Item 定义如下见 qidian_ranking.pyclass RankingItem(Item): target_item TextField(css_select.rank-list) ranking_title TextField(css_selecth3.wrap-title) more AttrField(css_selecth3a.more, attrhref) book_list HtmlField(css_selectdiv.book-listulli, manyTrue)TextField提取元素的文本内容如榜单标题AttrField提取元素的属性值如href属性这里用attrhref取到查看更多的链接HtmlField(css_select..., manyTrue)批量提取多个元素的 HTML 片段这里把每个div.book-listulli榜单中的一本书整体截取出来交给下一级 Item 二次解析。与起点对应的纵横榜单 Item见 zh_ranking.py结构几乎一致div.rank_i_p_list作为榜单容器、div.rank_i_p_tit作为榜单标题、div.rank_i_p_listdiv.rank_i_li批量提取每本书。可见 owllook 用两级 Item CSS 选择器的组合把不同站点的榜单页统一抽象成了同构的数据结构。3.2 二级 Item书名提取与容错榜单页中每本书的书名可能出现在两个位置置顶书名与普通书名因此第二级 Item 同时声明两个字段并做兜底见 qidian_ranking.pyclass NameItem(Item): top_name TextField(css_selecth4, default) other_name TextField(css_selecta.name, default)default保证字段缺失时不报错解析时用item_data.top_name or item_data.other_name优先取置顶书名取不到再回退到普通书名——这是典型的健壮性写法。3.3 clean_* 清洗钩子数据标准化Ruia 允许为字段定义clean_字段名异步方法做后处理。起点榜单里用到了两个清洗钩子async def clean_ranking_title(self, ranking_title): if isinstance(ranking_title, list): return ranking_title[0].text else: return str(ranking_title).split(榜)[0] 榜 async def clean_more(self, more): return https: moreclean_ranking_title兼容返回列表与返回字符串两种情况并把标题统一规整为XX榜格式clean_more页面返回的查看更多链接缺少协议头统一补全为https:绝对地址。纵横榜单的RankingItem则没有额外的清洗逻辑字段直接使用说明清洗钩子是按需添加的当页面数据结构不稳定时这里就是兜底修正的最佳位置。3.4 parse 解析榜单 Top10 截取与结果组装榜单页通常包含多个榜单区块parse方法对每个区块取排名前十的书籍见 qidian_ranking.pyasync for item in RankingItem.get_items(htmlres.html): each_book_list [] # 只取排名前十的书籍数据 for index, value in enumerate(item.book_list[:10]): item_data await NameItem.get_item(htmlvalue) name item_data.top_name or item_data.other_name each_book_list.append({num: index 1, name: name}) data { title: item.ranking_title, more: item.more, book_list: each_book_list, updated_at: time.strftime(%Y-%m-%d %X, time.localtime()), } result.append(data)res_dic中除了data榜单数据外还附带了target_url本次抓取的榜单 URL、type由qidian_type映射出的中文分类名与spider固定为qidian这些元信息用于区分数据来源。纵横版zh_ranking.py的逻辑相同只是type固定为人气榜单、spider为zongheng。3.5 save 入库MongoDB upsert 幂等写入榜单结果通过save方法写入 MongoDB 的novels_ranking集合见 qidian_ranking.pyasync def save(self, res_dic): try: motor_db MotorBaseOld().db await motor_db.novels_ranking.update_one( {target_url: res_dic[target_url]}, {$set: { data: res_dic[data], spider: res_dic[spider], type: res_dic[type], finished_at: time.strftime(%Y-%m-%d %X, time.localtime()) }}, upsertTrue) except Exception as e: self.logger.exception(e)几个值得注意的工程细节以target_url作为查询键同一分类榜单重复抓取时直接覆盖更新配合upsertTrue实现不存在则插入、存在则更新的幂等写入避免重复记录updated_at抓取开始时间在parse阶段写入每条榜单数据finished_at入库完成时间在save阶段写入文档外层两者可以用于监控抓取耗时MotorBaseOld来自 owllook/database/mongodb/motorbase.py是基于 MotorMongoDB 异步驱动封装的连接单例。纵横榜单的入库逻辑与起点完全一致zh_ranking.py两条榜单数据汇入同一个novels_ranking集合仅靠spider字段区分来源。四、榜单数据的定时调度与接入方式榜单是时效性数据owllook 提供了两种定时刷新方案4.1 独立调度脚本spider_console.py 是纯爬虫侧的调度入口schedule.every(60).minutes.do(start_spider) while True: schedule.run_pending() time.sleep(1)每 60 分钟依次启动QidianRankingSpider与ZHRankingSpider常驻运行适合只想同步榜单数据的部署场景。4.2 集成进项目主调度scheduled_task.py 将榜单刷新纳入 owllook 主任务体系from owllook.spiders import QidianRankingSpider, ZHRankingSpider def start_spider(): QidianRankingSpider.start() ZHRankingSpider.start() def refresh_task(): schedule.every(CONFIG.SCHEDULED_DICT[SPIDER_INTERVAL]).minutes.do(start_spider) while True: schedule.run_pending() time.sleep(1)刷新间隔由配置项SPIDER_INTERVAL控制。查 owllook/config/config.py 可知其默认值为 120分钟并支持通过环境变量覆盖SPIDER_INTERVALint(os.getenv(SPIDER_INTERVAL, 120)),两种方式都基于schedule库 time.sleep(1)的空转轮询实现启动后即可按固定周期把最新榜单写进novels_ranking。五、代理与请求可靠性中间件榜单站点对高频请求较敏感owllook 为爬虫设计了代理注入中间件位于 middlewares.pyowl_middleware.request async def add_random_proxy(request): request.kwargs.update({proxy: await update_proxy()}) request.request_config.update({RETRY_FUNC: retry_func}) async def update_proxy(): proxy await get_proxy_ip() if proxy: proxy http:// proxy else: proxy None return proxy async def retry_func(request): proxy await update_proxy() request.kwargs.update({proxy: proxy}) return request其工作方式为每次请求前从代理池动态取一个代理 IP 注入request.kwargs[proxy]并把自定义RETRY_FUNC写入请求配置重试时同样换新代理降低单 IP 连续请求被限制的风险。代理 IP 的获取实现在 spider_tools.py 的get_proxy_ip中它向CONFIG.REMOTE_SERVER[proxy_server]发起 POST 请求取回代理地址该服务地址在 config.py 中配置默认http://0.0.0.0:8002/即本地代理池服务实际部署时需指向可用代理源。使用方式榜单与书籍爬虫启动时传入该中间件如QidianRankingSpider.start(middlewaremiddleware)middleware为ruia_ua提供的 UA 中间件全站书籍爬虫则组合传入[ua_middleware, owl_middleware]见 qidian_all_novels.py同时拿到随机 UA 与随机代理。六、从榜单到全量配套的书籍数据爬虫榜单解决哪些书热门书籍爬虫解决这些书长什么样。owllook 的爬虫体系以榜单为核心入口同时配套了三类书籍数据爬虫数据最终汇入all_novels列表与all_novels_info详情两个集合爬虫文件抓取目标产出集合qidian_all_novels.py起点全站小说列表页all_novelsqidian_novel_info.py起点单本书详情页all_novels_infozongheng_all_novels.py纵横全站小说列表页all_novelszongheng_novel_info.py纵横单本书详情页all_novels_infoheiyan_novel_info.py黑岩单本书详情页all_novels_info6.1 列表页爬虫并发抓取 批量入库qidian_all_novels.py 与 zongheng_all_novels.py 的结构相同通过TextField/AttrField提取书名、作者、作者主页、分类、封面、简介等字段clean_*钩子负责把相对协议补全为https:/http:绝对地址parse中通过asyncio.ensure_future(self.save(res_dic))为每本书创建异步保存任务再用asyncio.wait(tasks)汇总结果并打印共 N 本小说抓取成功 M 本的统计信息save内以novel_url novel_name为查询键执行update_one(..., upsertTrue)幂等入库。值得留意的是二者在工程参数上的差异起点列表爬虫设置了concurrency 20、RETRIES 15、TIMEOUT 3qidian_all_novels.py纵横则开到concurrency 60、RETRIES 8zongheng_all_novels.py说明并发度与重试策略需要按目标站点承受能力单独调优。main入口按 100 页为一个批次批量生成start_urls并分页抓取起点还使用uvloop.EventLoopPolicy()替换默认事件循环以提升 asyncio 性能见 qidian_all_novels.py。6.2 详情页爬虫两类数据源策略详情爬虫存在两种典型的字段提取策略CSS 选择器策略起点、纵横如 qidian_novel_info.py 用TextField(css_select.book-infoh1em)取书名、AttrField(css_selecta#bookImgimg, attrsrc)取封面clean_status用#.join([i.text for i in status])把多个标签拼接成字符串Open Graph 元信息策略黑岩heiyan_novel_info.py 直接抓取页面meta propertyog:*标签的content属性例如og:title书名、og:novel:author作者、og:novel:latest_chapter_name最新章节信息密度更高、结构更稳定clean_latest_chapter_time还会把今天/昨日这类相对时间替换成具体日期。黑岩详情爬虫还配套了完整的单元测试 tests/test_heiyan_novel_info.py测试用例内置了一段包含og:元信息标签的真实 HTML 片段直接调用HYNovelInfoItem.get_item(htmlHTML)并断言item_data.novel_name 神仙微信群。这个测试证明了两点Item 的字段提取可以脱离网络独立验证owllook 的爬虫开发流程把页面解析与网络请求彻底解耦便于 CI 回归。七、运行前提与实战要点小结7.1 运行前提项目依赖 Ruia、ruia_ua、MotorMongoDB 异步驱动、schedule 等库依赖清单见仓库根目录 Pipfile需要可用的 MongoDB 服务榜单数据写入novels_ranking集合若启用 middlewares.py 的代理中间件需先配置好代理池服务地址CONFIG.REMOTE_SERVER[proxy_server]见 config.py目标站点页面结构可能随时间变化README 中r.qidian.com的旧入口与源码中www.qidian.com/rank/的新入口并存实际抓取时需以源码为准并注意遵守目标站点的访问规则。7.2 榜单爬虫核心链路回顾整个榜单爬虫的完整调用链可归纳为start_urls按chn参数批量生成各分类榜单 URLSpider并发请求concurrency3可挂载 UA/代理中间件parse用两级Item解析出榜单标题 更多链接 书籍 Top10clean_*钩子统一书名标题格式、补全协议头save以target_url为键、upsertTrue幂等写入novels_rankingschedule定时任务按SPIDER_INTERVAL默认 120 分钟周期性重复 15 步。7.3 可复用的扩展思路新增榜单站点参考 zh_ranking.py 为纵横写的同构实现只需定义目标页面的两级 Item CSS 选择器并将save中的spider字段替换为站点标识即可调整榜单分类修改start_urls与qidian_type映射表增强抓取稳定性复用owl_middleware的随机代理与重试换 IP 逻辑或按站点情况调整request_config中的RETRIES/DELAY/TIMEOUT。至此从 README 中一行 URL 参数表出发你已经看到了 owllook 榜单爬虫从分类构造、异步解析、数据清洗到定时入库的完整工程实现这份实现同样可以作为自建小说榜单聚合服务的参考蓝本。赞分享后端搜索引擎网页爬虫【免费下载链接】owllookowllook-小说搜索引擎项目地址https://gitcode.com/gh_mirrors/ow/owllook点击查看免费下载相关推荐时间表达式识别利器fnlp如何精准解析中文复杂时间描述时间表达式识别利器fnlp如何精准解析中文复杂时间描述 在中文自然语言处理领域时间表达式的识别与解析一直是开发者面临的重要挑战。fnlp作为一款专业的中文NLP机器学习人工智能2025最强异步爬虫框架Ruia异步Python爬虫实战指南 — 从入门到精通2025最强异步爬虫框架Ruia异步Python爬虫实战指南 — 从入门到精通 你还在为传统爬虫速度慢、资源占用高而烦恼吗面对反爬机制束手无策作为数据采集Ruia异步Python 3.6 网络爬虫微框架Ruia异步Python 3.6 网络爬虫微框架 Ruia 是一个基于 asyncio 的异步 Python 3.6 网络爬虫微框架旨在使得网络爬取工作上一篇EMQX 规则引擎 republish 动作的 Namespace 隔离修复limit_selects_in_namespace 行为详解下一篇CAMEL-AI 多智能体框架入门指南核心组件、生态体系与 5 分钟快速上手创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考