📝 요약
논문을 검색해 Zotero에 추가해도, 전문 PDF가 자동으로 붙지 않는 경우가 종종 있다.
그동안은 내가 소속된 기관 도서관 사이트에 직접 로그인하고, eJournal을 검색하고, 연결된 데이터베이스를 하나씩 눌러 PDF를 내려받아야 했다. 이번에는 그 반복 과정을 AI 에이전트에게 맡길 수 있는지 실험했고, 누락 PDF 후보를 좁히고 provider별 다운로드 경로를 recipe 로 쌓는 스킬 초안을 구성했다.
🎯 이런 분들께 도움돼요
Zotero와 같은 문헌 관리 도구를 쓰지만 PDF 정리가 자주 끊기는 분
기관 도서관, eJournal, 출판사 페이지를 오가며 반복 클릭을 많이 하는 분
😫 문제 상황: 왜 시작했나
이번 작업의 앞단에는 LLM Wiki raw 자동화 구축이 있었다.
LLM Wiki에 넣을 raw layer, 즉 나중에 요약·색인·연결·검토의 바탕이 되는 원문 자료층을 구성하는 작업을 하고 있었다. 그런데 Zotero에 item을 추가해도 어떤 논문은 PDF가 자동으로 붙지 않았다.
이 경우 지금까지는 사람이 직접 움직여야 했다.
기관 도서관 페이지에 로그인한다.
eJournal 메뉴에서 저널명을 검색한다.
구독 범위가 맞는 데이터베이스를 고른다.
출판사나 DB 페이지로 이동한다.
연도, 권, 호, 논문 페이지를 찾아간다.
PDF 버튼을 누른다.
내려받은 파일을 저장소와 Zotero 흐름에 맞게 정리한다.
한두 편이면 괜찮다. 문제는 이 일이 반복될 때다.
논문 후보를 찾고 읽는 일도 에너지가 드는데, 이후에 전문이 없는 논문의 PDF를 받는 것이 매우 귀찮다!!
그래서 이번 실험의 출발점은 이것이었다.
❓ Zotero에 PDF가 자동으로 붙지 않은 논문들을, AI 에이전트가 브라우저 제어를 통해 PDF를 다운받게 할 수는 없을까?
🛠️ 사용한 도구와 역할
Hermes: 여러 AI 프로필과 로컬 도구를 연결해 작업을 진행하는 에이전트 환경
Zotero: 논문 item과 첨부 PDF를 관리하는 문헌 관리 도구
pyzotero: Python에서 Zotero API를 다루기 위한 라이브러리. 이번 작업에서는 Zotero item의 현재 첨부 상태를 확인하고, 승인된 범위 안에서 내려받은 PDF를 linked-file attachment로 연결하는 데 사용했다.
keyring: Python에서 운영체제 보안 저장소의 비밀번호를 다루기 위한 라이브러리. 후반부에는 사용자가 매번 수동 입력하지 않아도 로그인을 진행할 수 있게 하는 후보 경로로 활용했다. 단, 비밀번호 값은 출력하거나 로그에 남기지 않는 방식으로 다뤘다.
브라우저 제어/CDP: Chrome을 제어해 로그인된 브라우저 세션을 이어받는 방식. CDP는 Chrome DevTools Protocol의 줄임말로, 브라우저 탭과 네트워크 응답을 프로그램에서 다루는 통로다.
작업 중 주요 원칙은 이것이었다.
⭐ 비밀번호, 쿠키, 세션 토큰, 다운로드용 임시 URL은 AI 로그나 문서에 남기지 않는다.
처음에는 에이전트에게 비밀번호를 알려주지 않고, 사용자가 브라우저에서 직접 로그인한 뒤 에이전트가 그 세션을 이어받는 방식을 썼다.
이후에는 Python의 keyring 라이브러리를 활용해 운영체제의 보안 저장소에서 비밀번호를 꺼내 쓰는 로그인 방식으로 진행했다.
🔧 작업 과정
1. 먼저 “PDF가 없는 논문”만 골랐다
필자의 옵시디언 볼트에는 Zotero 기반 메타데이터가 적힌 논문 요약노트들이 있었다. 이 노트들은 원래 PDF 요약과 연결되도록 설계되어 있었고, 메타데이터에도 PDF 경로 유무를 기록하도록 해두었다.
그래서 Hermes가 이를 기반으로 PDF가 없는 논문 목록을 고를 수 있었다.
실제 기록 기준으로는, 노트 frontmatter의 pdf_path, full_pdf_path가 비어 있는지 확인했고, 본문/태그에 pdf_missing, unresolved_pdf_path, PDF 없음 같은 누락 신호가 있는지도 봤다. 식별에는 citation key, DOI, PMID, Zotero key 같은 메타데이터를 함께 사용했다.
검증은 로컬/공유 저장소에 실제 PDF 파일이 있는지 다시 확인하는 방식이었다. 경로가 있고 파일도 있으면 다운로드 대상에서 제외했고, 경로는 있는데 파일이 없으면 attachment/path repair 대상으로 분류했다. 경로도 없고 누락 신호가 있으면 다운로드 queue로 보냈다.
2. 기관 도서관 경로의 공통 골격을 구성했다
수동 작업을 그대로 복원하면 이런 흐름이다.
도서관 로그인
→ eJournal 검색
→ 저널명 매칭
→ 구독 범위 확인
→ 출판사/DB outlink 이동
→ 논문 페이지 확인
→ PDF 다운로드
→ PDF 검증
→ 저장소에 PDF 저장출판사 DB마다 구성, PDF 다운로드 버튼 위치 등이 다양하므로 다음과 같이 나눠서 진행했다.
공통 skeleton: 로그인, eJournal 검색, coverage 확인, provider outlink 추출
provider recipe: 출판사/DB별 PDF 다운로드 방식에 대한 지침 저장
3. provider마다 PDF 버튼이 전부 달랐다
겉으로는 모두 “PDF 다운로드”지만, 실제 동작은 제각각이었다.
짧게 줄이면 이렇다.
provider 유형
에이전트가 관찰한 차이점
Springer 계열
기관 접근 표시와 Download PDF 링크가 비교적 직접적이었다.
Wiley 계열
처음 보이는 PDF 링크가 HTML 중간문일 수 있어, 실제 PDF 경로를 따로 찾아야 했다.
MDPI/PMC 비슷한 공개 접근 경로
직접 fetch는 실패해도 브라우저 경로로는 받을 수 있었다.
ScienceDirect 계열
추천 논문 묶음 다운로드와 목표 논문 PDF가 섞일 수 있어, 목표 PDF 응답만 골라야 했다.
LWW/Ovid 계열
Download → PDF → 경고 페이지 → Download content 같은 중간 단계가 있었다.
Provider 지침을 만드는 과정에서는 사용자가 중간에 직접 화면을 보고 PDF 다운로드 버튼이 어디 있는지 알려주거나, 해당 부분의 Element 정보를 복사해 전달하기도 했다. 이게 모든 문제를 바로 해결한 것은 아니지만, 에이전트가 어디를 다시 봐야 하는지 좁히는 데 힌트가 됐다.
결론은 단순했다.
하나의 만능 다운로드 스크립트보다,
공통 흐름 + provider별 작은 recipe가 현실적이다.4. 다운로드보다 중요한 것은 “검증 후 저장”이었다
초기 스크립트에서는 다운로드한 파일을 충분히 검증하기 전에 공유 저장소로 복사할 수 있는 구조였다.
이러면 실제 PDF가 아니라 HTML 오류 페이지나 로그인 페이지를 PDF처럼 저장할 위험이 있다.
그래서 검토를 거쳐 순서를 바꿨다.
다운로드 시도
→ PDF header 확인
→ 파일 크기 확인
→ content-type 확인
→ 논문 제목/DOI/페이지 등 target 확인
→ 그 다음 저장소로 복사그리고 저장할 때도 바로 덮어쓰지 않고, 임시 파일로 쓴 뒤 검증이 끝나면 rename하는 방식으로 바꿨다.
이 부분은 자동화에서 꽤 중요했다. “다운로드 버튼을 눌렀다”와 “올바른 PDF를 안전하게 저장했다”는 완전히 다른 일이었다.
파일을 저장할 때에는 이미 사용자가 쓰고 있는 논문 제목 정규화 규칙에 따라 저장하도록 했다.
5. Zotero 흐름까지 연결했다
PDF를 받는 것만으로는 일이 끝나지 않는다.
논문 관리 흐름에서는 PDF가 Zotero item과 연결되어야 하고, 노트의 PDF 경로도 갱신되어야 한다. 이때 Zotero 쪽 확인과 연결에는 pyzotero를 사용했다.
pyzotero는 Python에서 Zotero API를 호출할 수 있게 해주는 도구이다.
파일 제목이 정규화되어 있었기 때문에 그것을 기반으로 매칭할 서지 정보를 찾았고, 해당 서지 정보에 첨부파일 경로가 채워져 있는지 확인하고, 검증된 PDF를 linked-file attachment로 붙일 수 있었다.
그리고 연결만 하고 끝내지 않았다. Zotero Desktop에서 해당 item의 PDF 첨부를 더블클릭해 실제로 PDF가 열리는지도 확인했다. 이후 관련 노트의 메타데이터도 새로 고쳤다. 특히 첨부 PDF 유무를 다시 반영했다.
✅ 결과: 무엇이 달라졌나
이번 실험으로 완전한 범용 자동화가 끝난 것은 아니다. 하지만 업무의 시작점이 바뀌었다.
Before
PDF가 안 붙은 논문을 발견하면 사용자가 직접 움직였다.
도서관 로그인
→ eJournal 검색
→ 적당한 DB 선택
(가장 최근 날짜까지 지원하는 DB)
→ 출판사 화면에서 PDF 다운로드
→ 내려받은 PDF를 Zotero에 다시 끌어 다 붙이기After
이제는 에이전트가 위의 과정을 사람 대신 진행해준다. 표로 정리하면 다음과 같다.
결과물
의미
누락 PDF 점검 흐름
현재 PDF가 없는 후보만 추림
eJournal coverage 확인 흐름
도서관 페이지에 로그인해 구독 범위와 provider 후보를 확인
provider별 recipe 초안
Springer, Wiley, ScienceDirect, LWW/Ovid 등에서 관측된 다운로드 방식 축적
PDF 안전 검증
HTML 오류 페이지를 PDF처럼 저장하지 않도록 방지
Zotero linked-file backfill 흐름
받은 PDF를 Zotero item과 다시 연결
⚠️ 솔직한 한계
아직 완성된 제품은 아니다.
다른 DB에서도 추가 실험이 필요하다.
특히 ProQuest/EBSCO/Health & Medical Collection 계열
논문을 새로 검색해서 새로운 Zotero item을 만드는 단계는 이번 범위가 아니었다.
이번 작업은 이미 Zotero에 있는 item 중 PDF가 빠진 경우를 다뤘다.
keyring 라이브러리를 이용한 로그인 방식에 보안상 문제가 없을지 좀더 비밀번호 관리 방식에 대해 고민해야 함.
그래도 의미 있는 변화는 있었다.
“논문 PDF가 안 붙었으니 내가 직접 다시 찾아야 한다”에서 “에이전트가 누락 후보를 좁히고, provider별 경로를 실험해 검증된 PDF만 연결한다”로 업무 시작점이 바뀌었다.
🌍 다른 업무에 적용한다면
비슷한 구조의 업무라면 적용을 시도할 수 있겠다.
사이트에 로그인해야 한다.
검색 결과에서 정확한 항목을 골라야 한다.
외부 사이트마다 화면이 조금씩 다르다.
다운로드한 파일이 진짜 맞는지 검증해야 한다.
최종 파일을 정해진 저장소나 관리 도구에 연결해야 한다.
✏️ 앞으로 해야 할 것
글을 다 쓰고 드는 생각인데, 지금은 PDF를 다운로드하여 그걸 .md화 시켜서 LLM Wiki에 먹일 생각으로 있었다. 그런데 이미 open access로 볼 수 있는 논문이면 굳이 이런 뻘짓이 없었을지도 모르겠다는 생각이 들었다. 전문을 바로 볼 수 있는 논문이면, 그냥 그 페이지에서 text를 추출하도록 시켜봐야겠다.
다만 HTML 전문은 PDF와 문단 구조, 표, 그림 캡션, 참고문헌 형식이 다를 수 있으니 어떤 경우에 HTML을 raw로 삼고, 어떤 경우에 PDF를 기준으로 삼을지는 따로 정해야 한다.
그리고 다음 단계는 이것이다.
raw.md파일에 같이 넣으면 좋을 메타데이터 확정 (아마도 기본 zotero 정보와 better bibtex기반 키, 파일 경로 등)
raw 논문을 ingest하여 어떤 자료를 산출할지 고민하기
가장 간단한 것은 일단 AI 기반 요약노트가 될 듯