動的にコンテンツを生成してるサイトをクローラーbotに読ませたい

Javascriptコンテンツ

Googleのクローラーは巡回時にサイトのJavascriptを実行しないらしい。そうすると保存されるコンテンツキャッシュは中身スカスカの状態だ。てなると検索に引っかかりにくくなるし、探されづらくなる。GoogleさんがJSコンテンツをレンダリングしてくれるのがいいと思うんだけど、現状そうなってないのでこちらでクローラー用のコンテンツを用意してあげるとかがある(プリレンダリング)。ほっつい!もそういう感じにしてみたい。

方針

Googleから提供されている情報として、こちらの

https://developers.google.com/search/docs/advanced/javascript/javascript-seo-basics?hl=ja

一連のドキュメントがある。で、この中のダイナミックレンダリングを実装したいと思っていたのだけど、ここで解説されている方法はRendertronを使って静的HTMLファイルを返す方法だ。

https://codelabs.developers.google.com/codelabs/dynamic-rendering

Rendertronは内部にPuppeteerを使用しており、試してないけど説明を見る限りでは1アクセスごとに1レンダリングしてレスポンスを送るような形で実装しているみたい。すでに自分はSeleniumをインストールしているのに加えて、逐次的な実行はサーバーのリソース的に優しくなさそうだなーと思った。ので、リアルタイムではなくなるものの、クローラーの頻度もそんなに高くねーだろと思ったのでプリレンダリングした静的ファイルを用意しておき、botが来たときだけそっちのファイルを見せるような実装にしようと考えた。そうしましょう。

isbotでアクセスがbotのものか否かを判断する

isbotというライブラリを利用させてもらう。

https://github.com/omrilotan/isbot

有志によって作成されているクローラーbotリストをもとにUserAgentと比較してbotかどうかを判定してくれるナイスなライブラリだった。

$ npm i isbot

でインストールできる。そしたらコード内で

const isbot = require('isbot')

と、例えば

app.get('/hotwee', (req, res) => {
  
  if (isbot(req.header('User-Agent'))) {
    console.log('bot has come : ' + req.header('User-Agent'))
    res.sendFile('/***/rendered.html')
  } else {
    res.sendFile('/***/index.html')
  }
})

みたいな。これでbotからのアクセスの時には別のファイルを渡すという方法が実現できた。ここのrendered.htmlに保存してあげればよいのだな。

レンダリング後のHTMLファイルを保存する

Seleniumによって取得したレンダリング後のHTMLファイルを保存する。

driver.page_source

なのだが、これは現在のページをそのまま保存するやつなので、レンダリングされるまで待たないといけない。レンダリングされたことを取得するそれ用の方法が、調べた限りではなかったので代替方法として、レンダリングされないと出現しない要素を取得するコードを書き

driver.implicitly_wait(time)

で待つ最大値を設定しておくことで実現しようと思う。ただ、だとしても秒数までにレンダリングが終わらなければ取得はできない。…まぁいっか!というか結局time.sleep()で実装しちゃった。これだとブロッキング処理になるので実行中はサイト止まったりすんのかな。。。

# どれが必要でどれがいらないか忘れた。
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException
import chromedriver_binary
import time

options = webdriver.ChromeOptions()
options.add_argument('--headless') # ヘッドレスモード
options.add_argument('--no-sandbox') # サンドボックス使用しない
profile_path = '/root/.config/google-chrome/default' # chromeの個人設定のpath
options.add_argument('--user-data-dir=' + profile_path)  # 個人設定を利用するよう設定する
# これ自体がbotと認識されるのを防ぐため適当にUserAgentを設定する
options.add_argument('--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.82 Safari/537.36')
driver = webdriver.Chrome(options=options) # オプションを適用

driver.set_window_size(1600, 900)
driver.implicitly_wait(15)

driver.get("https://dalomo.net/hotwee")

time.sleep(10)

print(driver.page_source)

driver.quit()

最終的にprintを使ってるので、実行するとコンソール上にソースが表示される。Pythonからファイルに出力する方法を調べてもよかったが、めんどくさくなってしまったので簡単にシェルで出力することにした。つまり

0 10,22 * * * /usr/local/bin/python3 /home/dalomo/hotwee/getsource.py > /home/dalomo/hotwee/public/rendered.html

こうした。リダイレクションというらしい。大なり>を2つ重ねると>>追記する感じになるみたい。ログとかで使ったな。これで保存ができたわけだ。確実性という点ではちょっと劣るがまぁしょーがない。これをcronに登録しておく。

確認

https://search.google.com/test/mobile-friendly?hl=ja

を使ってサイトをテストする。自分のサイトだと

https://search.google.com/test/mobile-friendly/result?id=mUYg46635timlkcvvz0zCw&hl=ja

「テスト済みのページを表示」から確認できる。ちゃんと取得できてるのでおっけーですね。あとはー広告が邪魔くさいので削除できればいいんだけどそれは後回しかな。

カテゴリー: したい | タグ: , | コメントする

『乃木坂46弓木奈於とやみつきちゃん』 放送リスト

乃木坂46弓木奈於とやみつきちゃん

