banner
Riceneeder

Riceneeder

白天研究生,晚上研究死
github
email

使用python將SCI文獻PDF轉Markdown

這是之前寫文獻綜述的時候,為了方便整理文獻,寫了一個小工具,可以將 SCI 文獻的 PDF 轉換為 Markdown 格式。這樣就可以直接在 Markdown 編輯器中編輯文獻,方便整理、翻譯和寫作。

具體的代碼如下:

import requests
import random
import os
from concurrent.futures import ThreadPoolExecutor, as_completed
import scipdf
import string
from datetime import datetime

# 自定義異常,用於處理 GROBID 服務的異常情況
class GROBID_OFFLINE_EXCEPTION(Exception):
    pass

class PDFToMarkdown:
    def __init__(self, input_path, grobid_urls=None):
        """
        初始化 PDFToMarkdown 實例。

        Args:
            input_path (str): 要處理的文件或文件夾路徑。
            grobid_urls (list): 可選,GROBID 伺服器 URLs 列表。默認為預設的 URLs 列表。
        """
        self.input_path = input_path
        # 使用自定義 GROBID 伺服器,如果沒有則使用默認伺服器
        self.grobid_urls = grobid_urls if grobid_urls is not None else [
            "https://qingxu98-grobid.hf.space",
            "https://qingxu98-grobid2.hf.space",
            # ... (其他伺服器 URL)
            "https://qingxu98-grobid8.hf.space",
        ]

    def get_avail_grobid_url(self):
        """獲取可用的 GROBID 伺服器 URL"""
        if not self.grobid_urls:
            return None

        while self.grobid_urls:
            _grobid_url = random.choice(self.grobid_urls)  # 隨機選擇一個 GROBID URL
            if _grobid_url.endswith('/'):
                _grobid_url = _grobid_url.rstrip('/')
            try:
                # 檢查伺服器是否在線
                res = requests.get(f"{_grobid_url}/api/isalive", timeout=5)
                if res.text == 'true':
                    return _grobid_url  # 返回可用的 URL
            except (requests.ConnectionError, requests.Timeout):
                # 如果連接錯誤或超時,從列表中移除此 URL
                self.grobid_urls.remove(_grobid_url)
        return None  # 如果沒有可用的伺服器,返回 None

    @staticmethod
    def dict_to_markdown(article_json):
        """將文章字典轉換為 Markdown 格式字符串"""
        markdown_lines = []
        markdown_lines.append(f"# {article_json.get('title', '無標題')} \n")  # 標題
        markdown_lines.append(f"> doi:{article_json.get('doi', '')} \n")  # DOI
        markdown_lines.append(f"+ authors\n{article_json.get('authors', ['無作者'])}  \n")  # 作者
        markdown_lines.append(f"+ abstract\n{article_json.get('abstract', '無摘要')}  \n")  # 摘要

        # 處理各章節內容
        if 'sections' in article_json:
            for section in article_json['sections']:
                markdown_lines.append(f"+ {section['heading']}\n{section['text']}\n")  # 章節標題與內容

        return "\n".join(markdown_lines)  # 返回合併後的 Markdown 字符串

    @staticmethod
    def save_markdown_file(filename, content):
        """將內容寫入到 Markdown 文件"""
        with open(filename, 'w', encoding='utf-8') as f:
            f.write(content)  # 寫入內容到文件

    def parse_pdf(self, pdf_path, grobid_url):
        """解析單個 PDF 文件,返回文章字典"""
        if not os.path.isfile(pdf_path):
            raise FileNotFoundError(f"指定路徑下沒有找到 PDF 文件: {pdf_path}")  # 檢查文件是否存在

        if grobid_url.endswith('/'):
            grobid_url = grobid_url.rstrip('/')

        try:
            # 使用 GROBID 解析 PDF
            return scipdf.parse_pdf_to_dict(pdf_path, grobid_url=grobid_url)
        except GROBID_OFFLINE_EXCEPTION:
            raise GROBID_OFFLINE_EXCEPTION("GROBID 服務不可用,檢查配置中的 GROBID_URL。")
        except RuntimeError:
            raise RuntimeError("解析 PDF 失敗,請檢查 PDF 是否損壞。")

    def process_pdf_file(self, pdf_path, grobid_url):
        """處理單個 PDF 文件,返回 Markdown 內容"""
        print(f"正在解析: {pdf_path}")
        try:
            pdf_article_dict = self.parse_pdf(pdf_path, grobid_url)  # 解析 PDF 文件
            return self.dict_to_markdown(pdf_article_dict)  # 轉換為 Markdown
        except Exception as e:
            print(f"處理文件 {pdf_path} 時發生錯誤: {e}")
            return None  # 出現錯誤時返回 None

    def process(self):
        """處理輸入文件或文件夾,並返回生成的 Markdown 文件路徑"""
        markdown_contents = []  # 存儲所有 Markdown 內容
        grobid_url = self.get_avail_grobid_url()

        if grobid_url is None:
            raise RuntimeError("沒有可用的 GROBID 服務,請檢查您的伺服器配置。")

        # 根據輸入路徑判斷是文件還是文件夾
        if os.path.isfile(self.input_path):
            pdf_files = [self.input_path]  # 單個文件
        elif os.path.isdir(self.input_path):
            # 收集文件夾中的所有 PDF 文件
            pdf_files = [os.path.join(dirpath, filename)
                         for dirpath, _, filenames in os.walk(self.input_path)
                         for filename in filenames if filename.endswith('.pdf')]
        else:
            raise ValueError("輸入路徑既不是文件也不是文件夾。")

        # 使用線程池並行處理 PDF 文件
        with ThreadPoolExecutor(max_workers=5) as executor:
            future_to_file = {executor.submit(self.process_pdf_file, pdf, grobid_url): pdf for pdf in pdf_files}

            # 收集生成的 Markdown 內容
            for future in as_completed(future_to_file):
                result = future.result()
                if result:
                    markdown_contents.append(result)

        # 如果有有效的 Markdown 內容,將其保存到文件
        if markdown_contents:
            # 生成時間戳
            timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
            # 生成兩位隨機字母
            random_suffix = ''.join(random.choices(string.ascii_lowercase, k=2))
            output_filename = f"{timestamp}_{random_suffix}.md"
            self.save_markdown_file(output_filename, "\n\n".join(markdown_contents))  # 合併並保存為 Markdown 文件
            print(f"所有 Markdown 文件已合併並保存為 {output_filename}")
            return output_filename  # 返回生成文件路徑
        else:
            print("沒有有效的 Markdown 內容生成。")
            return None


# 如果直接運行此腳本,提供使用示例
if __name__ == "__main__":
    input_path = 'your_file_or_directory_path'  # 替換為你的文件或目錄路徑
    custom_grobid_urls = [
        "https://your-custom-grobid-server.com",
        "https://another-custom-grobid-server.com",
    ]
    pdf_to_markdown = PDFToMarkdown(input_path, grobid_urls=custom_grobid_urls)
    output_file = pdf_to_markdown.process()  # 處理 PDF 文件並生成 Markdown 文件
    print("生成的文件路徑:", output_file)  # 輸出生成的文件路徑

注意需要指定安裝了以下 Python 庫:

pip install git+https://github.com/titipata/scipdf_parser

使用時,替換 input_path 為你的文件或目錄路徑,這個腳本是多線程的,可以處理文件夾中的所有 PDF 文件。如果你有自己的 GROBID 伺服器,可以將其添加到 custom_grobid_urls 列表中,否則會使用默認的 GROBID 伺服器。最終會生成一個 Markdown 文件,其中包含所有 PDF 文件的內容。

參考:

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。