1
1

NCBIのAPIを用いたクローラー開発の備忘録2024/08/18ゆきこ

Posted at

NCBIのデータ取得の解説

import requests  # HTTPリクエストを送るためのライブラリ
import os  # OS関連の機能を使用するためのライブラリ
import pandas as pd  # データを操作・分析するためのライブラリ
from datetime import datetime  # 日付と時間を操作するためのライブラリ
from xml.etree import ElementTree as ET  # XMLデータを解析するためのライブラリ

# 日付の形式を統一する関数
def format_date(date_str):
    # 複数のフォーマットで日付をパースし、"YYYY/MM/DD"形式に変換する
    for fmt in ("%Y/%m/%d", "%Y年%m月%d日", "%Y年%m月", "%Y年"):
        try:
            return datetime.strptime(date_str, fmt).strftime("%Y/%m/%d")
        except ValueError:
            continue
    return date_str  # 変換できなかった場合、元の文字列を返す

# PubMed APIを使って論文データを取得する関数
def fetch_pubmed_data(journal=None, pdat=None, volume=None, issue=None, authors=None):
    base_url = "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi"  # APIのエンドポイント
    db = "pubmed"  # 使用するデータベースはPubMed
    retmode = "json"  # レスポンス形式はJSON

    # APIに送信するパラメータを辞書として定義
    params = {
        "db": db,
        "retmode": retmode,
        "term": f"{journal}[journal]" if journal else None,  # ジャーナル名を検索条件に追加
        "mindate": pdat,  # 最小日付
        "maxdate": pdat,  # 最大日付
        "volume": volume,  # 巻号
        "issue": issue,  # 発行号
        "author": authors  # 著者名
    }

    # 値が存在するパラメータのみをフィルタリング
    filtered_params = {key: value for key, value in params.items() if value}
    response = requests.get(base_url, params=filtered_params)  # APIリクエストを送信

    if response.status_code == 200:  # ステータスコードが200(成功)なら
        return response.json()  # JSON形式でレスポンスを返す
    else:
        print(f"Error: {response.status_code}")  # エラーコードを表示
        print(response.text)  # エラーメッセージを表示
        return {"error": f"Failed to fetch data, status code: {response.status_code}", "details": response.text}

# 論文IDを使って、詳細データを取得する関数
def fetch_article_details(uid):
    base_url = f"https://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi"  # APIのエンドポイント
    db = "pubmed"  # 使用するデータベースはPubMed
    retmode = "xml"  # レスポンス形式はXML

    # APIに送信するパラメータを辞書として定義
    params = {
        "db": db,
        "retmode": retmode,
        "id": uid  # 取得する論文のID
    }

    response = requests.get(base_url, params=params)  # APIリクエストを送信
    if response.status_code == 200:  # ステータスコードが200(成功)なら
        return response.text  # XML形式でレスポンスを返す
    else:
        print(f"Error fetching article {uid}: {response.status_code}")  # エラーメッセージを表示
        return None

# XMLデータから論文のタイトルとリンクを抽出する関数
def parse_article_details(xml_data):
    root = ET.fromstring(xml_data)  # XMLデータを解析してルート要素を取得
    title = root.findtext(".//ArticleTitle")  # 論文タイトルを取得
    term = title.replace(" ", "%20")  # タイトル内のスペースをURLエンコード
    link = f"https://pubmed.ncbi.nlm.nih.gov/?term={term}"  # 論文検索用リンクを作成

    return title, link  # タイトルとリンクを返す

# CitMatch APIを使って追加データを取得する関数
def fetch_citmatch_data(journal, volume, page):
    url = f"https://pubmed.ncbi.nlm.nih.gov/api/citmatch/?method=field&journal={journal}&volume={volume}&page={page}"  # CitMatch APIのエンドポイント
    response = requests.get(url)  # APIリクエストを送信

    if response.status_code == 200:  # ステータスコードが200(成功)なら
        return response.json()  # JSON形式でレスポンスを返す
    else:
        print(f"Error: {response.status_code}")  # エラーメッセージを表示
        print(response.text)  # エラーメッセージの詳細を表示
        return {"error": f"Failed to fetch data, status code: {response.status_code}", "details": response.text}