最近は乃木坂46の弓木奈於ちゃんにハマっている。発言や行動が突飛で面白い、その割に頭の良さも垣間見せる、その振れ幅にヤラれている。その弓木ちゃんがMCを務めている番組がひかりTVの『乃木坂46弓木奈於とやみつきちゃん』である。土曜22時から!

https://www.hikaritv.net/video/series/Z3JvdXAvbXNvbmx5X2IwMGFmYWM=

弓木奈於と乃木坂46のメンバーがルームシェアをしている架空の家が舞台。毎回“今後バズるかもしれない”もしくは“すでにバズり始めている”お届け物がやってくる。荷物の中身は、話題のグッズや本もあれば、見たこともないデバイスや食材、時には人間そのものも!?送り主は、ある事にどっぷりハマってしまった人、通称やみつきちゃん。やみつきちゃんが教える「ディープな世界」を初めて体験し、弓木らメンバーのやみつきになる姿、表情が露わになる!?

https://www.hikaritv.net/sp/nogidoyou22/index.html

dTVもあるがそっちは配信終了予定らしい。まぁそれはそれとして、各回の放送内容のリストがなく、リピートしようと思って過去回を探す時にちょっと不便なので簡単なリストを作ろうと思った。

番組SNS

https://twitter.com/nogidoyou22

https://www.instagram.com/nogidoyou22/

#1 ホットサンドメーカー (2021年6月12日)

乃木坂46メンバー

  • 樋口日奈

やみつきちゃん

  • 幕田美里

#2 初飲酒 やみつき酒 (2021年6月19日)

乃木坂46メンバー

  • 樋口日奈
  • 和田まあや

やみつきちゃん

  • 和田まあや

#3 缶詰 (2021年6月26日) ※生配信

乃木坂46メンバー

  • 矢久保美緒

やみつきちゃん

  • 黒川勇人

#4 Among Us 前編 (2021年7月3日)

乃木坂46メンバー

  • 佐藤璃果

やみつきちゃん

  • 木村良平
  • 柏木べるくら

他出演者

  • とりっぴぃ
  • フルコン
  • sunazame
  • れぷちん

#5 Among Us 後編 (2021年7月10日)

乃木坂46メンバー

  • 佐藤璃果

やみつきちゃん

  • 木村良平
  • 柏木べるくら

他出演者

  • とりっぴぃ
  • フルコン
  • sunazame
  • れぷちん

#6 完全再現料理 (2021年7月17日)

乃木坂46メンバー

  • 柴田柚菜

やみつきちゃん

  • いけや賢二

#7 カクテル (2021年7月24日)

乃木坂46メンバー

  • 田村真佑

やみつきちゃん

  • 河井ゆずる

#8 ちびめし料理 (2021年7月31日)

乃木坂46メンバー

  • 松尾美佑

やみつきちゃん

  • あさみ

#9 日本酒 前編 (2021年8月7日)

乃木坂46メンバー

  • 和田まあや

やみつきちゃん

  • 高田秋

#10 日本酒 後編 (2021年8月14日)

乃木坂46メンバー

  • 和田まあや

やみつきちゃん

  • 高田秋

#11 ヘアアレンジ (2021年8月21日)

乃木坂46メンバー

  • 金川紗耶

やみつきちゃん

  • 柴田紋奈

#12 Dead by Daylight 前編 (2021年8月28日)

乃木坂46メンバー

  • 吉田綾乃クリスティー

やみつきちゃん

  • 柏木べるくら
  • ゴー☆ジャス
  • れぷちん

#13 Dead by Daylight 後編 (2021年9月4日)

乃木坂46メンバー

  • 吉田綾乃クリスティー

やみつきちゃん

  • 柏木べるくら
  • ゴー☆ジャス
  • れぷちん

#14 3Dファントム・折り紙 (2021年9月11日)

乃木坂46メンバー

  • 筒井あやめ

やみつきちゃん

  • 勝川東・保坂瑞希

#15 未来フード・声フォント・ギー・漢字・アームレスリング・生き物の持ち方 (2021年9月18日) ※生配信

乃木坂46メンバー

  • 佐藤璃果
  • 金川紗耶

やみつきちゃん

  • なし

他出演者

  • 河井ゆずる・稲田直樹

#16 シンデレラ 前編 (2021年9月25日)

乃木坂46メンバー

  • 林瑠奈

やみつきちゃん

  • 川田雅直

#17 落ちもん写真・シンデレラ 後編 (2021年10月2日)

乃木坂46メンバー

  • 林瑠奈

やみつきちゃん

  • 藤田泰実
  • 川田雅直

#18 VRアート (2021年10月9日)

乃木坂46メンバー

  • 掛橋沙耶香

やみつきちゃん

  • せきぐちあいみ

#19 悪魔の食べ合わせ (2021年10月16日)

乃木坂46メンバー

  • 柴田柚菜

やみつきちゃん

  • 鈴木隆一

#20 スプレーアート (2021年10月23日)

乃木坂46メンバー

  • 掛橋沙耶香

やみつきちゃん

  • aicon

#21 デコミニ四駆 (2021年10月30日)

乃木坂46メンバー

  • 鈴木絢音

やみつきちゃん

  • ミニ四子(かえひろみ)

