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

スポンサーリンク
スポンサーリンク

Javascriptコンテンツ

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

スポンサーリンク

方針

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

JavaScript SEO の基本を理解する | Google 検索セントラル  |  ドキュメント  |  Google Developers
Google 検索で JavaScript が処理される仕組みと、JavaScript ベースのウェブアプリを Google 検索向けに改善するためのおすすめの方法をご確認ください。

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

Implement dynamic rendering with Rendertron  |  Google Codelabs
In this codelab, you’ll implement dynamic rendering for a sample site, which allows JavaScript content to display in Google Search.

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

スポンサーリンク

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

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

GitHub - omrilotan/isbot: 💻 JavaScript module that detects bots/crawlers/spiders via the user agent
💻 JavaScript module that detects bots/crawlers/spiders via the user agent - GitHub - omrilotan/isbot: 💻 JavaScript module that detects bots/crawlers/spiders via...

有志によって作成されているクローラー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に登録しておく。

スポンサーリンク

確認

モバイル フレンドリー テスト - Google Search Console

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

モバイル フレンドリー テスト - Google Search Console

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

コメント

タイトルとURLをコピーしました