Создание агрегаторов научных статей

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Всем привет! В этом посте я хочу рассказать про некоторые возможности автоматизации задач, с которыми сталкивается программист-исследователь.

В моей работе часто возникает потребность изучать научные статьи. Это помогает быть в курсе событий, а также исследовать новые методы и области.

Бывает очень полезно фиксировать прочитанную информацию, чтобы не приходилось постоянно возвращаться к одному и тому же материалу, чтобы что-то найти. Обычно я веду заметки, но переносить туда ссылки на статьи, скачивать их, создавать таблицы бывает муторно. Огромную работу проделали создатели гитхаб репозиториев-агрегаторов статей по определённым темам. Например, статьи про клоны кода или статьи про фаззинг. Эти репозитории заставили меня задуматься над автоматизацией создания таких списков статей. В результате я определила последовательность действий, которую я выполняю при исследовании новой темы:

  • Шаг 1. Поиск статей в известных источниках (например, Semantic Scholar или arxiv)

  • Шаг 2. Чтение аннотаций к статьям, по которым часто можно понять, подходят ли они по тематике.

  • Шаг 3. Выделение важных объектов из статей: к ним можно отнести ссылки на гитхаб, графики, картинки (чтобы можно было, например, сослаться на результаты статьи в своей презентации, не испортив качество объекта при вставке) , а также год написания и журнал для понимания уровня статьи и актуальности.

  • Шаг 4. Подробное изучение выбранных статей.

Сбор информации для первых трёх шагов можно автоматизировать. Остановимся подробнее на них.

Поиск статей

Semantic Scholar и arxiv имеют специальное API для поиска статей по запросу. С помощью него можно узнать базовую информацию про статьи и скачать их при наличии открытого доступа.

Например, исходя из документации для arxiv, для поиска статей по запросу потребуется написать подобный код:

import arxiv

# Construct the default API client.
client = arxiv.Client()

# Search for the 10 most recent articles matching the keyword "quantum."
search = arxiv.Search(
  query = "quantum",
  max_results = 10,
  sort_by = arxiv.SortCriterion.SubmittedDate
)
results = client.results(search)

Для найденных статей можно получить аннотацию, авторов, год публикации, ссылку на скачивание в случае открытого доступа и т.д:

papers = [
    {
          "title": result.title,
          "authors": ", ".join([author.name for author in result.authors]),
          "journal": result.journal_ref,
          "year": result.published.year,
          "abstract": result.summary,
          "openAccessPdf": {"url": result.pdf_url},
          "paperId": result.entry_id.split("/")[-1], # last part of url after slash
    } for result in results
]

Статьи можно скачать с помощью следующего кода:

results = client.results(search)
paper_to_download = next(results)
paper_to_download.download_pdf(dirpath=".", filename="some-article.pdf")

Для Semantic Scholar примеры использования API есть в репозитории.

Аналогичный по содержанию код для Semantic Scholar API может выглядеть следующим образом:

import requests
import json
from datetime import datetime

x_api_key = "your-api-key" # you can get it from official site

class SemanticScholarClient:
    def __init__(self):
        self.base_url = "https://api.semanticscholar.org/graph/v1"

    def search(self, query, max_results=10, sort_by="relevance"):
        endpoint = f"{self.base_url}/paper/search"
        
        params = {
            "query": query,
            "limit": max_results,
            "fields": "paperId,title,isOpenAccess,openAccessPdf,abstract,year,authors,citationCount,url,venue",
            "sort": sort_by
        }

        headers = {
            "X-API-KEY": x_api_key
        }

        response = requests.get(endpoint, params=params, headers=headers)
        response.raise_for_status()
        return response.json()['data']

class SemanticScholarSearch:
    def __init__(self, query, max_results=10, sort_by="relevance"):
        self.query = query
        self.max_results = max_results
        self.sort_by = sort_by

# Usage
client = SemanticScholarClient()