#22 クレーンゲーム・ビタ止め 前編 (2021年11月6日)

乃木坂46メンバー

  • 田村真佑

やみつきちゃん

  • 五十嵐直也
  • めいちゅん

#23 ビタ止め 後編 (2021年11月13日)

乃木坂46メンバー

  • 田村真佑

やみつきちゃん

  • めいちゅん

#24 SASSEN(サッセン)・VRバンジー・ピンダルー・超人スポーツ (2021年11月27日)

乃木坂46メンバー

  • 田村真佑

やみつきちゃん

  • 本村隆馬

#25 悪魔の食べ合わせ 2 (2021年12月4日)

乃木坂46メンバー

  • 柴田柚菜

やみつきちゃん

  • 鈴木隆一

#26 バーチャル就学旅行 (2021年12月11日)

乃木坂46メンバー

  • 矢久保美緒

やみつきちゃん

  • 平尾

#27 バーベキュー (2021年12月18日)

乃木坂46メンバー

  • 林瑠奈

やみつきちゃん

  • たけだバーベキュー

#28 物件探し 前編 (2022年1月29日)

https://www.hikaritv.net/video/detail/dm9kLzAwMDAwMDAwMDBfMDBrd2VqMTN0eQ==

乃木坂46メンバー

  • 金川紗耶
  • 矢久保美緒

やみつきちゃん

  • なし

他出演者

  • 河井ゆずる

#29 物件探し 後編 (2022年2月5日)

https://www.hikaritv.net/video/detail/dm9kLzAwMDAwMDAwMDBfMDBrd2VqMTRtOA==

乃木坂46メンバー

  • 金川紗耶
  • 矢久保美緒

やみつきちゃん

  • なし

他出演者

  • 河井ゆずる

#30 ペットマッサージ (2022年2月12日)

https://www.hikaritv.net/video/detail/dm9kLzAwMDAwMDAwMDBfMDBrd2VqMTVnNg==

乃木坂46メンバー

  • 佐藤楓

やみつきちゃん

  • 石野孝

他出演者

  • ぺこぱ

#31 ネクストスポーツ(コーンホール・ホッカン・バルーンバレー) (2022年2月19日)

https://www.hikaritv.net/video/detail/dm9kLzAwMDAwMDAwMDBfMDBrd2VqMTY5NA==

乃木坂46メンバー

  • 北川悠理

やみつきちゃん

  • 日澤準弥
  • ハラコ

他出演者

  • ぺこぱ

#32 ボードゲーム (2022年2月26日)

https://www.hikaritv.net/video/detail/dm9kLzAwMDAwMDAwMDBfMDBrd2VqMTcyNg==

乃木坂46メンバー

  • 佐藤璃果

やみつきちゃん

  • 鷹虎

他出演者

  • なすなかにし

#33 なすなかゲーム 前編 (2022年3月5日)

https://www.hikaritv.net/video/detail/dm9kLzAwMDAwMDAwMDBfMDBrd2VqMTd0eg==

乃木坂46メンバー

  • 林瑠奈

やみつきちゃん

  • なし

他出演者

  • なすなかにし

#34 なすなかゲーム 後編 (2022年3月12日)

https://www.hikaritv.net/video/detail/dm9kLzAwMDAwMDAwMDBfMDBrd2VqMThseA==

乃木坂46メンバー

  • 林瑠奈

やみつきちゃん

  • なし

他出演者

  • なすなかにし

#35 高野麻里佳 (2022年3月19日)

https://www.hikaritv.net/video/detail/dm9kLzAwMDAwMDAwMDBfMDBrd2VqMTlkZw==

乃木坂46メンバー

  • 矢久保美緒

やみつきちゃん

  • 高野麻里佳

#36 ネクストスポーツ 2 (ベンチリーチ・ビアポン・ペーパープレーン) (2022年3月26日)

https://www.hikaritv.net/video/detail/dm9kLzAwMDAwMDAwMDBfMDBrd2VqMWE1aw==

乃木坂46メンバー

  • 松尾美佑

やみつきちゃん

  • 柴田優
  • 藤原宣明

他出演者

  • さらば青春の光

#37 桃太郎電鉄 前編 (2022年4月2日)

https://www.hikaritv.net/video/detail/dm9kL21zb25seV8wMDAwMDAwMDAwXzAwa3dlajFheXo=

乃木坂46メンバー

  • 矢久保美緒
  • 和田まあや

やみつきちゃん

  • 無し

他出演者

  • アルコ&ピース

#38 桃太郎電鉄 後編 (2022年4月9日)

https://www.hikaritv.net/video/detail/dm9kLzAwMDAwMDAwMDBfMDBrd2VqMWNqYw==

乃木坂46メンバー

  • 矢久保美緒
  • 和田まあや

やみつきちゃん

  • 無し

他出演者

  • アルコ&ピース

#39 フリースタイルラップ (2022年4月16日)

https://www.hikaritv.net/video/detail/dm9kL21zb25seV8wMDAwMDAwMDAwXzAwa3dlajFkYmI=

乃木坂46メンバー

  • 北川悠理

やみつきちゃん

  • KEN THE 390

他出演者

  • 新作のハーモニカ

