WKWebView(UIWebViewにも応用可)で2チャンネルアンテナサイトを自動で飛ばす

# 2ちゃんまとめブラウザ作るんだがアンテナサイトのたらい回しにはこりごりな件
普段実は2ちゃんねるやそういった掲示板を読む機会はないが、こうして開発している間に自分の作っているアプリで記事を読んでいるうちになんというか少しずつノリを掴めてきた。
というわけで・・

すまん、硬派な俺だが今日はそんな感じでいく・・・お？

で、アンテナサイトだってみんなマネタイズしたくて頑張っているんだろうが、そいつらをみな駆逐することにしたお。

WKWebView前提で話進めるがUIWebViewなおまいらはコードのデリゲートメソッド名のところを
- (void)webViewDidFinishLoad:(UIWebView *)webView
- に置き換えてくれ。

# コード
javascriptやり込んでないからエレガントじゃなかったら教えろください

```objc
#define STRINGIZE(text) @#text

- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
	NSString *title = @"";
	id titleParamVal = webView.URL.uq_queryDictionary[@"title"];
	if ([titleParamVal isKindOfClass:[NSString class]]) {
		title = titleParamVal;
//		title = title.stringByRemovingPercentEncoding;
		if (title.length) DDLogDebug(@"searching string “%@” from a-tags", title);
	}
	NSString *script = [NSString stringWithFormat:
			STRINGIZE(
```
```js
			/* logging function */
					var appendedLogs = '';
					function log(text) {appendedLogs = appendedLogs + text + '\n'};
					/* main codes */
					var TITLE_MIN_LENGTH = 8;
					var TITLE_FROM_URL = '%@';
					/* fix tricks to all a-tags and search a-tag with text */
					var aTags = document.getElementsByTagName('a');
					for (var i = 0; i < aTags.length; i++) {
						var aTag = aTags[i];
						/* get text format value from a-tag */
						for (var c = aTag.firstChild; c; c = c.nextSibling) {
							if (c.nodeName == '#text') {
								var aText = c.nodeValue;
								/* @formatter:off */
								aText = aText.replace(/\s+/g, ''); /* remove whitespaces */
//								aText = aText.replace(/\n+/g, ''); /* remove line-breaks */
								/* @formatter:on */
								if (aText.length >= TITLE_MIN_LENGTH) { /* <- check has enough length */
									/* add get-parameter:'title' to href attribute */
									var href = aTag.getAttribute('href');
									var symbol = (href.indexOf('?') == -1) ? '?' : '&'; /* <- append 'title' param with this symbol */
									href += symbol + 'title=' + encodeURI(aText); /* <- 'title' param should be % encoded */
									aTag.setAttribute('href', href);
									/* if previous clicked a-tag's text is same as the aTag's text, jump to the linked site */
									if (TITLE_FROM_URL.length >= TITLE_MIN_LENGTH) { /* <- check has enough length */
										log('comparing “' + TITLE_FROM_URL + '” and “' + aText + '”.');
										if (aText.indexOf(TITLE_FROM_URL) != -1 || TITLE_FROM_URL.indexOf(aText) != -1) {
											log('found!!');
											window.location.href = aTag.getAttribute('href');
											break;
										}
									}
								}
							}
						}
					}
					appendedLogs;
```
```objc
			), title];
	[webView evaluateJavaScript:script completionHandler:^(id resultObj, NSError *error) {
		if ([resultObj isKindOfClass:[NSString class]]) {
			NSString *log = resultObj;
			if (log.length) DDLogVerbose(@"%@", log);
		}
		if (error) DDLogError(@"Error: %@", error);
	}];
}
```

# 下ごしらえ
使っているWebViewに応じて上のコードを記述するクラスをデリゲートにセットしてくれ。

```objc
wkWebView.navigationDelegate = self;
```

```objc
uiWebView.delegate = self;
```

# 解説
サイト読み込み毎に重たいとアレなのでjQueryとか使いたくないんよ。だから標準的なjavascript縛り。
流れとしてはサイトが読み込まれた時に上のメソッドが呼ばれ、Aタグに表示されてるテキスト取得してそれをそのAタグのhrefアトリビュートにGETパラメータとして追加。キーはtitle。
次にその読み込み完了メソッドが呼ばれた時には、そのサイトが読まれるきっかけとなったAタグのURLに埋め込まれているtitleパラメータと今回読み込まれたサイト内のAタグ上のテキストが一致していれば読み込み。
これがアンテナサイトを抜けるまで再起的に行われる。
（改行が//でなくいちいち/* */なのはSTRINGIZE内がワンラインななってしまった時、それ以降がすべてコメントアウトされるのを回避しようという試みだが心配には及ばなかった）
webView.URL.uq_queryDictionary[@"title"];に関してはNSURLからGETパラメータのtitleキーに対応する値を取得している。
このNSURLのGETパラメータをNSDictionaryにデシリアライズするライブラリは

```shell-session:Podfile
pod "NSURL+QueryDictionary"
```

でとってこれる。

# 問題点
まあ最初はすぐどうにでもなる問題なんだが、アンテナサイトいくつかURLで定義しといてフィルタリングはしたほうがいいな。
もう一つ問題は同じアンテナサイトで無限ループする。←てかこれ大問題
あとひとつ、Aタグの可読なテキスト部分って必ずしもAタグ直下にあるとは限らんから上のコードじゃまだ詰めが甘すぎるな。

# 余談
マクロ使ってObjective-Cファイルに結構さりげなくjavascript書いたがAppCodeだと微妙にシンタックスハイライトとか補完とかコードフォーマッターが効いた。これってある意味すごいことだと思う。
AppCodeでは@formatter:offと@formatter:onをコメントに記述することでコードフォーマッタを無効にしたり、再度有効にしたりできるが、@formatter:jsのように一時的、明示的に他言語のフォーマットに切り替えれたら便利だと思う。（まあこういうことはマクロ使って遊べる言語とかに限定されるだろうけど）

# たのむ
おふざけはこのへんにして、いくつか問題が残っているからコメントやmergeリクエストを送って完璧なコードにするのを手伝っていただきたい。
もちろん、現段階でもいくらかは有益な情報と思ってもらえるように努めたが不完全で大変申し訳なく思う。
（俺のポリシーとしてもここは知恵袋でもオーバー風呂でもないんだから完全なお悩み相談にはしたくなかった。）

というわけで情報提供に協力していただけたら非常に嬉しいです。
宜しくお願いします。