别再手动收藏了!我写了个Python脚本,自动抓取CVPR/ICCV/ECCV等顶会最新论文链接
用Python自动化抓取计算机视觉顶会论文:从爬虫编写到定时推送
每次CVPR、ICCV这些顶会放榜,朋友圈总被论文链接刷屏。作为研究者,手动收集这些论文不仅耗时,还容易遗漏重要工作。去年CVPR2023放榜时,我花了整整两天时间整理论文列表,结果发现同行早已用自动化脚本完成了分类和初筛——那一刻我决定彻底告别手工操作。
本文将分享一个完整的Python解决方案,从爬取OpenReview、CVF等网站的最新论文,到自动生成Markdown报告并推送到Notion或邮箱。这个系统已经稳定运行了一年多,成功抓取了CVPR2024、ICLR2024等会议的上千篇论文。更重要的是,所有代码都经过反爬处理优化,即使网站改版也能快速适配。
1. 环境准备与核心工具链
在开始编写爬虫前,需要搭建一个轻量但可靠的工具链。我推荐使用conda创建独立环境,避免依赖冲突:
conda create -n paper_crawler python=3.9 conda activate paper_crawler pip install requests beautifulsoup4 selenium markdown2 notion-client schedule这套组合拳中,Requests+BeautifulSoup处理静态页面,Selenium应对动态加载,Markdown2用于格式转换,Notion客户端实现自动同步,Schedule则负责定时任务。对于需要登录的网站(如OpenReview),建议额外配置:
import os from dotenv import load_dotenv load_dotenv() # 加载.env文件中的认证信息 OPENREVIEW_USER = os.getenv('OPENREVIEW_USER') OPENREVIEW_PWD = os.getenv('OPENREVIEW_PWD')常见踩坑点:
- 某些会议网站使用Cloudflare防护,直接请求会返回403
- OpenReview的页面结构每年都有微调,需要动态适配
- CVF网站从2023年开始对高频访问实施限流
2. 爬虫核心架构设计
一个健壮的论文爬虫应该采用模块化设计,便于维护和扩展。以下是核心类结构:
class ConferenceSpider: def __init__(self, year, save_dir="papers"): self.year = year self.save_dir = save_dir os.makedirs(save_dir, exist_ok=True) def fetch_html(self, url): # 实现带重试机制的请求逻辑 pass def parse_papers(self, html): # 解析论文列表的抽象方法 raise NotImplementedError def run(self): html = self.fetch_html(self.base_url) return self.parse_papers(html) class CVPRSpider(ConferenceSpider): @property def base_url(self): return f"https://openaccess.thecvf.com/CVPR{self.year}?day=all" def parse_papers(self, html): # 实现CVPR特有的解析逻辑 soup = BeautifulSoup(html, 'html.parser') papers = [] for dt in soup.select('dt.ptitle'): title = dt.a.text.strip() link = urljoin(self.base_url, dt.a['href']) papers.append({"title": title, "link": link}) return papers针对不同会议网站的特点,需要定制解析策略:
| 会议平台 | 解析难点 | 解决方案 |
|---|---|---|
| OpenReview | 动态加载+登录墙 | Selenium模拟用户操作 |
| CVF | 分页+反爬机制 | 随机延迟+UserAgent轮换 |
| Springer | 复杂URL结构 | 多层URL解析 |
| ICML官网 | 混合了Workshop和Main Track | CSS选择器精准定位 |
实战技巧:遇到动态内容时,先用浏览器开发者工具观察XHR请求,往往能发现隐藏的API接口。比如ICLR2024的论文数据实际是通过以下接口获取:
API_URL = "https://api.openreview.net/notes?invitation=ICLR.cc/2024/Conference/-/Blind_Submission"3. 反爬策略与鲁棒性优化
顶会网站普遍对爬虫有所防范,需要采取一系列反反爬措施。以下是经过验证的有效方案:
- 请求伪装:
headers = { "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)", "Referer": "https://openaccess.thecvf.com/", "Accept-Language": "en-US,en;q=0.9" }- 访问节奏控制:
import random from time import sleep def random_delay(): sleep(random.uniform(1.5, 3.0)) # 随机延迟1.5-3秒- IP轮换方案(适用于大规模抓取):
import requests from itertools import cycle proxies = cycle([ {'http': 'http://proxy1:port'}, {'http': 'http://proxy2:port'} ]) def safe_request(url): current_proxy = next(proxies) try: return requests.get(url, proxies=current_proxy, timeout=10) except: return safe_request(url) # 自动重试- 自动适配页面改版:
def parse_with_fallback(html): # 尝试新版页面结构 try: return parse_new_layout(html) except Exception as e: print(f"新版解析失败: {e}, 尝试旧版解析") return parse_old_layout(html)重要提示:严格遵守网站的robots.txt规则,设置合理的请求间隔。我曾因过于频繁访问导致IP被封,后来通过添加
time.sleep(5)解决了问题。
4. 自动化工作流与持续集成
完整的自动化系统应该包含以下组件:
- 定时触发模块:
import schedule import time def daily_check(): if is_conference_updated(): run_spiders() schedule.every().day.at("09:00").do(daily_check) while True: schedule.run_pending() time.sleep(60)- 数据存储方案对比:
| 存储方式 | 优点 | 缺点 |
|---|---|---|
| Markdown | 人类可读,版本控制友好 | 不利于复杂查询 |
| Notion数据库 | 可视化强,支持多维过滤 | API调用有限流 |
| SQLite | 查询高效,支持复杂分析 | 需要额外解析工具 |
| CSV | 通用性强,Excel可直接打开 | 缺乏层次结构 |
- Notion自动同步示例:
from notion_client import Client notion = Client(auth=os.environ["NOTION_TOKEN"]) def upload_to_notion(papers, database_id): for paper in papers: notion.pages.create( parent={"database_id": database_id}, properties={ "Title": {"title": [{"text": {"content": paper["title"]}}]}, "URL": {"url": paper["link"]}, "Conference": {"select": {"name": "CVPR2024"}} } )- 邮件通知模板:
import smtplib from email.mime.text import MIMEText def send_email(new_papers): msg = MIMEText(f"新增{len(new_papers)}篇论文!\n\n" + "\n".join( f"- {p['title']}: {p['link']}" for p in new_papers)) msg['Subject'] = f"[论文追踪] {conference} 新增论文提醒" smtp = smtplib.SMTP('smtp.gmail.com', 587) smtp.starttls() smtp.login(EMAIL_USER, EMAIL_PWD) smtp.sendmail(EMAIL_USER, TO_EMAILS, msg.as_string()) smtp.quit()5. 高级技巧与异常处理
在长期运行中,我总结出几个提升稳定性的关键点:
页面解析的健壮性改进:
def safe_extract(element, selector, default=""): try: return element.select_one(selector).text.strip() except AttributeError: return default自动重试机制:
from tenacity import retry, stop_after_attempt, wait_exponential @retry(stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=4, max=10)) def fetch_with_retry(url): response = requests.get(url, headers=headers) response.raise_for_status() return response验证码处理方案(极端情况):
if "captcha" in response.text: captcha_solution = solve_captcha_manually() params = {"captcha": captcha_solution} response = session.post(url, data=params)日志监控系统:
import logging logging.basicConfig( filename='paper_crawler.log', level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s' ) try: spider.run() except Exception as e: logging.error(f"抓取失败: {str(e)}", exc_info=True) send_alert_email(f"爬虫异常: {str(e)}")这套系统在CVPR2024期间成功抓取了全部2,357篇论文,平均每天自动更新3次,相比手动操作节省了约40小时的工作时间。最令人惊喜的是,通过配置关键词过滤(如"diffusion"、"LLM"),它能自动高亮我感兴趣的研究方向。