#40 春の感謝祭 (弓木奈緒 生態クイズ・握力チェック・ベンチリーチ) (2022年4月23日) ※生配信

https://www.hikaritv.net/video/detail/dm9kLzAwMDAwMDAwMDBfMDBrd2VqMWUycw==

乃木坂46メンバー

  • 林瑠奈
  • 金川紗耶

やみつきちゃん

  • 無し

他出演者

  • なすなかにし

#41 サウナ 前編 (2022年5月8日)

https://www.hikaritv.net/video/detail/dm9kLzAwMDAwMDAwMDBfMDBrd2VqMWV3Nw==

乃木坂46メンバー

  • 伊藤理々杏

やみつきちゃん

  • 無し

他出演者

  • 3時のヒロイン

#42 サウナ 後編 (2022年5月15日)

https://www.hikaritv.net/video/detail/dm9kLzAwMDAwMDAwMDBfMDBrd2VqMWZweA==

乃木坂46メンバー

  • 伊藤理々杏

やみつきちゃん

  • 無し

他出演者

  • 3時のヒロイン

#43 世界の料理 (デビルドエッグ、リーシプーロ、チャンピニョン・ア・ラ・プランチャ) (2022年5月21日)

https://www.hikaritv.net/video/detail/dm9kLzAwMDAwMDAwMDBfMDBrd2VqMWdoaA==

乃木坂46メンバー

  • 黒見明香

やみつきちゃん

  • ケイリーン
  • ノーラ
  • ロベルト

他出演者

  • 河井ゆずる

#44 街ブラロケ (2022年5月28日)

https://www.hikaritv.net/video/detail/dm9kLzAwMDAwMDAwMDBfMDBrd2VqMWg4bw==

乃木坂46メンバー

  • 林瑠奈

やみつきちゃん

  • 無し

他出演者

  • なすなかにし

#45 ロケ弁 (2022年6月11日)

https://www.hikaritv.net/video/detail/dm9kLzAwMDAwMDAwMDBfMDBrd2VqMWkwaQ==

乃木坂46メンバー

  • 林瑠奈

やみつきちゃん

  • 無し

他出演者

  • なすなかにし
  • 早川穣 (オーベルジーヌ三田店料理長)
  • 岸井美智子 (金兵衛)
  • 佐藤哲也 (浅草今半弁当工房 工房長)

#46 体幹 (マーメイドモノフィンボディワーク・VRフィットネス) (2022年6月18日)

https://www.hikaritv.net/video/detail/dm9kLzAwMDAwMDAwMDBfMDBrd2VqMWl1Ng==

乃木坂46メンバー

  • 掛橋紗耶香

やみつきちゃん

  • ジャスミン井上(マーメイドモノフィンボディワーク)
  • MY BASE 寺西

他出演者

  • さらば青春の光

#47 子ども (2022年6月25日)

https://www.hikaritv.net/video/detail/dm9kLzAwMDAwMDAwMDBfMDBrd2VqMWpuZw==

乃木坂46メンバー

  • 向井葉月

やみつきちゃん

  • てぃ

他出演者

  • シュウペイ

#48 運転 前編 (2022年7月2日)

https://www.hikaritv.net/video/detail/dm9kLzAwMDAwMDAwMDBfMDBrd2VqMWtnZw==

乃木坂46メンバー

  • 和田まあや

やみつきちゃん

  • なし

他出演者

  • なすなかにし

#49 運転 後編 (2022年7月9日)

https://www.hikaritv.net/video/detail/dm9kLzAwMDAwMDAwMDBfMDBsNG5ob3N0cA==

乃木坂46メンバー

  • 和田まあや

やみつきちゃん

  • なし

他出演者

  • なすなかにし

#50 弓木奈於 前編 (2022年7月16日)

https://www.hikaritv.net/video/detail/dm9kLzAwMDAwMDAwMDBfMDBsNG5ob3RxZA==

乃木坂46メンバー

  • 林瑠奈
  • 黒見明香

やみつきちゃん

  • なし

他出演者

  • さらば青春の光

#51 弓木奈於 後編 (2022年8月6日)

https://www.hikaritv.net/video/detail/dm9kLzAwMDAwMDAwMDBfMDBsNG5ob3VrbQ==

乃木坂46メンバー

  • 林瑠奈
  • 黒見明香

やみつきちゃん

  • なし

他出演者

  • さらば青春の光

#52 天然キノコ (2022年8月13日)

https://www.hikaritv.net/video/detail/dm9kLzAwMDAwMDAwMDBfMDBsNG5ob3ZmNA==

乃木坂46メンバー

  • 向井葉月

やみつきちゃん

  • 坂井きのこ

#53 令和ギャル (2022年8月28日)

https://www.hikaritv.net/video/detail/dm9kLzAwMDAwMDAwMDBfMDBsNG5ob3c5NQ==

乃木坂46メンバー

  • 松尾美佑

やみつきちゃん

  • BLEA学園

他出演者

  • アルコ&ピース

#54 怪談 (2022年9月4日)

https://www.hikaritv.net/video/detail/dm9kLzAwMDAwMDAwMDBfMDBsNG5ob3gzaQ==

乃木坂46メンバー

  • 清宮レイ
  • 北川悠理

やみつきちゃん

  • 島田秀平

