菠萝猫小说v2.2
https://www.boluomao.com
fried-deer (14318)3天前
【搜索方式】
• 关键词搜索:直接在搜索框输入书名或关键词
• 标签搜索:在搜索框输入"tag:标签名"或"标签:标签名"(例:"tag:玄幻")
注:标签搜索只能搜索到打上了相应标签小说,冒号不区分中英文
有效的搜索:"tag:无限流"、"标签:爽文"
无效的搜索:"tag:猫"(没有一个标签包含字样"猫")
【v2.0 更新说明】
1. 新增标签搜索功能;
2. 发现页拓展,具体新增内容自行查看;
3. 发现页新增"我的书架"入口,该书架与网页端菠萝猫书架直接同步;
【v2.1 更新说明】
1. 关键词搜索改用 rrssk 站点入口(网站合作更新);
2. 通过Java方法提交搜索,需登录(若不登录,搜索有概率跳转到可乐小说);
3. 无搜索次数限制;
【v2.2 更新说明】
1. 提交搜索改为适应当前网页算法,需登录;
【注】
反馈Bug以及书源获取添加QQ群:1040259688,如果网站有算法或加密更新,后续书源可能不再公开发布
与rrssk相关的书源如可乐小说等,亦可通过相似方法获取,不过不建议混用书源,书库内容是一样的
{
"bookSourceComment": "【搜索方式】\n• 关键词搜索:直接在搜索框输入书名或关键词 \n• 标签搜索:在搜索框输入\"tag:标签名\"或\"标签:标签名\"(例:\"tag:玄幻\")\n 注:标签搜索只能搜索到打上了相应标签小说,冒号不区分中英文\n 有效的搜索:\"tag:无限流\"、\"标签:爽文\"\n 无效的搜索:\"tag:猫\"(没有一个标签包含字样\"猫\")\n【v2.0 更新说明】\n1. 新增标签搜索功能;\n2. 发现页拓展,具体新增内容自行查看;\n3. 发现页新增\"我的书架\"入口,该书架与网页端菠萝猫书架直接同步;\n【v2.1 更新说明】\n1. 关键词搜索改用 rrssk 站点入口(网站合作更新);\n2. 通过Java方法提交搜索,需登录(若不登录,搜索有概率跳转到可乐小说);\n3. 无搜索次数限制;\n【v2.2 更新说明】\n1. 提交搜索改为适应当前网页算法,需登录;\n【注】\n反馈Bug以及书源获取添加QQ群:1040259688,如果网站有算法或加密更新,后续书源可能不再公开发布\n与rrssk相关的书源如可乐小说等,亦可通过相似方法获取,不过不建议混用书源,书库内容是一样的",
"bookSourceGroup": "菠萝猫",
"bookSourceName": "菠萝猫小说v2.2",
"bookSourceType": 0,
"bookSourceUrl": "https:\/\/www.boluomao.com",
"bookUrlPattern": "https?:\/\/www\\.boluomao\\.com\/book\/\\d+\\.html",
"customOrder": 1,
"enabled": true,
"enabledCookieJar": true,
"enabledExplore": true,
"exploreUrl": "@js:\nvar result = [];\nvar bigStyle = { \"layout_flexGrow\": 1, \"layout_flexBasisPercent\": 1 };\nvar uniformStyle = { \"layout_flexGrow\": 1, \"layout_flexBasisPercent\": 0.25 };\n\n\/* ===== 我的书架(对接书架API,自动遍历分页) ===== *\/\nresult.push({ \"title\": \"我的书架\", \"url\": \"\/api\/bookcase.php?page=1\", \"style\": bigStyle });\n\n\/* ===== 男生(大按钮)+ 子分类平铺 ===== *\/\nresult.push({ \"title\": \"男生\", \"url\": \"\/gender\/boy\/page\/{{page}}\/,{\\\"webView\\\":true}\", \"style\": bigStyle });\nvar boySubs = [\n [\"全部\",\"\/gender\/boy\/page\/{{page}}\/\"],[\"玄幻\",\"\/gender\/boy\/category\/1\/page\/{{page}}\/\"],\n [\"奇幻\",\"\/gender\/boy\/category\/2\/page\/{{page}}\/\"],[\"武侠\",\"\/gender\/boy\/category\/3\/page\/{{page}}\/\"],\n [\"仙侠\",\"\/gender\/boy\/category\/4\/page\/{{page}}\/\"],[\"都市\",\"\/gender\/boy\/category\/5\/page\/{{page}}\/\"],\n [\"军事\",\"\/gender\/boy\/category\/6\/page\/{{page}}\/\"],[\"历史\",\"\/gender\/boy\/category\/7\/page\/{{page}}\/\"],\n [\"游戏\",\"\/gender\/boy\/category\/8\/page\/{{page}}\/\"],[\"体育\",\"\/gender\/boy\/category\/9\/page\/{{page}}\/\"],\n [\"科幻\",\"\/gender\/boy\/category\/10\/page\/{{page}}\/\"],[\"诸天无限\",\"\/gender\/boy\/category\/11\/page\/{{page}}\/\"],\n [\"悬疑\",\"\/gender\/boy\/category\/12\/page\/{{page}}\/\"]\n];\nfor (var i = 0; i < boySubs.length; i++) {\n result.push({ \"title\": boySubs[i][0], \"url\": boySubs[i][1] + ',{\\\"webView\\\":true}', \"style\": uniformStyle });\n}\n\n\/* ===== 女生(大按钮)+ 子分类平铺 ===== *\/\nresult.push({ \"title\": \"女生\", \"url\": \"\/gender\/girl\/page\/{{page}}\/,{\\\"webView\\\":true}\", \"style\": bigStyle });\nvar girlSubs = [\n [\"全部\",\"\/gender\/girl\/page\/{{page}}\/\"],[\"古代言情\",\"\/gender\/girl\/category\/13\/page\/{{page}}\/\"],\n [\"仙侠奇缘\",\"\/gender\/girl\/category\/14\/page\/{{page}}\/\"],[\"现代言情\",\"\/gender\/girl\/category\/15\/page\/{{page}}\/\"],\n [\"浪漫青春\",\"\/gender\/girl\/category\/16\/page\/{{page}}\/\"],[\"玄幻言情\",\"\/gender\/girl\/category\/17\/page\/{{page}}\/\"],\n [\"悬疑推理\",\"\/gender\/girl\/category\/18\/page\/{{page}}\/\"],[\"科幻空间\",\"\/gender\/girl\/category\/19\/page\/{{page}}\/\"],\n [\"游戏竞技\",\"\/gender\/girl\/category\/20\/page\/{{page}}\/\"],[\"短篇言情\",\"\/gender\/girl\/category\/21\/page\/{{page}}\/\"],\n [\"耽美\",\"\/gender\/girl\/category\/32\/page\/{{page}}\/\"],[\"百合\",\"\/gender\/girl\/category\/33\/page\/{{page}}\/\"],\n [\"轻小说\",\"\/gender\/girl\/category\/34\/page\/{{page}}\/\"]\n];\nfor (var i = 0; i < girlSubs.length; i++) {\n result.push({ \"title\": girlSubs[i][0], \"url\": girlSubs[i][1] + ',{\\\"webView\\\":true}', \"style\": uniformStyle });\n}\n\n\/* ===== 二次元(大按钮)+ 子分类平铺 ===== *\/\nresult.push({ \"title\": \"二次元\", \"url\": \"\/gender\/acg\/page\/{{page}}\/,{\\\"webView\\\":true}\", \"style\": bigStyle });\nvar acgSubs = [\n [\"全部\",\"\/gender\/acg\/page\/{{page}}\/\"],[\"原生幻想\",\"\/gender\/acg\/category\/22\/page\/{{page}}\/\"],\n [\"恋爱日常\",\"\/gender\/acg\/category\/23\/page\/{{page}}\/\"],[\"衍生同人\",\"\/gender\/acg\/category\/24\/page\/{{page}}\/\"],\n [\"搞笑吐槽\",\"\/gender\/acg\/category\/25\/page\/{{page}}\/\"]\n];\nfor (var i = 0; i < acgSubs.length; i++) {\n result.push({ \"title\": acgSubs[i][0], \"url\": acgSubs[i][1] + ',{\\\"webView\\\":true}', \"style\": uniformStyle });\n}\n\n\/* ===== 热门专题(占位大按钮)+ 入口(去掉\"小说\"字样) ===== *\/\nresult.push({ \"title\": \"热门专题\", \"url\": \"\", \"style\": bigStyle });\nvar hotTopics = [\n [\"SF轻小说\",\"\/topic\/1.html?p={{page}}\"],[\"刺猬猫\",\"\/topic\/2.html?p={{page}}\"],\n [\"少年梦\",\"\/topic\/3.html?p={{page}}\"],[\"飞卢\",\"\/topic\/4.html?p={{page}}\"]\n];\nfor (var i = 0; i < hotTopics.length; i++) {\n result.push({ \"title\": hotTopics[i][0], \"url\": hotTopics[i][1] + ',{\\\"webView\\\":true}', \"style\": uniformStyle });\n}\n\n\/* ===== 最新专题(占位大按钮)+ 入口(去掉\"小说\"字样) ===== *\/\nresult.push({ \"title\": \"最新专题\", \"url\": \"\", \"style\": bigStyle });\nvar newTopics = [\n [\"息壤\",\"\/topic\/5.html?p={{page}}\"],[\"次元姬\",\"\/topic\/6.html?p={{page}}\"]\n];\nfor (var i = 0; i < newTopics.length; i++) {\n result.push({ \"title\": newTopics[i][0], \"url\": newTopics[i][1] + ',{\\\"webView\\\":true}', \"style\": uniformStyle });\n}\n\nJSON.stringify(result);",
"header": "{\n \"User-Agent\": \"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/120.0.0.0 Safari\/537.36\"\n}",
"lastUpdateTime": "1786595204336",
"loginUrl": "https:\/\/www.boluomao.com\/user\/login\/",
"respondTime": 180000,
"ruleBookInfo": {
"author": "@css:.bookTitleLeft a.author@text",
"coverUrl": "@css:meta[property=og:image]@content",
"intro": "@css:meta[property=og:description]@content || #bookIntro@text",
"kind": "@css:.info dl dt:contains(分类) + dd a@text && .info dl dt:contains(状态) + dd@text && .info dd.tags-line a@text",
"lastChapter": "@css:.info a.latest-link@text",
"name": "@css:h1.font36@text || meta[property=og:title]@content## 全文免费阅读.*|全文免费阅读.*|_.*",
"tocUrl": "{{baseUrl}}",
"wordCount": "@css:.txtb > .about .num@text"
},
"ruleContent": {
"content": "<js>\nvar doc = org.jsoup.Jsoup.parse(result);\ndoc.select(\"[style*='display:none']\").remove();\ndoc.select(\"[style*='display: none']\").remove();\ndoc.select(\"[style*='font-size:0']\").remove();\ndoc.select(\"[style*='font-size: 0']\").remove();\ndoc.select(\"[style*='visibility:hidden']\").remove();\ndoc.select(\"[style*='visibility: hidden']\").remove();\n\nvar paragraphs = doc.select(\"div.content p\").toArray();\nvar textList = [];\nfor (var i = 0; i < paragraphs.length; i++) {\n var txt = paragraphs[i].text().trim();\n if (txt) {\n textList.push(txt);\n }\n}\ntextList.join('\\n\\n');\n<\/js>",
"nextContentUrl": "<js>\nvar doc = org.jsoup.Jsoup.parse(result);\nvar a = doc.select(\"div.readPage a:contains(下一页)\").first();\nif (a) {\n var href = a.attr(\"href\");\n if (href && href.trim() != \"\") {\n var url = href.startsWith(\"http\") ? href : \"https:\/\/www.boluomao.com\" + href;\n url + ',{\"webView\":true}';\n } else {\n null;\n }\n} else {\n null;\n}\n<\/js>"
},
"ruleExplore": {
"author": "@css:span.author@text##作者:",
"bookList": "<js>\nvar isBookcase = typeof result === 'string' && result.trim().indexOf('{') === 0;\nif (isBookcase) {\n var allBooks = [];\n var page = 1;\n while (page <= 200) {\n var apiUrl = 'https:\/\/www.boluomao.com\/api\/bookcase.php?page=' + page;\n var resp;\n try {\n resp = java.ajax(apiUrl);\n } catch (e) {\n break;\n }\n if (!resp || resp.trim().length === 0) {\n break;\n }\n var json;\n try {\n json = JSON.parse(resp);\n } catch (e) {\n break;\n }\n if (!json.data || json.data.length === 0) {\n break;\n }\n for (var i = 0; i < json.data.length; i++) {\n allBooks.push(json.data[i]);\n }\n page++;\n }\n var html = '<div class=\"picList\"><ul>';\n for (var i = 0; i < allBooks.length; i++) {\n var book = allBooks[i];\n var href = '\/book\/' + book.articleid + '.html';\n var name = book.articlename || '';\n var cover = book.cover || '';\n var author = book.author || '';\n var size = book.size != null ? String(book.size) : '';\n var newest = book.newest_chapter_name || '';\n html += '<li><div class=\"picb\"><img src=\"' + cover + '\"><\/div>';\n html += '<div class=\"txtb\"><div class=\"name\"><a href=\"' + href + '\">' + name + '<\/a><\/div>';\n html += '<span class=\"author\">' + author + '<\/span>';\n html += '<span class=\"label\">' + newest + '<\/span>';\n html += '<span class=\"num\">字数:' + size + '<\/span>';\n html += '<div class=\"intro\"><\/div>';\n html += '<\/div><\/li>';\n }\n html += '<\/ul><\/div>';\n org.jsoup.Jsoup.parse(html).select('div.picList ul li');\n} else {\n org.jsoup.Jsoup.parse(result || '').select('div.picList ul li');\n}\n<\/js>",
"bookUrl": "@css:div.txtb div.name a@href##$##,{\"webView\":true}",
"coverUrl": "@css:div.picb img@src",
"intro": "@css:div.intro@text",
"kind": "@css:span.label@text",
"name": "@css:div.txtb div.name a@text## 全文免费阅读.*|全文免费阅读.*|_.*",
"wordCount": "@css:span.num@text##字数:"
},
"ruleSearch": {
"author": "<js>\nvar e = org.jsoup.Jsoup.parse(result);\nvar author = '';\nif (e.select('div.book-card__meta').size() > 0) {\n var spans = e.select('div.book-card__meta span.book-card__meta-item');\n for (var i = 0; i < spans.size(); i++) {\n var txt = String(spans.get(i).text());\n if (txt.indexOf('作者:') === 0) {\n author = txt.replace('作者:', '').trim();\n break;\n }\n }\n} else {\n author = String(e.select('span.author').text()).replace('作者:', '');\n}\nauthor;\n<\/js>",
"bookList": "<js>\nvar doc = org.jsoup.Jsoup.parse(result);\nif (doc.select('div.book-list').size() > 0 || doc.select('div.book-card').size() > 0) {\n doc.select('div.book-card');\n} else {\n doc.select('div.picList ul li');\n}\n<\/js>",
"bookUrl": "<js>\nvar e = org.jsoup.Jsoup.parse(result);\nvar url = '';\nif (e.select('div.book-card').size() > 0) {\n var onclick = e.select('div.book-card').attr('onclick');\n var m = onclick.match(\/t=([A-Za-z0-9+\/=]+)\/);\n if (m) {\n var decoded = java.base64Decode(m[1]);\n var idMatch = decoded.match(\/\\\/(\\d+)\\.html\/);\n if (idMatch) {\n url = 'https:\/\/www.boluomao.com\/book\/' + idMatch[1] + '.html';\n } else {\n url = decoded;\n }\n }\n} else {\n var a = e.select('div.txtb div.name a').first();\n if (a) {\n url = a.attr('href');\n if (url && !url.startsWith('http')) {\n url = 'https:\/\/www.boluomao.com' + url;\n }\n }\n}\nurl ? url + ',{\"webView\":true}' : '';\n<\/js>",
"coverUrl": "<js>\nvar e = org.jsoup.Jsoup.parse(result);\nif (e.select('div.book-card__cover img').size() > 0) {\n e.select('div.book-card__cover img').attr('src');\n} else {\n e.select('div.picb img').attr('src');\n}\n<\/js>",
"intro": "<js>\nvar e = org.jsoup.Jsoup.parse(result);\nif (e.select('p.book-card__desc').size() > 0) {\n e.select('p.book-card__desc').text().trim();\n} else {\n e.select('div.intro').text();\n}\n<\/js>",
"kind": "<js>\nvar e = org.jsoup.Jsoup.parse(result);\nvar kinds = [];\nfunction addKind(val) {\n val = String(val).trim();\n if (val && kinds.indexOf(val) === -1) kinds.push(val);\n}\nif (e.select('div.book-card').size() > 0) {\n var metaItems = e.select('div.book-card__meta span.book-card__meta-item');\n for (var i = 0; i < metaItems.size(); i++) {\n var txt = String(metaItems.get(i).text());\n if (txt.indexOf('分类:') === 0) {\n addKind(txt.replace('分类:', ''));\n }\n }\n addKind(e.select('span.book-tag--status').text());\n var tags = e.select('div.book-card__tags span.book-tag:not(.book-tag--status)');\n for (var i = 0; i < tags.size(); i++) {\n addKind(tags.get(i).text());\n }\n var update = String(e.select('span.book-card__update').text()).replace('更新:', '');\n addKind(update);\n} else {\n addKind(e.select('span.label').text());\n}\nkinds.join(',');\n<\/js>",
"name": "<js>\nvar e = org.jsoup.Jsoup.parse(result);\nif (e.select('h3.book-card__title').size() > 0) {\n e.select('h3.book-card__title').text();\n} else {\n var t = e.select('div.txtb div.name a').text();\n String(t).replace(\/ 全文免费阅读.*|全文免费阅读.*|_.*\/, '');\n}\n<\/js>",
"wordCount": "<js>\nvar e = org.jsoup.Jsoup.parse(result);\nif (e.select('span.num').size() > 0) {\n String(e.select('span.num').text()).replace('字数:', '');\n} else {\n '';\n}\n<\/js>"
},
"ruleToc": {
"chapterList": "@css:#chapters .direList ul li a",
"chapterName": "text",
"chapterUrl": "href##$##,{\"webView\":true}",
"nextTocUrl": "<js>\nvar doc = org.jsoup.Jsoup.parse(result);\nvar nextA = doc.select(\"div.page-range-list span.cur + a\").first();\nif (nextA) {\n var href = nextA.attr(\"href\");\n if (href && href.trim() != \"\") {\n var url = href.startsWith(\"http\") ? href : \"https:\/\/www.boluomao.com\" + href;\n url + ',{\"webView\":true}';\n } else {\n null;\n }\n} else {\n null;\n}\n<\/js>"
},
"searchUrl": "<js>\n(function() {\n \/\/ 1. 判断是否是标签搜索\n function isTagSearch(key) {\n return \/^(tag|标签)[::]\/.test(key);\n }\n \n if (isTagSearch(key)) {\n java.longToast('🔍 正在使用标签搜索(菠萝猫搜索)');\n var tag = key.replace(\/^(tag|标签)[::]\/, '').trim();\n var baseUrl = 'https:\/\/www.boluomao.com\/tag\/' + java.encodeURI(tag) + '\/';\n return page > 1 ? baseUrl + 'page\/' + page + '\/' : baseUrl;\n }\n\n \/\/ 2. 关键词搜索逻辑 (通过缓存和 rrssk.com 动态签名)\n var cacheKey = \"rrssk_find_url_\" + java.md5Encode(key);\n var targetUrl = cache.get(cacheKey);\n\n if (!targetUrl) {\n java.longToast('🔍 正在安全连接并检索书籍...');\n var window = {};\n \n \/\/ 获取中转页 HTML\n var resHtml = java.get('https:\/\/www.rrssk.com\/boluomao.html', {\n \"User-Agent\": \"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/120.0.0.0 Safari\/537.36\",\n \"Referer\": \"https:\/\/www.rrssk.com\/\"\n }).body();\n\n \/\/ 提取 _t\n var tMatch = resHtml.match(\/name=\"_t\"\\s+value=\"([^\"]+)\"\/);\n if (!tMatch) {\n throw new Error(\"无法从中转页获取到签名令牌(_t)\");\n }\n var tVal = tMatch[1];\n\n \/\/ 依次执行所有内联 script,加载签名函数及可能用到的加密工具函数\n var scriptRegex = \/<script[^>]*>([\\s\\S]*?)<\\\/script>\/gi;\n var match;\n var foundSign = false;\n while ((match = scriptRegex.exec(resHtml)) !== null) {\n var code = match[1];\n if (code && code.trim().length > 0) {\n try {\n eval(code);\n if (code.indexOf(\"__SIGN\") !== -1) {\n foundSign = true;\n }\n } catch(e) {\n \/\/ 忽略部分因缺少浏览器DOM环境引起的无害报错\n }\n }\n }\n\n if (!foundSign || !window.__SIGN || typeof window.__SIGN.f !== 'function') {\n throw new Error(\"未能成功初始化动态签名算法,请反馈至作者维护\");\n }\n\n \/\/ 与 PHP rawurlencode 完全一致的 RFC3986 编码\n function __enc(x) {\n return encodeURIComponent(x).replace(\/[!'()*]\/g, function(c) {\n return '%' + c.charCodeAt(0).toString(16).toUpperCase();\n });\n }\n\n var ts = Math.floor(Date.now() \/ 1000);\n var s = window.__SIGN.f(__enc(key), tVal, ts);\n\n \/\/ 构造载荷提交 POST 搜索请求\n var postData = \"action=search&_t=\" + tVal + \"&_ts=\" + ts + \"&_s=\" + s + \"&keyword=\" + java.encodeURI(key);\n var postRes = java.post(\"https:\/\/www.rrssk.com\/?action=search\", postData, {\n \"Content-Type\": \"application\/x-www-form-urlencoded\",\n \"Referer\": \"https:\/\/www.rrssk.com\/boluomao.html\",\n \"User-Agent\": \"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/120.0.0.0 Safari\/537.36\"\n });\n\n \/\/ 获取最终的 find 重定向页面地址\n targetUrl = postRes.url().toString();\n\n if (!targetUrl || targetUrl.indexOf(\"action=find\") === -1) {\n var loc = postRes.header(\"Location\");\n if (loc) {\n if (!loc.startsWith(\"http\")) {\n targetUrl = \"https:\/\/www.rrssk.com\" + (loc.startsWith(\"\/\") ? \"\" : \"\/\") + loc;\n } else {\n targetUrl = loc;\n }\n }\n }\n\n if (!targetUrl || targetUrl.indexOf(\"action=find\") === -1) {\n throw new Error(\"未能进入有效的搜索结果页面,请尝试重新搜索\");\n }\n\n \/\/ 规范化 URL,剔除原有 page 参数以供后续动态翻页拼接\n targetUrl = targetUrl.replace(\/[&?]page=\\d+\/g, \"\");\n cache.put(cacheKey, targetUrl, 300); \/\/ 结果地址写入缓存 (有效期 5 分钟)\n }\n\n var conn = targetUrl.indexOf(\"?\") !== -1 ? \"&\" : \"?\";\n return targetUrl + conn + \"page=\" + page;\n})()\n<\/js>",
"weight": 0
}