PythonでWordPressの記事を取得する方法

環境

  • Windows 10
  • Python 3.10.1
  • VSCode

使用するソースコード

以下の公開リポジトリに置いています

GitHub - masayan1126/tao-py-py: 作業自動化用 Python ライブラリ
作業自動化用 Python ライブラリ. Contribute to masayan1126/tao-py-py development by creating an account on GitHub.

実装方法

WordPressのrest-apiのドキュメントによると、記事一覧の取得APIのエンドポイントは、https://example.com/wp-json/wp/v2/postsになるので、こちらに対してpythonのプログラムからrequestsモジュールでHttpリクエストを送ればOKです

masayan
masayan

公式ドキュメントのAPIリファレンスはこちらです。

Whttps://developer.wordpress.org/rest-api/reference/

呼び出し側

  • wordpressのエンドポイントを生成し、それをwp管理用の自作クラスに渡しています
  • fetch_posts()にはページの指定ができるようにしていますが、デフォルトは全件取得のためNoneにしています
from shared.Domain.Wp.wp_operator import WpOperator

blog_url = "https://maasaablog.com/"
api_url = blog_url + "/wp-json/wp/v2/posts"

wp = WpOperator(api_url=api_url)
posts = wp.fetch_posts(page_number=None)

記事の取得処理

  • オブジェクト生成時に、wordpressのエンドポイントとなるurlを受け取ります
  • レスポンスヘッダ―に記事の全件数とページ数が入っているのでそれらを取得できるメソッドを実装します
    • 総ページ数はレスポンスヘッダの[“X-WP-TotalPages”]
    • 総記事数はレスポンスヘッダの[“X-WP-Total”]
  • fetch_postsでは、呼び出し側から受け取ったページ数の指定がなければ全件取得し、ページ指定があれば、そのページの記事を取得するようにしています
  • 実際にエンドポイントを叩く処理はpythonのrequestsモジュールのgetメソッドを使用しているだけです
from typing import List

import urllib.request, urllib.error
from shared.Domain.Wp.i_wp_operator import IWpOperator
import requests
from shared.Domain.xurl import XUrl
import json
from shared.Exception.wp_error import WpError

class WpOperator(IWpOperator):
    def __init__(self, api_url: XUrl):
        # urlがそもそも無効ならここで落とす
        try:
            f = urllib.request.urlopen(api_url)
            self._api_url = api_url
        except urllib.error.URLError as e:
            raise e
        finally:
            if "f" in locals():
                f.close()

    def response_headers(self):
        return requests.head(self._api_url).headers

    def total_page_count(self) -> int:
        try:
            return int(self.response_headers()["X-WP-TotalPages"])
        except KeyError as e:
            raise WpError("This url is valid. But may not be a wordpress api url")

    def total_posts_count(self) -> int:
        try:
            return int(self.response_headers()["X-WP-Total"])
        except KeyError as e:
            raise WpError("This url is valid. But may not be a wordpress api url")

    def fetch_posts(self, page_number: int = None) -> List[dict]:
        try:
            posts = []

            # ページ指定なし
            if page_number is None:
                _posts = []
                for page_count in range(1, self.total_page_count() + 1):
                    res = requests.get(f"{self._api_url}?page={page_count}")

                    for post in json.loads(res.text): # JSON文字列を辞書型に変換
                        _posts.append(post)

            else:
                res = requests.get(f"{self._api_url}?page={page_number}")
                _posts = json.loads(res.text)  # JSON文字列を辞書型に変換

            for post in _posts:
                post_info = {
                    "title": post["title"]["rendered"],
                    "link": post["link"],
                }
                posts.append(post_info)
            return posts

        except requests.exceptions.HTTPError as e:
            raise e
masayan
masayan

json.loadsの返り値は記事の配列ですが、1つ1つの記事は以下のような辞書型です

{‘id’: 4150, ‘date’: ‘2022-02-28T08:34:33’, ‘date_gmt’: ‘2022-02-27T23:34:33’, ‘guid’: {‘rendered’: ‘https://maasaablog.com/?p=4150’},  ‘status’: ‘publish’, ‘type’: ‘post’, ‘link’: ‘https://maasaablog.c…thon/4150/’, ‘title’: {‘rendered’: ‘Pythonでいい感じのロギングするためのTips’},  …}

Python学習におすすめの書籍

独習Python/山田祥寛【3000円以上送料無料】
bookfan 1号店 楽天市場店
¥ 3,300(2023/01/31 18:22時点)
タイトルとURLをコピーしました