他出演者

  • かが屋

#55 手書きPOP (2022年9月18日)

https://www.hikaritv.net/video/detail/dm9kLzAwMDAwMDAwMDBfMDBsNG5ob3h5MQ==

乃木坂46メンバー

  • 鈴木絢音

やみつきちゃん

  • はりまりょう

他出演者

  • 流れ星

#56 着ぐるみ 前編 (2022年9月24日)

https://www.hikaritv.net/video/detail/dm9kLzAwMDAwMDAwMDBfMDBsNG5ob3lyMw==

乃木坂46メンバー

  • 吉田綾乃クリスティー
  • 矢久保美緒

やみつきちゃん

  • 大平長子

他出演者

  • ハマカーン

#57 着ぐるみ 後編 (2022年10月1日)

https://www.hikaritv.net/video/detail/dm9kLzAwMDAwMDAwMDBfMDBsNG5ob3prbQ==

乃木坂46メンバー

  • 吉田綾乃クリスティー
  • 矢久保美緒

やみつきちゃん

  • 大平長子

他出演者

  • ハマカーン

#58 弓木奈於の総合演出 (2022年10月15日)

https://www.hikaritv.net/video/detail/dm9kLzAwMDAwMDAwMDBfMDBsNG5ocDBkcg==

乃木坂46メンバー

  • なし

やみつきちゃん

  • なし

他出演者

  • タイムマシーン3号

#59 弓木奈於のルーツ (2022年10月29日)

 

https://www.hikaritv.net/video/detail/dm9kLzAwMDAwMDAwMDBfMDBsNG5ocDE3Nw==

乃木坂46メンバー

  • なし

やみつきちゃん

  • なし

他出演者

  • なすなかにし

#60 メンズファッション (2022年11月5日)

https://www.hikaritv.net/video/detail/dm9kLzAwMDAwMDAwMDBfMDBsNG5ocDIyOA==

乃木坂46メンバー

  • 中村麗乃

やみつきちゃん

  • Tany

他出演者

  • ウェストランド

#61 麻雀 (2022年11月12日)

https://www.hikaritv.net/video/detail/dm9kLzAwMDAwMDAwMDBfMDBsNG5ocDJ2eA==

乃木坂46メンバー

  • 金川紗耶
  • 北川悠理

やみつきちゃん

  • 丸山奏子

他出演者

  • タイムマシーン3号

#62 バラエティ力 前編 (2022年11月19日)

https://www.hikaritv.net/video/detail/dm9kLzAwMDAwMDAwMDBfMDBsNG5ocDNxOA==

乃木坂46メンバー

  • 向井葉月

やみつきちゃん

  • 菊地亜美

他出演者

  • 流れ星

#63 バラエティ力 後編 (2022年12月3日)

https://www.hikaritv.net/video/detail/dm9kLzAwMDAwMDAwMDBfMDBsNG5ocDRqbw==

乃木坂46メンバー

  • 向井葉月

やみつきちゃん

  • 菊地亜美

他出演者

  • 流れ星

#64 科学実験 (2022年12月10日)

 

https://www.hikaritv.net/video/detail/dm9kLzAwMDAwMDAwMDBfMDBsNG5ocDVkYw==

乃木坂46メンバー

  • 黒見明香

やみつきちゃん

  • 海老谷浩

他出演者

  • 流れ星

#65 最終回 卒業式 大好きな人たちとやり残したこと全部やるSP (2022年12月17日)

 

https://www.hikaritv.net/video/detail/dm9kLzAwMDAwMDAwMDBfMDBsNG5ocDY4Yg==

乃木坂46メンバー

やみつきちゃん

他出演者

  • 流れ星
  • さらば青春の光 森田
  • なすなかにし
  • タイムマシーン3号
カテゴリー: のーと | タグ: | コメントする

はてなブックマークのコメントを猥雑な並びにするChrome拡張を作った

猥雑コメント

人気コメント順が最初の10件しか表示されなくなったあたりからなんとなく作りたいなーと思ってて、ちょっと前に建設的~APIが導入されてからそういや作りたいと思ってたなと思い出した。

できたもの

https://github.com/dalomo-net/Hatena-Bookmark-disorder-comments

こちらです。とりま動くものができた。Download Zipから落として適当な所に解凍して、Chromeの拡張機能からパッケージ化されていない拡張機能を読み込む、でさっきのフォルダを選択すれば使える。

どうなる

エントリーページに行ってしばらくすると新着コメントの隣に猥雑コメントタブが現れる。それをクリックすると猥雑な並びになったコメント一覧が現れる。

どうやった

http://developer.hatena.ne.jp/ja/documents/bookmark/apis/getinfo

http://developer.hatena.ne.jp/ja/documents/star/apis/entry

を使用した。エントリー情報を取得後、各ユーザーのスタ-数を取得し並び順を変えている。猥雑と言いつつも規則はあり、並び順はユニークスター順だが、カラースターについては重み付けをしている。

function multiplier(color) {
    if (color == "green") {
        return 2
    } else if (color == "red") {
        return 3
    } else if (color == "blue") {
        return 4
    } else if (color == "purple") {
        return 5
    }
}

