FC2 BLOG(628)の編集について
アイテム: FC2 BLOG - データベース: AutoPagerize - wedata
この編集の意図を教えていただけるとありがたいです。https://t.co/Qq7zhabgU1
— 小川謙三 (@kogawa_vonly) January 21, 2022
伺いたい点は2つほどあります。まずはurlについてです。
url | length | |
私案 | ^.+://.+\.blog(.+)?\.fc2\.com | 29 |
現状 | ^\w+://[^/]+\.blog\d*\.fc2\.com | 31 |
おそらく極力長さを短くしたいという意図は伝わっていると思うのですが、あえて2長くしていることで得られるメリットは何でしょうか。
次にpageElementについてです。
私案 | id("main")/node()[not(string-length(//link[@rel="top"]/@href)<34)] |
現状 | id("main")[*/@class='page_navi']/node() |
マジックナンバーを外すのはわかりますが、page_naviクラスを参照することで得られるメリットは何でしょうか。
もしこのまま返事が来なければ、こういう編集をしようかと思います。
url
url | length | |
現状 | ^\w+://[^/]+\.blog\d*\.fc2\.com | 31 |
改案 | ^.+://.+\.blog\d*\.fc2\.com | 27 |
pageElement
現状 | id("main")[*/@class='page_navi']/node() |
改案 | id("main")/node() |
Griverさんへの返信 その3
少し退屈かもしれませんが、今回は精神論の話をさせてください。
編集合戦の火蓋を切ってませんか?トマ村さんが応戦してきたら開戦してる気がします。
これだけは言いきれます。トマ村さんがご自分のコードに戻していたとしても、編集合戦は起きません。
なぜそもそもWedataを更新しているのか考えてみたのですが、コードを弄ること自体が好きだからです。ある意味初めて作ったミニ四駆をコースで走らせている小学生となんら変わらないとさえ思います。
テキストノードがどうの、クオーテーションがどうのという話はごく表層的な上っ面だけの話で本質的にそんなことはどうでもいいのです。もしかしたら、機能性や安定性だってどうでもいいのかもしれません。ここまで編集を続けられているのは、ただただ楽しいという理由だけだからです。
Grieverさんが長いXPathを管理しているのだって楽しいという気持ちがあるからではありませんか?
なんとか改善策を見つけたいんですがソースが汚いし7000文字とかの XPath 作り出しててデバッグが大変なので時間かかりそうです。
— Griever (@Griever2) December 7, 2021
好きだからこそ人とぶつかりあうこともあるのですが、長いこと続けているとなんとなく引き際は見極められます。長く編集を続けられている方とは信頼関係があるからですね。できればGrieverさんともそういう信頼関係を築きたいと思っています。
@class も contains もクォーテーションも使っていい条件なら walkerplus article_list は
//div[@class='m-mainlist']
や
//ul[@class='m-newslist__list']
や
//li[@class='m-newslist__item']
ではダメなんですか?(動作確認はしていません)
まず現状はこうしています。
//li[./a[contains(@href,"/article/")]]
アイテム: walkerplus article_list - データベース: AutoPagerize - wedata
なぜ単にクラス名で指定しないかというと、理由は2つあります。
1.初見のサイトでクラス名をどこまで信用していいか分からない
これまで長いクラス名を信用しすぎて痛い目を見てきた経験からの判断です。
2.誰でも書けるコードを書くのはつまらない
メンテナンスを軽んじるつもりはないのですが、長く続けていると飽きがきます。ずっと楽しんで編集を続けるにはもっと難しい課題に挑戦したいのです。
追記
本丸も更新しました。ようやくトマ村さんのコードに追いついた感があります。
descendant::*[contains(@class,"date")][1]/../following-sibling::div[./figure or ./ul]
アイテム: walkerplus - データベース: AutoPagerize - wedata
結局どうするのか
今回の騒動を引き起こしたそもそものきっかけであるwalkerplus(85745)をどうするかという話です。
アイテム: walkerplus - データベース: AutoPagerize - wedata
トマ村さん案
//main/section/node()[contains(.,'start ニュース本文')]/following-sibling::*[following-sibling::node()[contains(.,'end ニュース本文')]]
更新案A
//main//ul[.//img]|descendant::*[./figure/a][1]
更新案B
descendant::*[./figure/a][1]|//a[@rel="next" or @rel="prev"]/ancestor::div[./following-sibling::div][1]/preceding-sibling::div[1]//ul
更新案C(現状)
descendant::*[./figure/a][1]|descendant::*[count(./preceding-sibling::div)>1 and count(./following-sibling::div)>1][1][count(./*)>1 or ./ul]
テキストノードを使いたくないのでトマ村さん案を更新したのですがGrieverさんの評価は思った以上に高いようです。たしかに階層を順にたどって考えればよいという意味ではシンプルなコードだと言えます。
いくつか更新案を考えたのですが、Aは先のエントリで否定されてしまいました。
またドキュメントの出現順に要素をチェックするので目的の ul が見つかったのにその中の深い階層まで img を探しに行くのは非効率に感じます(プログラマの考え方です)
Griverさんへの返信 その2 - 1300
これを踏まえてひねり出したのがBとCです。
BはnextLinkのある階層からancestorで祖先ノードへ逆流し、複数のdivが存在する直近の階層を探しています。Cは同一階層にあるprecedingとfollowingのdivを数え、同一階層に5以上のノードが存在する3番目を確保しています。
どれがよいと判断するかは人によって異なるはずですからこのまま更新がなければ現状を維持します。いい勉強になりました。
追記
やはり気になるので少し妥協します。article_listを新規に分けました。
descendant::*[contains(@class,"date")][1]/../following-sibling::div[position()<3]
アイテム: walkerplus article_list - データベース: AutoPagerize - wedata
//li[./div/*[contains(@class,"date")]]
Griverさんへの返信 その2
抽象的なことばかり話してもどうかなと思ったのでコードを弄りました。見落としていたURLの分を考え直しています。
walkerplus
//main//ul[.//img]|descendant::*[./figure/a][1]
アイテム: walkerplus - データベース: AutoPagerize - wedata
article_listへの拡張を踏まえulの取得範囲をmain内に限定しました。
あと現状の walkerplus では 2ページ目に画像がないと継ぎ足せないようです。
https://www.walkerplus.com/article/1061211/
こちらはあまり機能の必要性を感じません。保留とさせてください。他に機能しない例があればまた考えます。
pixiv
//div[@class="event-information"]|(//nav|//div[@class="_pager-complex"])/following-sibling::*[./following-sibling::nav or ./following-sibling::div[@class="_pager-complex"]]|//*[./div[@class="_pager-complex"]]/descendant::ul[last()][count(//div[@class="_pager-complex"])=1]
アイテム: [pixiv] - データベース: AutoPagerize - wedata
ページャーの間を取得しています。//div[@class="_pager-complex"]をカウントすると1、つまりページャーが1つしかなければ親ノードから見て最後のulを取得しています。
残りは感想を書きます。
pixiv も walkerplus サイトが大きく複雑で要素名だけで解決しようとするのは難しいのではないか?
確かにそうかもしれません。いただいたアドバイスを生かしたつもりですが、現状はどうでしょうか。
exampleUrl が増えて動作確認が大変なのではないか?
exampleUrlが増えるのはwedataにはよくあることです。
動作確認がしやすい、あるいは難しいのは何をもって決まるのかよくわかりません。多分主観の問題な気がするので、もしそうだとすれば好きにさせてもらえないでしょうか。
今後も同じような誤作動が起こるのでは?
一応注意するつもりではいますが、これまで通り気づいたら修正するだけです。
Griverさんへの返信
前のエントリにいただいたコメントへ返信します。
過去にコードの見た目で書き換えてた人がいたのかもしれませんが、私は「人のコードはむやみに変えるべきではない」という考えです。
書いた人の意図や尊厳を大事にしたいです。そうしないと編集合戦になりそうですし...
まったく同感です。より良いコードを探っているだけで他の方の人格を否定しているわけではありません。
descendant::ul[count(./li)>9 or .//a[@data-src]][1]
こちらは意味不明なコードなんですよね。
そうですか。ご理解いただけなくて残念です。代案を教えていただけると幸いです。pixivは特にクラス名で取得してしまうと際限がなくなってしまう気がします。
ちなみに DMM や walkerplus(http://wedata.net/items/85745?rev=155845) で元の記述に戻したのは t_f_m さんのコードが「どこを取得したいのか」をはっきり示すコードで動作も問題なかったからです。
ミスに気づけなかった以上言い訳になるのですが、walkerplusに関しては更新前のコードが少し変則的な感覚はあります。
//main/section/node()[contains(.,'start ニュース本文')]/following-sibling::*[following-sibling::node()[contains(.,'end ニュース本文')]]
アイテム: walkerplus - データベース: AutoPagerize - wedata
難しい判断を求められるサイトで悩みました。トマ村さんもこのコードが決して本意ではない気がします。どちらが実用的かはまた別の議論でしょうが少なくとも手を入れたことが間違いだとは思いません。
厚かましいのを承知で無理を言わせていただくと、できればそのまま突き返すよりは編集を加えていただけるとありがたいです。このケースでは難しかったとは思いますがコードを全否定されると流石にヘコみます。
要素名だけでコードを書く場合は url 正規表現を厳しめにする、構造がワンパターンなサイトのみにする、main, section, article など用途が定められたものを基準にするのであれば問題は出にくいと思います。
そうでなければ @id, @class, @role などをコードに含めて動作の安定性を高めたり、コードを見た人に「この辺りを取得するよ」という意思表示をしてもらえると助かります。
私が言いたいのは「コードを短くするために必要な @id, @class を省略しないでほしい」「コードの綺麗さよりも動作のほうが大事」ということです。
長文失礼しました。
意思表示というのは具体的にどうやったらいいのかよくわかりません。コメントで伝えるとかですかね?
もし誤動作の苦情がGrieverさんのような開発者の方へ向かうとしたら心苦しいのですが、一つ一つのsiteinfoにベストを尽くした結果ならばご容赦いただきたいところです。
動作を最優先させるのはもちろんですが、美しさを求めてはいけないのでしょうか。同じことを繰り返しているだけでは何も変わらないはずです。
Wedataの編集方針について
Grieverさんからの質問にお答えします。
修正ありがとうございます。
— Griever (@Griever2) December 17, 2021
前から気になっているのですが id や class を使わずに要素名だけで記述するのは理由があるんですか?
//article[./a]とかdescendant::ul[1]とかの話ですね。
多野さんが積極的に編集していた時代ならコードである種の議論を行いどちらに優位性があるか、そしてお互いの妥協点を探っていけば済みました。しかしその結果生み出された400がメンテナンスされていない以上考え方を変える必要がありそうです。
wedata.net
これまでの経験から感じたのは、コーダー同士、そしてサイト管理者の方との無駄な争いが多すぎるということにつきます。もちろんXPathの性質上仕方のない部分はありますがhttpsに対応し、クラス名を単独指定からcontainsへ変更し、テキストノードを変更し、ひいてはクオーテーションのダブルとシングルを変更したりするのは本質からあまりにも外れていると言わざるを得ません。
これらを避けつつシンプルで美しいコードを書くには、そもそもテキストノードに加えてclassやidも使わなければよいという答えに行き着きました。
方針そのもの、そしてコードが間違っているのであればどちらにしても変えるだけです。
西野ブログ対策リターン版
なぜか引っ越したはずのアメブロに更新があるので対策を出しておきます。
ameblo.jp
// ==UserScript== // @name nishino_ameblo_return // @namespace http://tampermonkey.net/ // @version 0.1 // @description try to take over the world! // @author You // @match https://ameblo.jp/nishino-akihiro/* // @icon https://www.google.com/s2/favicons?domain=ameblo.jp // @grant none // ==/UserScript== $('.skin-entryBody *').removeAttr('style'); $('.skin-entryBody *').removeAttr('face'); $('.skin-entryBody *').removeAttr('color'); $('.skin-entryBody div>div,.skin-entryBody p>div,.skin-entryBody div>p').unwrap(); $('.skin-entryBody h1,.skin-entryBody h2').wrap('<h3>'); $('.skin-entryBody h1,.skin-entryBody h2').contents().unwrap(); $('.skin-entryBody>br').remove(); $('.skin-entryBody font,.skin-entryBody b,.skin-entryBody strong').contents().unwrap(); $(".skin-entryBody>*").contents().filter(function () { return this.nodeType === 3; }).wrap("<span class='n_text'></span>"); $('.skin-entryBody *').each(function(){ if($(this).text().match(/(\u0020|\u00A0|\u3000| ){2}/gi)){ $(this).addClass("nbsp"); } else if($(this).text().match(/(\u0020|\u00A0|\u3000| )|\s/gi)){ if($(this).text().length<2){ $(this).addClass("nbsp"); } } }); $('.nbsp:has(*)').removeClass("nbsp"); $('.nbsp').remove(); $('.skin-entryBody span>br').unwrap(); $('.skin-entryBody>p:empty').remove(); $('.skin-entryBody>*>*:not(br):last-of-type').addClass("text_last"); $('.text_last:last-of-type').prevAll().removeClass("text_last"); $('p:has(a.text_last)+a.ogp-form').addClass("dup_a"); $('.ogpCard_root+.ogp-title+.ogp-url').addClass("dup_a"); $('.skin-entryBody>p:has(br+*:not(br)),.skin-entryBody>div:has(br+*:not(br))').addClass("br_mix"); $('.skin-entryBody>p:has(*:not(br)+br),.skin-entryBody>div:has(*:not(br)+br)').addClass("br_mix"); $('.skin-entryBody>p:has(br):not(.br_mix),.skin-entryBody>div:has(br):not(.br_mix)').addClass("br_only"); $('.ogpCard_root *').css('display','none'); $('.ogpCard_url,.ogpCard_url *').css('display','inline'); $('.ogpCard_root *:has(.ogpCard_url)').css('display','inline'); $('*.br_only,*.dup_a,*.ogpCard_root,*.ogp-title').addClass("act"); $('.skin-entryBody>*:not(.act)').removeAttr('class'); $('.act').removeClass('act');
.skin-entryHead,.skin-entryHead *,.skin-entryBody,.skin-entryBody *{margin:0 !important;padding:0 !important;line-height:1.2;} .hashtag-module,.js-blogGenreRank{display:none;} br:first-child,br:first-child+br,br+br+br{display:none;} .text_last+br+br{display:none;} .skin-entryBody h3{font-size:1.17em;} .ogp-title{display:none;} .dup_a{display:none;}