Skip to content

naoland/advent20201220

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

14 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Qiitaアドベントカレンダー2020年12月20日用の記事

はじめに

nemlogの新着記事のタイトルとURLを取得する方法を簡単に紹介します。

この手法はスクレイピングを使っていますので、もし、ご紹介したコードをご利用する前、にnemlog管理者の「しゅうさん」に必ず了解を得ましょう。

私は忘れてしまったので、事後報告とともに「しゅうさん」にご連絡するつもりです。

許可をいただきました!

動作確認はUbuntu 20.04LTSで行っています。

(venv) nao@330:~/naoland/advent20201220$ neofetch
            .-/+oossssoo+/-.               nao@330
        `:+ssssssssssssssssss+:`           -------
      -+ssssssssssssssssssyyssss+-         OS: Ubuntu 20.04.1 LTS x86_64
    .ossssssssssssssssssdMMMNysssso.       Host: 81D0 Lenovo ideapad 330-14IGM
   /ssssssssssshdmmNNmmyNMMMMhssssss/      Kernel: 5.4.0-58-generic
  +ssssssssshmydMMMMMMMNddddyssssssss+     Uptime: 1 day, 15 hours, 47 mins
 /sssssssshNMMMyhhyyyyhmNMMMNhssssssss/    Packages: 1684 (dpkg), 15 (snap)
.ssssssssdMMMNhsssssssssshNMMMdssssssss.   Shell: bash 5.0.17
+sssshhhyNMMNyssssssssssssyNMMMysssssss+   Resolution: 1366x768
ossyNMMMNyMMhsssssssssssssshmmmhssssssso   Terminal: /dev/pts/0
ossyNMMMNyMMhsssssssssssssshmmmhssssssso   CPU: Intel Celeron N4100 (4) @ 2.400GHz
+sssshhhyNMMNyssssssssssssyNMMMysssssss+   GPU: Intel UHD Graphics 605
.ssssssssdMMMNhsssssssssshNMMMdssssssss.   Memory: 2427MiB / 3758MiB
 /sssssssshNMMMyhhyyyyhdNMMMNhssssssss/
  +sssssssssdmydMMMMMMMMddddyssssssss+
   /ssssssssssshdmNNNNmyNMMMMhssssss/
    .ossssssssssssssssssdMMMNysssso.
      -+sssssssssssssssssyyyssss+-
        `:+ssssssssssssssssss+:`
            .-/+oossssoo+/-.

Python環境は導入済みであることを前提として、以降の説明をすすめていきます。

事前準備

JavaScriptによって動的に生成される新着記事を取得するために、Pythonパッケージをインストールします。

pip install requests_html

pipは事前にアップデートしておいた方がよいかもしれません。 また、不足しているUbuntuのパッケージ(主に開発用)があるかもしれませんが、その場合はエラーが表示されますので、必要なパッケージをインストールしましょう。

nemlogの新着記事を取得

次のPythonコードをgetnewpost.pyとして任意の場所に保存してください

"""nemlogの新着記事を1件取得して`dict`型の変数に格納します"""

from requests_html import HTMLSession, AsyncHTMLSession

newpost: dict = {}

# セッション開始
session = HTMLSession()
url = "https://nemlog.nem.social/guest"
r = session.get(url)

# HTMLを生成
r.html.render(timeout=30)  # デフォルトだとタイムアウトが頻発する
selector = "div.blog-card-wrapper"

items = r.html.find(selector, first=False)
for i in items:
    title = i.text.splitlines()[2]
    url = list(i.absolute_links)[0]
    newpost = {"title": title, "url": url}
    break  # 1件だけ

print(f"新着ポスト: {newpost}")

このコードでは説明の便宜上、適切なエラー処理を行っていません。

次のようにコードを実行します。

python getnewpost.py

初回のプログラム実行時には、ヘッドレスchromiumがダウンロードされます。

[W:pyppeteer.chromium_downloader] start chromium download.
Download may take a few minutes.
100%|███████████████████████████████████████████████████████████████████████████████████████████| 108773488/108773488 [03:24<00:00, 531491.68it/s]
[W:pyppeteer.chromium_downloader] 
chromium download done.

しかし、初回のプログラム実行時には次のようにタイムアウトエラーが発生するかもしれません。

(venv) $ python getnewpost.py 
Traceback (most recent call last):
  File "getnewpost.py", line 9, in <module>
    r.html.render(timeout=30)  # デフォルトだとタイムアウトが頻発する
  File "/home/nao/naoland/advent20201220/venv/lib/python3.8/site-packages/requests_html.py", line 598, in render
    content, result, page = self.session.loop.run_until_complete(self._async_render(url=self.url, script=script, sleep=sleep, wait=wait, content=self.html, reload=reload, scrolldown=scrolldown, timeout=timeout, keep_page=keep_page))
  File "/usr/local/lib/python3.8/asyncio/base_events.py", line 616, in run_until_complete
    return future.result()
  File "/home/nao/naoland/advent20201220/venv/lib/python3.8/site-packages/requests_html.py", line 512, in _async_render
    await page.goto(url, options={'timeout': int(timeout * 1000)})
  File "/home/nao/naoland/advent20201220/venv/lib/python3.8/site-packages/pyppeteer/page.py", line 885, in goto
    raise error
pyppeteer.errors.TimeoutError: Navigation Timeout Exceeded: 30000 ms exceeded.

私もタイムアウトエラーが発生したのですが、何度実行しなおしても同じエラーが発生していました

そのため、タイムアウトを30秒に指定しましたが、たまにタイムアウトエラーが発生します。

このコードの正常な実行結果は次のようになります。

(venv) $ python getnewpost.py 
新着ポスト: {'title': 'ネムツア12/19 空き時間でランと筋トレ', 'url': 'https://nemlog.nem.social/blog/53235'}

動画GIF getpost

今後の改良点

  • 今回の記事では新着記事1件のみを取得していますが、お好みの件数分取得したり、前回の記事取得時から更新された分だけ取得するなど、工夫してみるとよいでしょう。
  • 定期的に新着記事をチェックすると良いかもしれません。ただし、スクレイピングはnemlogに負担をかけますので、1時間未満の定期チェックは避けるべきです。
  • 新着情報をLineやメールなどで通知できるようにすると便利かもしれません。

最後に

ご紹介した整理後のコードを見るととても簡単そうに見えますが、作成中はrequests_htmlが返すオブジェクトの中身を逐一チェックして調整をおこなっています。 結構面倒くさかったです。

新着記事の箇所を見つけるために、

selector = "div.blog-card-wrapper"

という「CSSセレクター」を指定していますが、「XPath」という方式で指定する方法もあります。

この記事ではスクレイピングについては詳しく説明していませんが、興味のある方はスクレイピング というキーワードでググってみてください。

いや~、こういう処理にはPythonはもってこいですね!

p.s. 本当はLINEに新着を通知するところまでやりたかったのですが今回は無理でした。おそらくこのリポジトリ内+nemlogで続きを紹介したいと思います。 ただし、「しゅうさん」の了解がとれた場合です。

許可をいただきました!

参考情報へのリンク