スター無しは時間の昇順降順で並び替えされる。APIを利用している都合上、人気・新着コメントに表示されているブクマ数・コメント・スターと相違がある。

やってない

  • 1000ユーザー以上のエントリページでは実行されない。
  • カラースターは反映されず重み付け後のスター総数が表示される。また、各スターに投げた人の情報は表示されない。
  • スターボタンが機能していないのでスターを付けられない。
  • その他ボタンが機能していないのでお気に入りや通報などができない。
  • 閲覧者の非表示ユーザー設定が反映されないと思う。
  • コメント中のidやhttps://~はリンクにならない。
  • タグが反映されない。

こんなとこかしら。ラグがあるのはしょうがないものの、最低限の機能はできたと思う。とても嬉しい!お金ないのでストアに公開はしないかな。できるところは改善したいかも。

がんばったところ

あとで書くかも。

カテゴリー: できた | タグ: , , | コメントする

twitterで人気のあるメディアツイートが見れるサイト「ほっつい!」を作った

ほっつい!

https://dalomo.net/hotwee/

やってみたらできた。意外とできるもんだ。twitterで人気のある画像・動画系のツイートを取得してきてギャラリー風に表示してくれるサイト。仕事PCだとtwitterがブロックされるので、これを使って仕事中にも見るんだ。

頑張ったところ

  • 初めてCSSでデザイン的なことをした
    • でもダサい…
  • node.jsでsqlite3を使った
    • ほんとは公開サイトで使うようなDBではないらしい
  • もっと読むボタンを作った
    • ほんとは無限スクロールを作りたかった

あれ?これぐらい?…けっこー時間かかったんだけどな。でも当初思い描いてた形にかなり近く作ることができたので満足!

 

カテゴリー: できた | タグ: , | コメントする

はてブbotを作った

はてブbot

https://b.hatena.ne.jp/Hotwee/

ほっついー

定期的に人気ツイートをとってきてくれるやーつ

流れてっちゃうのを留めときたいから作った

カテゴリー: のーと | タグ: , | コメントする

Refused to execute inline script because it violates the following Content Security Policy directive: “script-src ‘self'”. Either the ‘unsafe-inline’ keyword, a hash (‘sha256-xxx’), or a nonce (‘nonce-…’) is required to enable inline execution.ってエラー

Refused to execute inline script because it violates the following Content Security Policy directive: “script-src ‘self'”. Either the ‘unsafe-inline’ keyword, a hash (‘sha256-xxx’), or a nonce (‘nonce-…’) is required to enable inline execution.

<script></script>で囲った中に書いてあるコードを外部ファイル化したら直った。

カテゴリー: のーと | タグ: | コメントする

簡易掲示板を作りたい、node.js+expressで ⑦色々

色々

思いついたことを色々やっていく。

Helmetを使う

https://expressjs.com/ja/advanced/best-practice-security.html#use-helmet

expressで推奨されてた。

 $ npm install --save helmet

インストールして追記

var helmet = require('helmet')
app.use(helmet())

効果はよく分からない。

https://qiita.com/qianer-fengtian/items/148602c437e1703aa764

とか参照。

Javascriptでhtmlspecialchars

PHP使ったときなんかこんなのあったよなーと思って探してみたら、javascriptではないらしい。なので自分で関数作って対応するそうな。ちょうどStackoverflowに同様の質問があった。

https://stackoverflow.com/questions/1787322/what-is-the-htmlspecialchars-equivalent-in-javascript

