1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

[Python]Qiitaの記事情報をmongoDBに突っ込んだ

Posted at

やりたいこと

Qiitaの記事情報をQiitaAPIで取得し、どの記事、どのタグがよく見られているのか?などを確認したい。
その第一歩として、APIで取得した情報をmongoDBに登録してみる

Qiitaの記事情報を取得する

今回の内容はPythonで書いています。
記事情報の取得は以下の記事を参考にさせていただきました。

Qiita APIをPythonから使ってみる

get_qiita_info.py
import requests
import logging
import json

formatter = '%(asctime)s %(name)-12s %(levelname)-8s %(message)s'
logging.basicConfig(level=logging.WARNING, format=formatter)
logger = logging.getLogger(__name__)

class GetQiitaInfo(object):

    def __init__(self):
        self.token = 'your token'        

    def get_next_url(self, response):
        """次のページがある場合は'rel="next"'としてurlが含まれるので、urlを抽出して返す。
        ない場合はNoneを返す。

        link: <https://qiita.com/api/v2/authenticated_user/items?page=1>;
        rel="first", <https://qiita.com/api/v2/authenticated_user/items?page=2>;
        rel="next", <https://qiita.com/api/v2/authenticated_user/items?page=4>;
        rel="last"

        :param response:
        :return: 次のurl
        """
        link = response.headers['link']
        if link is None:
            return None

        links = link.split(',')

        for link in links:

            if 'rel="next"' in link:
                return link[link.find('<') + 1:link.find('>')]
        return None
      
    def get_items(self):
        
        """ページネーションして全ての記事を取得し、
        ストック数とビュー数は一覧に含まれないので、それらの情報も追加して返す。

        :param token:
        :return: 記事のリスト
        """
        
        url = 'https://qiita.com/api/v2/authenticated_user/items'
        headers = {'Authorization': 'Bearer {}'.format(self.token)}

        items = []
        while True:
            response = requests.get(url, headers=headers)
            response.raise_for_status()
            items.extend(json.loads(response.text))
            logger.info('GET {}'.format(url))
            # 次のurlがあるかを確認する
            url = self.get_next_url(response)
            if url is None:
                break

        # 各記事についてビュー数とストック数の情報を取得して追加する
        # page_views_countは一覧APIにもフィールドはあるがnullが返ってくる
        for item in items:

            # ビュー数
            url = 'https://qiita.com/api/v2/items/{}'.format(item['id'])
            logger.info('GET {}'.format(url))
            response = requests.get(url, headers=headers)
            response.raise_for_status()
            itemJson = json.loads(response.text)
            item['page_views_count'] = itemJson['page_views_count']
            item['tag1'] = itemJson['tags'][0]['name']
            item['tag2'] = itemJson['tags'][1]['name'] if len(itemJson['tags']) >= 2 else ''
            item['tag3'] = itemJson['tags'][2]['name'] if len(itemJson['tags']) >= 3 else ''
            item['tag4'] = itemJson['tags'][3]['name'] if len(itemJson['tags']) >= 4 else ''
            item['tag5'] = itemJson['tags'][4]['name'] if len(itemJson['tags']) >= 5 else ''

            tag_list = []
            for i in range(len(itemJson['tags'])):
                tag_list.append(itemJson['tags'][i]['name'])
            item['tag_list'] = tag_list

            # ストック数
            url = 'https://qiita.com/api/v2/items/{}/stockers'.format(item['id'])
            logger.info('GET {}'.format(url))
            response = requests.get(url, headers=headers)
            response.raise_for_status()
            users = json.loads(response.text)
            for user in users:
                logger.info({
                    'id': user['id'],
                    'name': user['name']
                    })
            item['stocks_count'] = len(users)

        return items

自身の勉強のため、参考にさせていただいた記事から2点変更を加えました。
・クラスにした
・tag1~tag5、tag_listを追加

mongoDB操作用クラス

以前にmongoDB操作の記事を書きましたが、その内容のままです。

参考
Pythonでmongodbを操作する~その4:insert編~

mongo_sample.py
from pymongo import MongoClient

class MongoSample(object):

    def __init__(self, dbName, collectionName):
        self.client = MongoClient()
        self.db = self.client[dbName] #DB名を設定
        self.collection = self.db.get_collection(collectionName)

    def find_one(self, projection=None,filter=None, sort=None):
        return self.collection.find_one(projection=projection,filter=filter,sort=sort)

    def find(self, projection=None,filter=None, sort=None):
        return self.collection.find(projection=projection,filter=filter,sort=sort)

    def insert_one(self, document):
        return self.collection.insert_one(document)

    def insert_many(self, documents):
        return self.collection.insert_many(documents)

記事情報を取得しmongoDBに登録する

sample.py
from get_qiita_info import GetQiitaInfo
from mongo_sample import MongoSample

# Qiitaの記事情報を取得する
qiita = GetQiitaInfo()
items = qiita.get_items()

# arg1:DB Name
# arg2:Collection Name
mongo = MongoSample("db", "qiita")

# 不要なキー値を削除しないのであれば
# mongo.insert_many(items)
# で一括登録

for item in items:
    # rendered_body/body は不要なので削除
    item.pop("rendered_body")
    item.pop("body")
    # 一件ずつ登録
    mongo.insert_one(item)

result = mongo.find_one()
print(result)

上記のコードを実行後のmongoDBを見てみます。
※上記のコードの実行結果として1件データを表示していますが、1行に表示されて見辛いのでmongoDBで確認。。

> db.qiita.findOne()
{
        "_id" : ObjectId("5e38ff43c92e7c532aeffb47"),
        "coediting" : false,
        "comments_count" : 0,
        "created_at" : "2020-02-04T13:37:44+09:00",
        "group" : null,
        "id" : "331ae2289a95f5a9b901",
        "likes_count" : 0,
        "private" : false,
        "reactions_count" : 0,
        "tags" : [
                {
                        "name" : "Python",
                        "versions" : [ ]
                },
                {
                        "name" : "Python3",
                        "versions" : [ ]
                }
        ],
        "title" : "[Python]No value for argument 'self' in unbound method callが出た",
        "updated_at" : "2020-02-04T13:37:44+09:00",
        "url" : "https://qiita.com/bc_yuuuuuki/items/331ae2289a95f5a9b901",
        "user" : {
                "description" : "ブロックチェーン/AI/Python/Golang/MongoDBなどを学習中です。\r\nこのサイトにおける掲載内容はあくまで私自身の見解であり、必ずしも私の所属団体・企業における立場、戦略、意見を代表するものではありません。",
                "facebook_id" : "",
                "followees_count" : 0,
                "followers_count" : 2,
                "github_login_name" : null,
                "id" : "bc_yuuuuuki",
                "items_count" : 28,
                "linkedin_id" : "",
                "location" : "",
                "name" : "",
                "organization" : "",
                "permanent_id" : 476876,
                "profile_image_url" : "https://pbs.twimg.com/profile_images/1157834557783072768/ktpc9kGV_bigger.jpg",
                "team_only" : false,
                "twitter_screen_name" : "bc_yuuuuuki",
                "website_url" : ""
        },
        "page_views_count" : 54,
        "tag1" : "Python",
        "tag2" : "Python3",
        "tag_list" : [
                "Python",
                "Python3"
        ],
        "stocks_count" : 0
}

登録されていることが確認出来ました。

感想

今回のコードではAPIの取得結果に多少手を加えていますが、APIを叩いて取得したJSONを何も考えずに突っ込んで検索や集計が出来るようになるのは便利ですね。

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?