mdpi_search.py
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
MDPI 论文搜索脚本
"""
import argparse
import requests
from bs4 import BeautifulSoup
import json
def search_mdpi_papers(keyword, journal=None, max_results=10):
"""
搜索 MDPI 论文
Args:
keyword: 搜索关键词
journal: 期刊名称(可选)
max_results: 最大结果数
Returns:
论文列表
"""
try:
# 尝试访问搜索页面,使用更简单的请求头
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:120.0) Gecko/20100101 Firefox/120.0",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
"Accept-Language": "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2",
"Connection": "keep-alive",
"Upgrade-Insecure-Requests": "1",
"TE": "Trailers",
}
# 使用不同的搜索 URL 格式
if journal:
url = f"https://www.mdpi.com/search?term={keyword}&journal={journal}&pageCount={max_results}"
else:
url = f"https://www.mdpi.com/search?term={keyword}&pageCount={max_results}"
print(f"正在尝试访问: {url}")
# 使用会话来保持连接
session = requests.Session()
response = session.get(url, headers=headers, timeout=10)
response.raise_for_status()
print(f"响应状态: {response.status_code}")
print(f"响应内容长度: {len(response.text)}")
# 首先解析整个 HTML 以便备用方法使用
soup = BeautifulSoup(response.text, 'html.parser')
# 使用字符串搜索直接查找 __NUXT_DATA__
print("使用字符串搜索查找 __NUXT_DATA__")
start = response.text.find('id="__NUXT_DATA__">')
if start != -1:
start += len('id="__NUXT_DATA__">')
end = response.text.find('</script>', start)
if end != -1:
print("成功找到 __NUXT_DATA__ 内容")
try:
# 提取 JSON 数据
json_str = response.text[start:end]
data = json.loads(json_str)
print("JSON 数据解析成功")
# 查找 articles 信息
papers = []
def find_articles(obj):
if isinstance(obj, dict):
if 'articles' in obj:
return obj['articles']
for key in obj:
result = find_articles(obj[key])
if result:
return result
elif isinstance(obj, list):
for item in obj:
result = find_articles(item)
if result:
return result
return None
articles_list = find_articles(data)
if articles_list and isinstance(articles_list, list):
print(f"找到 {len(articles_list)} 篇文章")
for i, article in enumerate(articles_list):
if len(papers) >= max_results:
break
# 提取论文信息
paper_info = {}
# 提取标题
paper_info['title'] = article.get('title', 'No title')
# 提取作者信息
if 'authors' in article:
authors = []
for author in article['authors']:
if isinstance(author, dict) and 'name' in author:
authors.append(author['name'])
paper_info['authors'] = ', '.join(authors) if authors else 'No authors'
else:
paper_info['authors'] = 'No authors'
# 提取期刊信息
if 'journal' in article:
paper_info['pub_info'] = article['journal']
else:
paper_info['pub_info'] = 'No info'
# 提取链接
if 'identifier' in article:
paper_info['link'] = f"https://www.mdpi.com/10.3390/{article['identifier']}"
elif 'doi' in article:
paper_info['link'] = f"https://www.mdpi.com/{article['doi']}"
else:
paper_info['link'] = "No link"
papers.append(paper_info)
return papers
except Exception as e:
print(f"解析 JSON 数据失败: {e}")
print("尝试使用备用方法...")
else:
print("未找到 __NUXT_DATA__ 结束标签")
else:
print("未找到 __NUXT_DATA__ 开始标签")
# 如果无法解析 JSON 数据,使用备用方法
# 尝试查找所有包含 href 属性且包含 /article/ 或 /10.3390/ 的链接
papers = []
links = soup.find_all('a', href=True)
for link in links:
href = link['href']
# 检查是否是论文链接
if (('/article/' in href or '/10.3390/' in href) and
len(papers) < max_results):
# 尝试提取标题
title = link.text.strip()
# 检查是否有相邻的标题元素
parent = link.find_parent('div')
if parent:
h2 = parent.find('h2')
if h2:
title = h2.text.strip()
# 提取作者信息(如果可用)
authors = "No authors"
if parent:
author_elem = parent.find(class_='authors')
if not author_elem:
author_elem = parent.find('div', string=lambda text: 'by' in str(text))
if author_elem:
authors = author_elem.text.strip().replace('by', '').strip()
# 构建完整链接
if not href.startswith('http'):
href = f"https://www.mdpi.com{href}"
# 添加到结果列表
papers.append({
"title": title if title else "No title",
"link": href,
"authors": authors,
"pub_info": "No info"
})
# 去重结果
unique_papers = []
seen_links = set()
for paper in papers:
if paper['link'] not in seen_links:
seen_links.add(paper['link'])
unique_papers.append(paper)
# 限制结果数量
return unique_papers[:max_results]
except requests.exceptions.RequestException as e:
print(f"搜索失败: {e}")
return []
def main():
parser = argparse.ArgumentParser(description="搜索 MDPI 期刊论文")
parser.add_argument("keyword", help="搜索关键词")
parser.add_argument("--journal", help="特定期刊名称(可选)")
parser.add_argument("--max-results", type=int, default=10, help="最大结果数")
args = parser.parse_args()
print(f"搜索 MDPI 论文: {args.keyword}")
if args.journal:
print(f"期刊: {args.journal}")
papers = search_mdpi_papers(args.keyword, args.journal, args.max_results)
if papers:
print(f"\n找到 {len(papers)} 篇论文:\n")
for i, paper in enumerate(papers, 1):
print(f"{i}. {paper['title']}")
print(f" 作者: {paper['authors']}")
print(f" 信息: {paper['pub_info']}")
print(f" 链接: {paper['link']}")
print()
else:
print("未找到匹配的论文")
if __name__ == "__main__":
main()