node.jsを使って「はてなブログ」の記事から画像を引っこ抜く事ができました
基軸になるXMLは以下で簡単にダウンロードできます
masalib.hatenablog.com
概要
はてな記事のXMLからcontens部分を抽出してその中に記載している画像のみをダウンロードする
単純に全画像を引っこ抜くなら超ー簡単なのですが
いらない画像はダウンロードしたくないので選別しています
ソース
var fs = require('fs'), che = require('cheerio'); var client = require('cheerio-httpcli'); const {HATENA_SITE_ID, HATENA_SITE_PW} = require('./config.json'); //markdownの場合 //var xml_data = fs.readFileSync("./tempxml/10328537792363751905.xml", "utf-8"); //htmlの場合 var xml_data = fs.readFileSync("./tempxml/10328749687197681522.xml", "utf-8"); //解説1 $ = che.load(xml_data, { xmlMode: true }); //リンクされているページを取得 $("link").each(function(idx){ if ($(this).attr('rel') == 'edit'){ edit_url= ($(this).attr('href')); //ブログを更新時に使用する } else { alternate_url= ($(this).attr('href'));//画像を引っこ抜く時に使う } }); var content_type = $("content").attr('type'); var content = $("content").html(); var image_id = []; var image_id_replace = []; //置き換えるようの配列 var image_id_index = []; //検索用の配列 //解説2 if (content_type == "text/x-hatena-syntax" || content_type == "text/x-markdown" ) { //はてな表記とmarkdownの場合 //[f:id:masalib:20161026224357p:plain]みたいな形になっている。それを引っこ抜く var s = content; var r = /\[([^\]]*)\]/g; while ((m = r.exec(s)) != null) { if ( m[1].indexOf('f:id:') != -1) { image_id.push(m[1]); //変換前(この時点では変換前も変換後も同じ) image_id_replace.push(m[1]);//変換後(この時点では変換前も変換後も同じ) image_id_index.push(m[1]); //ダウンロード判定の配列 } } } else { console.log("htmlの場合"); $xml_content = che.load(content); $xml_content("img").each(function(i, el) { //console.log($xml_content(this).toString() ); image_id.push($xml_content(this).toString());//変換前(この時点では変換前も変換後も同じ) image_id_replace.push($xml_content(this).toString() );//変換後(この時点では変換前も変換後も同じ) image_id_index.push($xml_content(this).attr('src'));//ダウンロード判定の配列 }); } //解説3 //記事のURLから画像引っこ抜く alternate_url //実行フォルダの配下にdlimageフォルダはあるものとする // ①ダウンロードマネージャーの設定(全ダウンロードイベントがここで処理される) // dlimageというフォルダはある前提 client.download .on('ready', function (stream) { var filename_ex = stream.url.href.match(".+/(.+?)([\?#;].*)?$")[1]; var filename = stream.url.href.match(".+/(.+?)\.[a-z]+([\?#;].*)?$")[1]; var i = 0; image_id_index.forEach(function(temp_fileid){ if ( temp_fileid.indexOf(filename) != -1) { console.log('./dlimage/' + filename_ex); stream.pipe(fs.createWriteStream('./dlimage/' + filename_ex )); console.log(stream.url.href + 'をダウンロードしました'); image_id[i] = filename; } else { console.log(stream.url.href + 'をダウンロードしません'); } console.log(temp_fileid); i += 1; }); }) .on('error', function (err) { console.error(err.url + 'をダウンロードできませんでした: ' + err.message); }) .on('end', function () { console.log('ダウンロードが完了しました'); }); // ④並列ダウンロード制限の設定 client.download.parallel = 4; // ②スクレイピング開始 client.fetch(alternate_url, function (err, $, res, body) { // ③imgタグをダウンロード(imageがない時の処理が足りない・・・) $('img').download(); console.log('OK!'); });
解説
解説1
if ($(this).attr('rel') == 'edit'){ edit_url= ($(this).attr('href')); //ブログを更新時に使用する } else { alternate_url= ($(this).attr('href'));//画像を引っこ抜く時に使う }
はてなブログの記事はかならず
記事の更新用URLと表示用のURLがあります
どちらも後続処理で使うので取得します
解説2
if (content_type == "text/x-hatena-syntax" || content_type == "text/x-markdown" ) {
はてなブログは、「markdown」と「はてな表記」と「HTML」の形式があります
「markdown」と「はてな表記」のimageの記載方法は、同じっぽい・・・
どちらとも正規表現で抽出する事で対応
var s = content; var r = /\[([^\]]*)\]/g; while ((m = r.exec(s)) != null) { if ( m[1].indexOf('f:id:') != -1) {
「HTML」は普通のimgタグなので、そちらを配列にいれます
後続の更新処理で使う予定です
$xml_content = che.load(content); $xml_content("img").each(function(i, el) { //console.log($xml_content(this).toString() ); image_id.push($xml_content(this).toString());//変換前(この時点では変換前も変換後も同じ) //例 //<img class="hatena-fotolife" title="f:id:masalib:20161207001505j:image" src="https://cdn-ak.f.st-hatena.com/images/fotolife/m/masalib/20161207/20161207001505.jpg" alt="f:id:masalib:20161207001505j:image">
cheerioの公式サイトに「toString()」のメソッドが書いておらず、困った
ブログレベルだと、表示されないものもあるらしい
テストしながら判別していきます
解説3
client.download .on('ready', function (stream) { ・
ダウンロードはcheerio-httpcliの本家のサンプルから作りました
テストデータが少なくて気が付かなかったけど
はてなフォト以外の画像は引っこ抜く必要がないかも
選択できるようにするべきかも
はてなブログをnode.jsで更新シリーズの進捗
・記事データをXMLとしてダウンロード
完了
・記事データXMLから画像をダウンロード
はてな表記:完了 ←★NOW
HTML:完了 ←★NOW
MARKDOWN:完了 ←★NOW
・画像をクオリティーを下げずに圧縮 完了
あとは組み込むだけ
・画像をはてなフォトにアップ
画像アップ 完了
アップした内容からXMLを更新:未完
・記事データのSSL化
はてな表記:現在進行中
HTML:未完
MARKDOWN:未完
変更箇所を洗い出し中
・記事データXMLから記事を更新
はてな表記:完了(組み込むだけ)
HTML:未完
MARKDOWN:未完
・XMLをもとに検証用ブログにアップする(追加:2017/09/27)
・手順書作成(追加:2017/09/27)
JS+Node.jsによるWebクローラー/ネットエージェント開発テクニック
- 作者: クジラ飛行机
- 出版社/メーカー: ソシム
- 発売日: 2015/08/31
- メディア: 単行本
- この商品を含むブログ (2件) を見る