À propos de ce qu'était une banque de mangas.
La « mangabank.org » a disparu.
C'est devenu un nouveau site illégal appelé 13dl.me, mais depuis que le style de lecture en ligne a été abandonné et qu'il est devenu un type de portée de téléchargement, cet article a également été mis à jour sur le tableau, comme une nouvelle étape.
Fr:La « mangabank.org » a disparu.
https://rentry.co/hzpue
Eng:The "mangabank.org" has disappeared.
https://rentry.co/vh3py
Русский:«mangabank.org» исчез.
https://rentry.co/oq975
Spanish:El "mangabank.org" ha desaparecido.
https://rentry.co/agr95
Ja
https://rentry.co/mangabankdatta
漫画バンク、だったものについて。
漫画バンクは消えた。
新たに13dl.meという違法サイトになったが、これまでのオンラインリーディング型のスタイルを捨てて、ダウンロードリーチ型になったので、この記事もボードで更新していたのを、新たに節目としてこのようにしてみた。
過去のボード
mangaBank が消えるまで
https://crieit.net/boards/manga-B
さて、Javascript
ってどうやって書くんだろうと前々から気になっていたので、この新たな違法サイトについて、どういうものか見てみるのに Javascript
で node.js
を使ってプログラムを書いてみた。
Promise
についてよくわからなかったので、ずいぶん時間がかかったが、Nim
よりは Javascript
について書かれたドキュメントは数多くあるので、プログラムが一応動くというところまでは早かった。
node.js
をインストールして、npm
パッケージマネージャで axios
, cheerio
をインストールする。
https://github.com/axios/axios#installing
axios
が httpsリクエストするモジュールで、Promise
型の返り値で、リクエストが成功するとresponse を処理できる。cheerio
は、html テキストをオブジェクトにして css セレクターとして使う。Ruby
での nokogiri
に類する、python
での bueatifulsoup4
のような、go
での goquery
のような、Nim
での nimquery
のような扱いで使用した。こういう便利セレクターはそれぞれに使い方が似ていて違うので、よく調べないとちゃんと使えないということに慣れていない場合、使わなくても正規表現でもなんとかなるので、その場合は言語が違っても、同じ標準的な正規表現スタイルの場合は同じように書ける。go にも標準ライブラリではないけど perl 様式の正規表現モジュールはある。
RE2 is a fast, safe, thread-friendly alternative to backtracking regular expression engines like those used in PCRE, Perl, and Python. It is a C++ library.
License
BSD-3-Clause license
https://github.com/google/re2/
const cheerio = require('cheerio'),
axios = require('axios');
// url = `https://13dl.me/`;
var url = `https://13dl.me/list/popular/`;
var counter = 0;
function recursive(url){
let temp_url = url;
axios.get(url)
.then((response) => {
if (response.status == 200){
let $ = cheerio.load(response.data);
$('a').each(function (i, e) {
let title = $(e).attr('title');
let link = $(e).attr('href');
if (title !== undefined){
let h = /^Home/.test(title),
po = /^Popular\s/.test(title),
p = /^Prev/.test(title),
pa = /^Page/.test(title),
n = /^Next/.test(title);
if (h || po || p || pa || n || title === ``){
//unless
} else {
counter++;
console.log(counter + `{` + title +`{` + link);
// console.log(counter,title);
// console.log(`____________________`);
}
}
if (title === `Next`){
url = link;
// recursive(url);
}
})
if (url !== temp_url){
recursive(url);
}
}
}).catch(function (e) {
console.log(e);
recursive(url);
});
}
recursive(url);
どういうプログラムかというと、サイトにあるコンテンツを列挙していくものだ。
関数を再帰的に呼ぶのだけど、Javascript でこういう書き方するのかは、しらないまま書いたら、一応動いたので、列挙していくコンテンツを SQLite データベースに記録しよう。awk
と併用すればこの base プログラムでも SQLite3 のデータベースファイルは作れますが。区切り文字 {
で csv
にして、SQLite3 で csv
を読み込んで保存すればデータベースファイルになる。
似た感じで Ruby で書くと
require 'nokogiri'
require 'open-uri'
url = 'https://13dl.me/list/popular/'
counter = 0
threads = []
def recursive(counter,url,threads)
html = URI.open(url).read
doc = Nokogiri::HTML.parse(html)
doc.css('a').each do |x|
xx = x.attr('title')
pa = /^Page/.match?("#{xx}")
p = /^Prev/.match?("#{xx}")
if xx && xx !='' && xx !='Home' && xx !='Popular Manga' then
unless pa | p then
n = /^Next/.match?("#{xx}")
link = ''
if n then
link = x.attr('href')
threads << Thread.new do
recursive(counter,link,threads)
end
else
counter += 1
puts "#{counter} #{xx}"
end
end
end
end
end
recursive(counter,url,threads)
threads.each(&:join)
recursive
https://rentry.co/5ibqk
while
https://rentry.co/ir4b3
while
https://rentry.co/856s2
threadpool ... Work in Progress
https://rentry.co/ze8f4
recursive
https://rentry.co/f55r8
while ( for )
https://rentry.co/75gch
&sync.wait.Group{}, sync.Mutex, channel ... Work in Progress とってもスピーディー
https://rentry.co/wikwa
contents 数とpage 数の関係 | channel, sync.Mutex
https://rentry.co/o8fp4
const cheerio = require('cheerio'),
axios = require('axios');
const sqlite3 = require('sqlite3').verbose();
const db = new sqlite3.Database('13dlme0.db',(err) => {
if(err) {
return console.error(err.message);
}
console.log('Connect to SQLite database.');
});
db.serialize(() => {
db.run(`CREATE TABLE manga(id interger,title string,link string)`)
});
var url = `https://13dl.me/list/popular/`;
var counter = 0;
function recursive(url){
let temp_url = url;
axios.get(url)
.then((response) => {
if (response.status == 200){
let $ = cheerio.load(response.data);
$('a').each(function (i, e) {
let title = $(e).attr('title');
let link = $(e).attr('href');
if (title !== undefined){
let h = /^Home/.test(title),
po = /^Popular\s/.test(title),
p = /^Prev/.test(title),
pa = /^Page/.test(title),
n = /^Next/.test(title);
if (h || po || p || pa || n || title === ``){
//unless
} else {
counter++;
// console.log(counter + ` ** ` + title + ` ** ` + link);
db.run(`insert into manga(id,title) VALUES(?,?)`,[counter,title]);
console.log(counter,title);
console.log(`____________________`);
}
}
if (title === `Next`){
url = link;
}
})
if (temp_url != url){
recursive(url);
};
}
}).catch(function (e) {
console.log(e);
recursive(url);
});
}
recursive(url);
db.close()
してない。
どうやって close()
すべきだろうか ?
const cheerio = require('cheerio'),
axios = require('axios');
const sqlite3 = require('sqlite3').verbose();
const db = new sqlite3.Database('13dlme_test1-1.db',(err) => {
if(err) {
return console.error(err.message);
}
console.log('Connect to SQLite database.');
});
db.serialize(() => {
db.run(`CREATE TABLE manga(id interger,title string,link string)`)
});
var url = `https://13dl.me/list/popular/`;
var counter = 0;
function recursive(url){
const temp_url = url;
const promise1 = axios.get(url)
const promiseData1 = promise1.then((response) => {
if (response.status == 200){
let $ = cheerio.load(response.data);
$('a').each(function (i, e) {
const title = $(e).attr('title');
const link = $(e).attr('href');
if (title !== undefined){
const h = /^Home/.test(title),
po = /^Popular\s/.test(title),
p = /^Prev/.test(title),
pa = /^Page/.test(title),
n = /^Next/.test(title);
if (h || po || p || pa || n || title === ``){
//unless
} else {
counter++;
// console.log(counter + ` ** ` + title + ` ** ` + link);
db.serialize(() => {
db.run(`insert into manga(id,title) VALUES(?,?)`,[counter,title]);
});
console.log(counter,title);
console.log(`____________________`);
}
}
if ((title === `Next`) && (link != undefined)){
url = link;
}
})
} else {
console.log(response);
}
if (temp_url !== url){
return recursive(url);
// `:keep going:`;
} else {
console.log('Close SQLite database.');
return `:stop:`;
}
}).catch(function (e) {
console.log(e);
});
Promise.all([promiseData1]).then((value) => {
if (value[0] === `:stop:`){
db.close((err) => {
if(err) {
console.error(err.message);
}
});
}
});
}
recursive(url);
db.close()
できたかな?
const cheerio = require('cheerio'),
axios = require('axios');
const sqlite3 = require('sqlite3').verbose();
const db = new sqlite3.Database('13dlme_test2.db',(err) => {
if(err) {
return console.error(err.message);
}
console.log('Connect to SQLite database.');
});
db.serialize(() => {
db.run(`CREATE TABLE manga(id interger,title string,link string)`)
});
var url = `https://13dl.me/list/popular/`;
var counter = 0;
const recursive = async (url) => {
console.log(url);
const temp_url = url;
try {
const {data} = await axios.get(url);
const $ = cheerio.load(data)
$('a').each(function (i, e) {
const title = $(e).attr('title');
const link = $(e).attr('href');
if (title !== undefined){
const h = /^Home/.test(title),
po = /^Popular\s/.test(title),
p = /^Prev/.test(title),
pa = /^Page/.test(title),
n = /^Next/.test(title);
if (h || po || p || pa || n || title === ``){
//unless
} else {
counter++;
// console.log(counter + ` ** ` + title + ` ** ` + link);
db.run(`insert into manga(id,title) VALUES(?,?)`,[counter,title]);
console.log(counter,title);
console.log(`____________________`);
}
}
if ((title === `Next`) && (link != undefined)){
url = link;
}
});
if (temp_url !== url) {
recursive(url);
//`:keep going:`;
}else{
console.log('Close SQLite database.');
db.close();
//`:stop:`;
}
} catch(error) {
throw error;
}
}
recursive(url);
ただ、2
... の場合でも、クローズしてなくともデータベースには書き込めているようなので、commit
できているよう。
ハードディスクにツクツク書き込む古いPCの場合、SQLite のファイルに書き込むのに、1つづつコミットしたり、オープンクローズを繰り返すとスピードが犠牲になり遅くなるが、メモリ上にテーブル作って、データを書き込んで、できたものを最後に .db
ファイルに書き込むとコミットは最後だけで済むのでいいかもしれない。 3
, 4
のプログラムコードはそれぞれ、すべてのデータが書き込まれた場合、データベースをクローズするように書いたつもりではあるが、これではそうならないケースがあるはずだが、きれいにクローズされた。おかしいが、ノンブロッキング。追求の余地があるが、これで結果がエラーにならないから難しい。
解説すべきことは特にない。
require 'nokogiri'
require 'open-uri'
require 'sqlite3'
url = 'https://13dl.me/list/popular/'
counter = 0
threads = []
SQL =<<EOS
create table manga(
id INTEGER PRIMARY KEY,
title text
);
EOS
db = SQLite3::Database.open("13dlme.db")
db.execute(SQL)
def recursive(counter,url,threads,db)
html = URI.open(url).read
doc = Nokogiri::HTML.parse(html)
doc.css('a').each do |x|
xx = x.attr('title')
pa = /^Page/.match?("#{xx}")
p = /^Prev/.match?("#{xx}")
if xx && xx !='' && xx !='Home' && xx !='Popular Manga' then
unless pa | p then
n = /^Next/.match?("#{xx}")
link = ''
if n then
link = x.attr('href')
threads << Thread.new do
recursive(counter,link,threads,db)
end
else
counter += 1
puts "#{counter} #{xx}"
db.execute("insert into manga(id,title) values('#{counter}','#{xx}') ;")
end
end
end
end
end
recursive(counter,url,threads,db)
threads.each(&:join)
db.close
プログラムとしては、スマートフォン等でアプリの termux
、あるいは userland
が動作するのであれば root 化されていなくても node.js
がパッケージでインストール可能なので動作します。
いま現在 openssl 3 に依存する Perl5 Net::SSLeay は termux で普通にインストールするとコンパイルエラーになるため perl 5 だけ https 未対応。
Rf.
https://github.com/radiator-software/p5-net-ssleay/pull/391
https://debimate.jp/2019/03/16/androidにlinux環境を構築するuserlandがソースリーディング環/
termux の場合は、node.js
をインストール、npm
パッケージマネージャーで axios
, cheerio
, sqlite3
をインストールすれば上記のプログラムを書けるわけですが、userland
は、まず OS を選ぶところからですが、OS によって apt
だったり apk
だったりの違いがありますが node.js
をインストールできれば、あとは termux
とほぼ同じ行程です。
iOS の場合 iSh
というターミナルエミュレーターのアプリがありますが、iOS ではテストしていません。mac を持っていないのと、iOS の iphone のお古をもらったけれども、apple という会社に生理的嫌悪があるのでなかなか触れない。
Ruby や python だとライブラリのインストールまでに OS によって色々と違いがありますが、node.js
の場合、そう違いが発生しないのはメリットかもしれないですね。javascript がいいのかどうかはさておいて、ブラウザだけで動くようにも書き換えれるはずなので。
著作権管理している人としては、リストの中に管理してるタイトルがあれば、テイクダウンの手続きを。
漫画 Bank であったときは、cloudflare のプロクシー上の画像データは IP アドレスによって日本国外からのアクセスは受け付けないようになってましたが、今回はそうなっていないようですし、タイトルもアルファベットで日本語タイトルと対応させていることから海外向けの需要を意識しているのかもしれません。
第1回 | ある一つのサイト についての |
第2回 | スキャンレーション |
第3回 | ある一つのサイトについての |
第4回 | タイトルから書籍情報を探す。 |
第5回 | 漫画Bank / La « mangabank.org » a disparu. |
Crieitは誰でも投稿できるサービスです。 是非記事の投稿をお願いします。どんな軽い内容でも投稿できます。
また、「こんな記事が読みたいけど見つからない!」という方は是非記事投稿リクエストボードへ!
こじんまりと作業ログやメモ、進捗を書き残しておきたい方はボード機能をご利用ください。
ボードとは?
コメント