您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
从日本读书网站摘取书评显示在豆瓣读书条目页面
// ==UserScript== // @name 豆瓣読書泥棒 // @namespace https://gimo.me/ // @version 0.3.0 // @description 从日本读书网站摘取书评显示在豆瓣读书条目页面 // @author Yuanji // @match https://book.douban.com/subject/* // @connect booklog.jp // @grant GM_xmlhttpRequest // @license MIT // ==/UserScript== function buildCommentItem(props) { return ` <li class="comment-item" data-cid="549875751"> <div class="comment"> <h3> <span class="comment-info"> <a href=${props.url}>${props.author}</a> <span class="user-stars allstar${props.rating}0 rating" title="推荐"></span> <span>${props.date}</span> </span> </h3> <p class="comment-content"> <span class="short">${props.content}</span> </p> </div> </li> ` } function buildRatingInfo(props, isbn10) { starValue = Math.round(props.rating) * 5 url = `https://booklog.jp/item/1/${isbn10}` return ` <div class="rating_wrap clearbox" rel="v:rating"> <div class="rating_logo">ブクログのレビュー</div> <div class="rating_self clearfix" typeof="v:Rating"> <strong class="ll rating_num " property="v:average"> ${props.rating} </strong> <span property="v:best" content="10.0"></span> <div class="rating_right "> <div class="ll bigstar${starValue}"></div> <div class="rating_sum"> <span class=""> <a href="${url}" class="rating_people">レビュー<span property="v:votes">${props.count}</span>件</a> </span> </div> </div> </div> </div> ` } function getISBN() { const metaInfo = document.querySelector('head > script[type="application/ld+json"]') if (metaInfo) { return JSON.parse(metaInfo.textContent)['isbn'] } } function isJapaneseBook(isbn) { return (typeof isbn === 'string' && isbn[3] === '4') } function Request(url, method, opt = {}) { Object.assign(opt, { url, timeout: 2000, headers: { 'User-Agent': window.navigator.userAgent }, method: method }) return new Promise((resolve, reject) => { opt.onerror = opt.ontimeout = reject opt.onload = resolve GM_xmlhttpRequest(opt) }) } function parseBooklogReview(el) { const reviewAuthorElement = el.querySelector('span[class="reviewer"]') const reivewDateElement = el.querySelector('p[class="review-date"]') const reviewURLElement = reivewDateElement && reivewDateElement.firstElementChild const reviewTextElement = el.querySelector('p[class="review-txt"]') const reviewRatingElement = el.querySelector('span[itemprop="ratingValue"]') // すべては存在すべき if (![reviewAuthorElement, reivewDateElement, reviewURLElement, reviewTextElement, reviewRatingElement].every(i => !!i)) { return null } return { author: reviewAuthorElement.textContent.trim(), date: reivewDateElement.textContent.trim(), url: reviewURLElement.href.replace('book.douban.com', 'booklog.jp'), content: reviewTextElement.innerHTML, rating: reviewRatingElement.getAttribute('content') } } function parseBooklogRating(doc) { ratingDiv = doc.querySelector('div[class="rating-value"]') rating = ((+ratingDiv.innerText.split('\n')[0])*2).toFixed(1) count = +doc.querySelector('span[itemprop="reviewCount"]').innerText return { rating, count } } function ISBN13ToISBN10(isbn13) { const commonChars = isbn13.slice(3, -1) let sum = 0 for (const [idx, char] of Array.from(commonChars).entries()) { sum += (10 - idx) * parseInt(char) } let checkDigest = (11 - (sum % 11)) % 11 checkDigest = checkDigest !== 10 ? checkDigest.toString() : 'X' return commonChars + checkDigest } (function () { 'use strict' const isbn = getISBN() if (!(isbn && isJapaneseBook(isbn))) { return } const navTab = document.querySelector('div[class="nav-tab"]') // ブクログのタブを追加する navTab.firstElementChild.insertAdjacentHTML('beforeend', `<span>/<span><a class="short-comment-tabs" href="booklog" data-tab="booklog">ブクログ</a>`) const commentListWrapper = document.getElementById('comment-list-wrapper') commentListWrapper.insertAdjacentHTML('beforeend', `<div id="comments" class="comment-list booklog noshow"><ul id="booklog-review-list"></ul></div>`) const booklogReviewList = document.getElementById('booklog-review-list') const RatingInfoList = document.getElementById('interest_sectl') const isbn10 = ISBN13ToISBN10(isbn) const booklogURL = `https://booklog.jp/item/1/${isbn10}?perpage=10&rating=0&is_read_more=2&sort=1` console.log(booklogURL) Request(booklogURL, 'GET').then(res => { const booklogHTML = res.responseText const booklogDoc = new DOMParser().parseFromString(booklogHTML, "text/html") return booklogDoc }).then(doc => { const reviewList = doc.querySelectorAll('li[class="review clearFix"]') const reviewPropsList = [] for (let li of reviewList) { const props = parseBooklogReview(li) if (props) { console.log(props) reviewPropsList.push(props) } } for (let props of reviewPropsList) { const review = document.createElement('li') review.innerHTML = buildCommentItem(props) booklogReviewList.appendChild(review) } console.log(doc.location) RatingInfoList.insertAdjacentHTML('beforeend', buildRatingInfo(parseBooklogRating(doc), isbn10)) }) })();