function escapeHtml(text) {
  return text
      .replace(/&/g, "&")
      .replace(/</g, "<")
      .replace(/>/g, ">")
      .replace(/"/g, """)
      .replace(/'/g, "'");
}

replaceで一個ずつ置き換えてく。

入力文字数チェック

未入力だの、長いやつを弾く。

if (req.body['user_message'] === '') {
      res.status(400).send('ないようがないよう')
      return;
    }

    if (req.body['user_message'].length > 400) {
      res.status(400).send('ないようがながいよう')
      return;
    }

    if (req.body['user_name'].length > 20) {
      res.status(400).send('なまえがながいよう')
      return;
    }

長さ見てるだけだね。

新しい投稿が上に来るようにする

data.reverse();

こんな簡単なのだな。ただ編集→更新したやつは上に来ない。

日時をGMTにする、形式を変える

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/DateTimeFormat

こちらに書いてあることを読み解きつつ

function fmtdate(){
  let o = new Intl.DateTimeFormat('jp-JP', {
    weekday: 'narrow',
    year: 'numeric',
    month: '2-digit',
    day: '2-digit',
    hour: '2-digit',
    minute: '2-digit',
    second: '2-digit',
    fractionalSecondDigits: 3
  })

  return o.format(new Date())
}

こんな関数を作った。今まで

2022-01-02T11:50:36.446Z

こんな表示でUTCだったのが

2022/01/02(日) 20:51:07.812

こんな表示でGMTになった。

とりあえず終わり

こんなところかなぁ。あと最終のソース。

カテゴリー: したい, できた | タグ: , , | コメントする

簡易掲示板を作りたい、node.js+expressで ⑥/nodebbs/msgで更新する

更新

更新機能をつけたい。どういう感じがいいんだろうなーと考えて、編集ボタンを押すと投稿された文章が編集できるように変わって、更新ボタンを押すとそのまま更新されるのがかっこよさめじゃないかと思った。そういう感じにできるように頑張る。

ボタンを付ける

<p id="${row['id']}">${row['contents']['msg']}</p>
<p><button type="button" id="edit-${row['id']}" onclick="editbtn()">編集</button>
名前: ${row['contents']['name']} 日時: ${row['contents']['dt']}
<button type="button" id="del-${row['id']}" onclick="delbtn()">削除</button></p>
<hr>

表示のとこに新たにボタンを作った。後々のためにてきとーにidもくっつけておく。これを押すとまずは編集できるようにしたい。

ボタンを押すと編集できるようにする

function editbtn() {
            let id = event.target.id.slice(5)
            let p = document.getElementById(id)
            let msg = p.innerText
            let textarea = document.createElement('textarea')
            textarea.value = msg
            textarea.id = id
            p.replaceWith(textarea)

            let btn = document.getElementById('edit-' + id)
            btn.innerText = '更新'
            btn.setAttribute('onclick', 'update()');
        }

冗長かなぁ。でもこうしか思いつかん。idで<p>タグの内容を色々取得して、新たに<textarea>の要素を作りreplaceWithで置き換えた。

https://developer.mozilla.org/ja/docs/Web/API/Element/replaceWith

そんでボタンの方は、更新ボタンになるようにテキストとonclickの内容を変えている。

https://developer.mozilla.org/ja/docs/Web/API/Element/setAttribute

ボタンを押すと更新処理する

function update() {
            let id = event.target.id.slice(5)
            let textarea = document.getElementById(id)
            let msg = textarea.value
            let data = {
                'msg': msg
            }
            fetch('https://dalomo.net/nodebbs/msg/' + id, {
                method: 'PUT',
                body: JSON.stringify(data),
                headers: {
                    'Content-Type': 'application/json'
                }
            })
                .then(res => {
                    let p = document.createElement('p')
                    p.id = id
                    p.innerText = msg
                    textarea.replaceWith(p)
                })
        }

これもIntelliSenseさんが怒涛の勢いで作ってくれた…。

testareaに入力された値をオブジェクトにして、fetchでPUTメソッドを使い、bodyに更新内容をstringifyして送信した。headersはまぁ必要なんだろうこれ。こことか読むとこうすることによってサーバー側で受け取りやすくなってるのかな。で、レスポンス返ってきたら、textareaからpタグに戻して終わり。これはクライアントサイドなので、あとはサーバーサイドを作る。

サーバー側のデータを更新する

app.put('/nodebbs/msg/:id', (req, res) => {
  const id = req.params.id
  const obj = JSON.parse('[' + fs.readFileSync('log.json', 'utf8') + ']')
  const newObj = obj.map(item => {
    if (item.id == id) {
      item.contents.msg = req.body['msg']
      item.contents.dt = (new Date()).toJSON()
    }
    return item
  })
  fs.writeFileSync('log.json', JSON.stringify(newObj).slice(1).slice(0, -1), 'utf8')
  res.end()
})

これも(ry マジですごいよね。考えることがほぼないよ。

まぁログを読み込んで、obj.mapでオブジェクトの要素をなめて、idが一致したらその内容を書き換える。ついでに日付も変わる。このmap関数っていうのがすごい便利なのね。for文とかでやるところだと思うんだけどIntelliSenseさん様々だわ。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/map

あとは編集後のデータをlog.jsonに書き戻すだけ。すごーい、あっという間にできちゃった。

https://dalomo.net/nodebbs/

とりあえず、基本的な機能を持つ掲示板を作れた。セキュリティ等加味してないのでちょっとアレですが嬉しいねぇ。

カテゴリー: したい | タグ: , , | コメントする

簡易掲示板を作りたい、node.js+expressで ⑤/nodebbs/msgで削除する

削除

削除ができるようにしたい。ほんとはパスワードとか入れて書き込んだ本人であるかのチェックが必要なんだろうけど、まずはボタン一発即削除という形で作りたい。

ID的な要素を追加する

見通しが立っていないがあると便利そうなので追加したい。どの程度のスペックが必要なIDかというのはなんか色々あるみたいだが時間でいいやと思った。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Date/now

ちゅーことでapp.post内を

var obj = {
    id: Date.now(),
    contents: {
      name: req.body['user_name'],
      msg: req.body['user_message'],
      dt: (new Date()).toJSON()
    }
  }

こう変えた。それに伴って

 for (let row of data) {
    s += `
        <p>${row['contents']['msg']}</p>
        <p><button type="button" id="${row['id']}" onclick="delbtn()">削除</button> 名前:${row['contents']['name']} 日時: ${row['contents']['dt']}</p>
        <hr>
        `
    }

こうした。

HTTP DELETEメソッドを使う

ボタンを押したらidを伴ってサーバー側に飛ばすイメージで書く。

function delbtn() {
            let id = event.target.id
            fetch('https://dalomo.net/nodebbs/msg/' + id, {
                    method: 'DELETE'
                })
                .then(res => location.reload())
        }

これ、VSC使ってたらほぼ書いてくれた。いつの間にか未来いたわ。

eventがクリックイベントの要素が入っとるらしい。そこのidを取得

https://developer.mozilla.org/ja/docs/Web/API/Event/target

HTMLのみでDELETEメソッドを使う方法がわからなかったので、Javascriptのfetchを使う

https://developer.mozilla.org/ja/docs/Web/API/Fetch_API/Using_Fetch#supplying_request_options

そのままほっとくと画面が更新されなかったのでリロードを入れてみた。これもっとスマートな方法ないのかな。

受け取ったリクエストをサーバーで処理する

app.delete('/nodebbs/msg/:id', (req, res) => {
  const id = req.params.id
  const obj = JSON.parse('[' + fs.readFileSync('log.json', 'utf8') + ']')
  const newObj = obj.filter(item => item.id != id)
  fs.writeFileSync('log.json', JSON.stringify(newObj).slice(1).slice(0,-1), 'utf8')
  res.end()
})

こ、これもほぼ自動的に作られた…。やべーな未来。でもあんま理解度が高くないからこれが合ってるのか分からないんですよね。。。

app.deleteでDELETEメソッドのリクエストを処理できる。ルートパスにパラメータを含めて、req.params.idで取得できる。

https://expressjs.com/ja/guide/routing.html#:~:text=res.send(%27/.*fly%24/%27)%0A%7D)-,%E3%83%AB%E3%83%BC%E3%83%88%E3%83%BB%E3%83%91%E3%83%A9%E3%83%A1%E3%83%BC%E3%82%BF,-%E3%83%AB%E3%83%BC%E3%83%88%E3%83%BB%E3%83%91%E3%83%A9%E3%83%A1%E3%83%BC%E3%82%BF%E3%81%AF

JSONを読み込んで、obj.filter(item => item.id != id)のところ、これ勝手にAIが作ったコードなんだけどidでフィルターかけるんだけど削除したいid除外でフィルタかけるんだよね。全然発想持ってなかったわ。考えてたのはidでなんか検索とかして、その要素のみ削除みたいな感じで考えてた。すげーよ、こっちのが全然スマートな解決だわ。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/filter

で、文字列に変換して、最初と最後の[]を削除して、ファイルを書き出し。でres.end()で終了。できたー。

ミリ秒単位なので自分の場合はほぼ起こらないと思うけど、例えば削除のために読み込んでる途中で新規書き込みがあったりすると、削除後のファイル書き込みによって、新規が無い状態での上書きがされるので、新規がどっかいくみたいなことは起こりうる。こういうのを防ぐためにDBとかの仕組みがあったりすのかなぁとか思った。

カテゴリー: したい | タグ: , , | コメントする

簡易掲示板を作りたい、node.js+expressで ④/nodebbs/msgで取得する

取得

同一URLでデータを取得するようにする。さっきこのURLはPOSTメソッドだと投稿ができるようにしてたけど、今度はGETメソッドでJSONを取得できるようにする。そんでその取得したデータをもとに、投稿をページに表示すれば良いはず。

GET /nodebbs/msg

log.jsonファイルを読み込んでJSON文字列形式に変換しレスポンスを返す。

const obj = JSON.parse('[' + fs.readFileSync('log.json', 'utf8') + ']')

log.jsonはちゃんとしたJSON形式ではないのでそのまま読み込もうとするとエラーが出る。なので配列を表す[]をつけてJSON.parseに流してあげる。

https://nodejs.org/api/fs.html#fsreadfilesyncpath-options

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse

expressにはJSON形式で返すというメソッドがあったのでそれを使う

 res.json(obj)

https://expressjs.com/ja/4x/api.html#res.json

とりあえず全部返すようにした。全部返すなら一旦オブジェクトに変換せんでもlog.jsonに[]つけた文字列そのまま返せばいーじゃんとも思ったけど、後で範囲指定とかできたらしたいなと思ったのでこうした。ここまでやると

https://dalomo.net/nodebbs/msg

にアクセスするとJSONが返ってくる。ただこれexpress5.x系だと削除されるメソッドらしい。

JavascriptでAPIを叩きレスポンスをページに反映する

https://news.mynavi.jp/techplus/article/zerojavascript-8/

こちらを参考に

    <script>
        fetch('https://dalomo.net/nodebbs/msg')
            .then(res => res.json())
            .then(data => contents(data));

        function contents(data) {
            let s = ''
            for (let row of data) {
                s += `
                    <p>${row['msg']}</p>
                    <p>名前:${row['name']} 日時: ${row['dt']}</p>
                    <hr>
                    `
            }
            var contents = document.getElementById('contents')
            contents.innerHTML = s
        }
    </script>

fetchでAPIにアクセス。res.json()でレスポンスをJSON形式に。そのデータをcontents関数に渡して内容を作る。

for分でオブジェクトそれぞれのデータをHTMLにしてく。${ }というのがプレースホルダーとして使えるらしい。初めて知った。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Template_literals

できたHTML分をcontents内に配置して完了。これは前もやったな。デーモン化しておく。

https://dalomo.net/nodebbs/

できた!ただ今のままだと脆弱性ありありでおっかない出来だと思うので、どーしたもんかな。

カテゴリー: したい | タグ: , , | コメントする