# Search for the 10 most recent articles matching the keyword "quantum."
search = SemanticScholarSearch(
    query="quantum",
    max_results=10,
    sort_by="publicationDate:desc"  # Sort by publication date, descending
)
results = client.search(search.query, search.max_results, search.sort_by)

papers = [
    {
        "title": result['title'],
        "authors": ", ".join([author['name'] for author in result['authors']]),
        "journal": result.get('venue', ''),
        "year": result['year'],
        "abstract": result.get('abstract', ''),
        "openAccessPdf": {"url": result.get('openAccessPdf', {}).get('url', '')} if result.get('openAccessPdf', {}) else None,
        "paperId": result['paperId'],
    } for result in results if result
]


# Download papers
for paper in papers:
    if paper['openAccessPdf']:
        print(f"Title: {paper['title']}")
        response = requests.get(paper['openAccessPdf']['url'])
        response.raise_for_status()

        filepath = f"{paper['title']}.pdf"

        with open(filepath, 'wb') as f:
            f.write(response.content)

Выделение объектов

Для автоматизации выделения объектов из статьи можно использовать библиотеку pdfplumber. В написании кода с использованием этой библиотеки очень помогла статья. С помощью парсинга элементов в PDF и регулярных выражений можно извлекать существующие в статье ссылки на гитхаб:

import pdfplumber
import re

def extract_text_from_pdf(pdf):
      text = ""
      for page in pdf.pages:
          text += page.extract_text() + "\n"
      return text.strip()

pdf = pdfplumber.open("some-article.pdf")
text_from_pdf = extract_text_from_pdf(pdf)

github_regex = r"https?://(?:www\.)?github\.com/[\w-]+/[\w.-]+[\w-]"
github_links = re.findall(github_regex, text_from_pdf)

Для извлечения картинок подходит библиотека PyMuPDF. Вот подробный гайд про использование библиотеки. Для сохранения картинок из статьи можно написать следующий код:

import fitz
doc = fitz.Document("some-article.pdf")

for i in tqdm(range(len(doc)), desc="pages"):
    cnt = 0 # counter to divide images on one page
    for img in tqdm(doc.get_page_images(i), desc="page_images"):
        xref = img[0]
        image = doc.extract_image(xref)
        pix = fitz.Pixmap(doc, xref)
        pix.save("img_%s_%s.png" % (i, cnt))
        cnt += 1

Не во всех случаях указанным методом удаётся извлечь все изображения из статей, поэтому в этой задаче есть огромное пространство для размышлений и идей по улучшению метода.


Перечисленные этапы реализованы в репозитории Researcher-Helper. На данный момент в нём поддерживается поиск по Semantic Scholar и arxiv. В результате он позволяет сгенерировать по запросу таблицу со статьями в формате html. Буду рада обратной связи, идеям по улучшению и советам в реализации описанных этапов!

Источник: https://habr.com/ru/articles/846704/


Интересные статьи

Интересные статьи

И это уже третья статья (первая и вторая) из цикла «Chrome Windows 7». Произошло несколько знаковых событий, о которых уважаемому читателю будет интересно знать и понимать, что готовит ему «корпорация...
Применять паттерны программирования — хорошая практика. К сожалению, на проектах CMS Bitrix редко встречаются примеры использования. В статье я покажу на примере, как можно использовать паттерн D...
Во второй части статьи про bitrix кластер мы будет рассматривать настройку percona xtradb cluster mysql 5.7, настройка арбитра, настройка удобного dashboard.Если вы пропустили предыдущие части: Первая...
Удалённая работа или офис открытого типа? Идея общего рабочего пространства далеко не нова. Вспомним, хотя бы, планировку статистической организации, в которой трудились известные персонажи советского...
Реализация ORM в ядре D7 — очередная интересная, перспективная, но как обычно плохо документированная разработка от 1с-Битрикс :) Призвана она абстрагировать разработчика от механики работы с табл...