# メイン関数
def main():
    print("PubMed Search")  # 検索開始のメッセージを表示
    journal = input("Enter journal name (or leave blank): ")  # ジャーナル名を入力
    pdat = input("Enter publication date (YYYY/MM/DD, YYYY年MM月DD日, etc., or leave blank): ")  # 発行日を入力
    volume = input("Enter volume (or leave blank): ")  # 巻号を入力
    issue = input("Enter issue (or leave blank): ")  # 発行号を入力
    authors = input("Enter authors (format: Surname Initial, or leave blank): ")  # 著者名を入力

    if not (journal or pdat or volume or issue or authors):  # いずれかの条件が設定されていない場合
        print("Error: At least one search parameter must be provided.")  # エラーメッセージを表示
        return

    result = fetch_pubmed_data(journal, pdat, volume, issue, authors)  # PubMedデータを取得

    if "error" in result:  # エラーが含まれている場合
        print(result)  # エラーメッセージを表示
        return

    titles = []  # タイトルを格納するリスト
    links = []  # リンクを格納するリスト
    if "esearchresult" in result and "idlist" in result["esearchresult"]:  # 検索結果が存在する場合
        for uid in result["esearchresult"]["idlist"]:  # 取得した論文IDごとに
            details = fetch_article_details(uid)  # 論文の詳細を取得
            if details:
                title, link = parse_article_details(details)  # タイトルとリンクを解析
                titles.append(title)  # タイトルをリストに追加
                links.append(link)  # リンクをリストに追加

    # CitMatch APIを使って追加データを取得
    citmatch_result = fetch_citmatch_data("Front Immunol", "13", "826091")
    if "result" in citmatch_result and "uids" in citmatch_result["result"]:
        for item in citmatch_result["result"]["uids"]:
            uid = item["pubmed"]  # PubMed IDを取得
            details = fetch_article_details(uid)  # 論文の詳細を取得
            if details:
                title, link = parse_article_details(details)  # タイトルとリンクを解析
                titles.append(title)  # タイトルをリストに追加
                links.append(link)  # リンクをリストに追加

    data = {
        'Title': titles,  # タイトルリストをデータフレームに追加
        'Link': links  # リンクリストをデータフレームに追加
    }

    df = pd.DataFrame(data)  # データフレームを作成

    # Excelファイルの出力先を定義
    output_directory = os.path.join(os.path.expanduser('~'), 'Documents')
    output_file_path = os.path.join(output_directory, 'ncbi_api_result_info.xlsx')

    df.to_excel(output_file_path, index=False, engine='openpyxl')  # データフレームをExcelに出力

    print(f"Excelファイル '{output_file_path}' に保存されたよ!")  # 完了メッセージを表示

if __name__ == "__main__":
    main()  # メイン関数を実行

解説

このコードは、NCBIのAPIを使用してPubMedデータベースから学術論文の情報を取得し、それをExcelファイルに保存するものです。以下にコードの主要部分を解説します。

  1. 日付フォーマットの変換 (format_date 関数)
    日付を複数の形式から統一された形式(%Y/%m/%d)に変換します。異なる日付形式を取り扱うための処理です。

  2. PubMedデータの取得 (fetch_pubmed_data 関数)
    esearch.fcgi エンドポイントを使って、指定されたパラメータ(ジャーナル名、出版日、巻号、著者など)に基づいてPubMedデータベースから論文情報を検索します。検索結果はJSON形式で返されます。

  3. 論文の詳細取得 (fetch_article_details 関数)
    efetch.fcgi エンドポイントを使って、特定の論文ID(UID)に対応する詳細情報を取得します。この情報はXML形式で返されます。

  4. 論文タイトルとリンクの解析 (parse_article_details 関数)
    取得したXMLデータから論文タイトルを抽出し、PubMedでの検索リンクを生成します。

  5. Citmatch APIを使った追加データの取得 (fetch_citmatch_data 関数)
    ジャーナル名、巻号、ページ番号を指定して、特定の論文に関連するデータを取得します。取得したデータは、他のデータと同様に論文の詳細を取得するために使われます。

  6. メイン処理 (main 関数)
    ユーザーからの入力を受け取り、上記の関数を使って論文情報を取得し、Excelファイルとして保存します。

保存と出力
取得した論文情報をデータフレームにまとめ、Excelファイルとして保存します。出力先はユーザーのドキュメントフォルダです。

このコードを使うことで、指定した条件に基づくPubMedの論文情報を簡単に取得し、管理することができます。

詳細解説

  1. PubMedデータの取得 (fetch_pubmed_data)
    この関数では、esearch.fcgiというエンドポイントを使って、指定した条件に基づいてPubMedデータベースから論文のIDリストを取得します。journal(ジャーナル名)、pdat(発行日)、volume(巻号)、issue(号数)、authors(著者)などの検索パラメータを使って、検索クエリを作成します。

コード解説:

base_urlにAPIのエンドポイントURLを設定。
paramsに検索条件をセットし、リクエストを送信。
レスポンスをJSON形式で受け取り、結果を返します。
2. 論文詳細の取得 (fetch_article_details)
取得した論文ID(UID)を使って、efetch.fcgiエンドポイントから論文の詳細情報(XML形式)を取得します。

コード解説:

論文IDをパラメータとしてリクエストを送信。
XML形式で詳細データを受け取り、返します。
3. 論文詳細の解析 (parse_article_details)
XMLデータから論文のタイトルを抽出し、そのタイトルを使ってPubMedの検索リンクを生成します。

コード解説:

ElementTreeを使ってXMLを解析し、ArticleTitle要素からタイトルを取得。
タイトルを使って検索リンクを作成。
4. CitMatchデータの取得 (fetch_citmatch_data)
ジャーナル名、巻号、ページ番号を使って、特定の論文に関するデータを取得します。

コード解説:

citmatch APIにリクエストを送り、結果をJSON形式で受け取ります。
5. データの保存とエクスポート
取得した論文タイトルとリンクをExcelファイルに保存します。pandasを使ってデータフレームを作成し、openpyxlを利用してExcelファイルを出力します。

コード解説:

取得したデータをpandasのDataFrameに格納し、Excelファイルに保存。
このように、このコードはNCBIのAPIを活用してPubMedからの情報を自動で取得・整理し、使いやすい形で保存することができます。

1
1
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
1