「Qiitaのトレンドを取得しようと思ったけど、そのためのAPI用意されてないじゃん、、」
今回は、そんな方へ向けて、PythonでQiitaのトレンド情報を取得するプログラムを紹介・解説します。
ここで紹介するプログラムは2通りあるので、用途に合わせて活用してみてください。
(サンプルコードもあります)
本記事でわかること
- requestsを使ってトレンドを取得する方法
- ChromeDriver + Seleniumを使ってトレンドを取得する方法
動作環境
・Windows 10
・Python 3.7.7
事前準備
Qiitaのトレンド情報を抽出する際に、Pythonのライブラリである「BeautifulSoup」を使用するため、まだインストールしていない方は、先にインストールを行ってください。
以下のコマンドをターミナル上に入力すればインストールできます。
ChromeDriverとSeleniumも用意する必要があるので、Selenium・WebDriverの準備手順に従って準備してください。
requests ver
まずは、requestsモジュールを使ったコードを紹介します。
実装コード
実装コードはこちらです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
# 必要なライブラリのインポート import json import requests import pandas as pd from bs4 import BeautifulSoup url = "https://qiita.com/" # QiitaのトップページURL html = requests.get(url) soup = BeautifulSoup(html.text, "html.parser") # トップページのソースコードを取得 items = soup.find(attrs={"data-hyperapp-app": "Trend"}) # トレンド情報を持つ要素を抽出 trend_info = json.loads(items["data-hyperapp-props"]) # トレンド情報を抽出 article_info = { "Created at": [], "Title": [], "Likes": [], "URL": [] } article_url_temp = "https://qiita.com/{user_name}/items/{article_id}" # 記事URLのテンプレート # すべてのトレンド情報をループで回す for item in trend_info["trend"]["edges"]: item = item["node"] created_at = item["createdAt"] # 投稿日 title = item["title"] # 記事タイトル likes_count = item["likesCount"] # LGTMの数 user_name = item["author"]["urlName"] # ユーザー名 article_id = item["uuid"] # 記事ID article_url = article_url_temp.format( # 記事URL user_name=user_name, article_id=article_id ) # リストに格納 article_info["Created at"].append(created_at) article_info["Title"].append(title) article_info["Likes"].append(likes_count) article_info["URL"].append(article_url) trend_df = pd.DataFrame(article_info) # データフレーム化 trend_df.to_csv("trends.csv", index=False, encoding="utf_8_sig") # CSVファイルで保存 |
実行結果
さきほどのプログラムで保存される情報は、以下の4つです。
- 投稿日
- 記事タイトル
- LGTMの総数
- 記事のURL
保存したCSVファイルはこのようになります。
解説
7~9行目
まずは、Qiitaのトップページのソースコードを取得します。
7 8 9 |
url = "https://qiita.com/" # QiitaのトップページURL html = requests.get(url) soup = BeautifulSoup(html.text, "html.parser") # トップページのソースコードを取得 |
11,12行目
ここでは、ソースコードの中からトレンド情報だけを抽出しています。
11 12 |
items = soup.find(attrs={"data-hyperapp-app": "Trend"}) # トレンド情報を持つ要素を抽出 trend_info = json.loads(items["data-hyperapp-props"]) # トレンド情報を抽出 |
実際にソースコードを確認すると、属性値として、json形式でトレンド情報が格納されていますね。
上のコードでは、この値だけを抽出していることになります。
14~40行目
ここでは、先ほど抽出した情報をループで回して、その中から更に必要な情報だけを抽出しています。
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
article_info = { "Created at": [], "Title": [], "Likes": [], "URL": [] } article_url_temp = "https://qiita.com/{user_name}/items/{article_id}" # 記事URLのテンプレート # すべてのトレンド情報をループで回す for item in trend_info["trend"]["edges"]: item = item["node"] created_at = item["createdAt"] # 投稿日 title = item["title"] # 記事タイトル likes_count = item["likesCount"] # LGTMの数 user_name = item["author"]["urlName"] # ユーザー名 article_id = item["uuid"] # 記事ID article_url = article_url_temp.format( # 記事URL user_name=user_name, article_id=article_id ) # リストに格納 article_info["Created at"].append(created_at) article_info["Title"].append(title) article_info["Likes"].append(likes_count) article_info["URL"].append(article_url) |
抽出した値は、 article_info 内のリストへ格納しておきます。
ポイントとして、抽出した情報の中に、記事のURLは含まれていないのですが、その他の情報をもとにURLを作成しています。
コードからわかるように、Qiitaの記事URLは、 https://qiita.com/{user_name}/items/{article_id} という構成になっているので、 user_name と article_id を埋めることでURLを作成できるということです。
42,43行目
最後に、4種類のトレンド情報をCSVファイルとして保存しておしまいです。
42 43 |
trend_df = pd.DataFrame(article_info) # データフレーム化 trend_df.to_csv("trends.csv", index=False, encoding="utf_8_sig") # CSVファイルで保存 |
requests verのデメリット
requestsモジュールを使った方法は、とても単純であり、実行時間もほとんどかかりません。
しかし、「1日のトレンド情報しか取得できない」というデメリットがあります。
これは、週間・月間トレンド情報は、Qiitaにログインしていないと見ることができない、という仕様が要因です。
requestsモジュールを使ってログインする方法があればいいのですが、色々試しても、うまくいく手段がありませんでした。
(requestsモジュールで、Qiitaにログインする方法がわかる方は是非教えてください!)
requestsのデメリットを考慮して、次に紹介する方法では、自動ログインも実装します。
ChromeDriver + Selenium ver
ここでは、ChromeDriverとSeleniumを使ったスクレイピングを紹介します。
先に言っておくと、後半の処理は、requestsモジュールを使ったコードと同じになっています。
先程との違いとしては、自動ログインを追加した点ぐらいですね。
では、実際に内容を見ていきましょう。
実装コード
実装コードはこちらになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
# 必要なライブラリのインポート import json import requests import pandas as pd from time import sleep from bs4 import BeautifulSoup from selenium import webdriver from selenium.webdriver.chrome.options import Options USER_NAME = "<NAME of EMAIL>" # Qiitaのユーザー名 or メールアドレス PASSWORD = "<PASSWORD>" # Qiitaのパスワード scope = "daily" # トレンド期間 (週間: weekly, 月間: monthly) url = f"https://qiita.com/login?redirect_to=%2F%3Fscope%3D{scope}" # ログインURL driver_path = "./chromedriver.exe" # Chrome Driverのパス options = Options() options.add_argument('--headless') # ヘッドレス driver = webdriver.Chrome(executable_path=driver_path, options=options) driver.get(url) # URLを読み込む sleep(0.2) identity = driver.find_element_by_name("identity") password = driver.find_element_by_name("password") identity.send_keys(USER_NAME) # ユーザー名を入力 password.send_keys(PASSWORD) # パスワードを入力 sleep(0.2) login_btn = driver.find_element_by_name("commit") sleep(0.2) login_btn.click() # ログイン html = driver.page_source # ソースコードを取得 driver.close() # Chrome Driverを閉じる soup = BeautifulSoup(html, "html.parser") # トップページのソースコードを取得 items = soup.find(attrs={"data-hyperapp-app": "Trend"}) # トレンド情報を持つ要素を抽出 trend_info = json.loads(items["data-hyperapp-props"]) # トレンド情報を抽出 article_info = { "Created at": [], "Title": [], "Likes": [], "URL": [] } article_url_temp = "https://qiita.com/{user_name}/items/{article_id}" # 記事URLのテンプレート # すべてのトレンド情報をループで回す for item in trend_info["trend"]["edges"]: item = item["node"] created_at = item["createdAt"] # 投稿日 title = item["title"] # 記事タイトル likes_count = item["likesCount"] # LGTMの数 user_name = item["author"]["urlName"] # ユーザー名 article_id = item["uuid"] # 記事ID article_url = article_url_temp.format( # 記事URL user_name=user_name, article_id=article_id ) # リストに格納 article_info["Created at"].append(created_at) article_info["Title"].append(title) article_info["Likes"].append(likes_count) article_info["URL"].append(article_url) trend_df = pd.DataFrame(article_info) # データフレーム化 trend_df.to_csv("trends.csv", index=False, encoding="utf_8_sig") # CSVファイルで保存 |
最終的にできるCSVファイルは、requestsを使った場合と同じです。
解説
※ 39行目以降は、requests verと全く同じなので割愛します。
11, 12行目
まずは、Qiitaのアカウント情報を入力します。
11 12 |
USER_NAME = "<NAME of EMAIL>" # Qiitaのユーザー名 or メールアドレス PASSWORD = "<PASSWORD>" # Qiitaのパスワード |
14~23行目
ここでは、自動ログインのための初期設定を行います。
14 15 16 17 18 19 20 21 22 23 |
scope = "daily" # トレンド期間 (週間: weekly, 月間: monthly) url = f"https://qiita.com/login?redirect_to=%2F%3Fscope%3D{scope}" # ログインURL driver_path = "./chromedriver.exe" # Chrome Driverのパス options = Options() options.add_argument('--headless') # ヘッドレス driver = webdriver.Chrome(executable_path=driver_path, options=options) driver.get(url) # URLを読み込む sleep(0.2) |
週間トレンドを取得したい場合は、scope = “weekly” 、月間トレンドを取得したい場合は、scope = “monthly” としてください。
それ以外を指定した場合は、自動的に1日のトレンドになります。
このURL先のログイン画面では、ログイン後、指定した期間のトレンド画面へと遷移します。
あとは、 driver.get(url) で、URL先にアクセスします。
25~33行目
ここでは、ログイン画面のフォームを埋めて、Qiitaへログインしていきます。
15 16 17 18 19 20 21 22 23 |
identity = driver.find_element_by_name("identity") password = driver.find_element_by_name("password") identity.send_keys(USER_NAME) # ユーザー名を入力 password.send_keys(PASSWORD) # パスワードを入力 sleep(0.2) login_btn = driver.find_element_by_name("commit") sleep(0.2) login_btn.click() # ログイン |
35,36行目
トップページのソースコードを取得後、Driverを閉じて、おしまいです。
35 36 |
html = driver.page_source # ソースコードを取得 driver.close() # Chrome Driverを閉じる |
これで、HTMLコードの取得まで終わったので、残りはrequests verと同じ処理を行います。
ChromeDriver + Selenium verのデメリット
ChromeDriver + Seleniumを使った場合、トレンド期間を指定して情報を取得できますが、実行時間が長いというデメリットがあります。
リアルタイムでささっとトレンド情報を取得する必要がある場合は、ここがボトルネックとなる可能性があります。
ただ、そこまでスピードを求めないのであれば、特に問題はないです。
おわりに
今回は、2種類のコードを紹介してみました。
実際のところ、ChromeDriver + Seleniumを使った方が、期間も指定でき、サクッとトレンド情報を取得できると思います。
時間に制限がある場合は、おそらく要相談って感じでしょうね。
余談ですが、僕の場合、アレクサのスキル開発で使用したかったので、ChromeDriver + Seleniumだと時間制限がきつかったです。
>>【Alexa × LINEBot】Qiitaのトレンドを取得するアプリを作ってみた!
まあ、両方扱えて損は無いと思うので、是非2種類とも使ってみてください。
では、今回はここまでとします。
お疲れさまでした。