当前位置: 首页 > news >正文

Python爬虫实战:爬取论文期刊 文献整理+管理表生成

写论文的时候最烦什么?不是写内容,是找文献和整理文献。相信每个研究生都有过这样的经历:打开十几个浏览器标签页,一篇一篇复制论文标题、作者、期刊、发表时间、摘要,然后粘贴到Excel里,一不小心还会复制错格式,或者漏掉重要信息。等整理完几十篇文献,半天时间就没了,眼睛也花了,手也酸了。

我上周就遇到了这个问题,导师让我写一篇关于工业视觉在制造业应用的综述,需要至少100篇中英文文献。一开始我老老实实地手动整理,整理了20篇就崩溃了。这哪是搞科研,这是纯体力劳动啊。作为一个写了十年代码的老程序员,我怎么能忍受这种低效的工作方式?于是我花了一个晚上,写了一个Python爬虫,自动爬取论文信息并生成标准化的文献管理表。

现在我把这个过程分享出来,希望能帮到同样被文献整理折磨的同学们。

整体流程设计

先给大家看一下整个爬虫的工作流程,这样大家心里有个底。

输入关键词/期刊名

构造搜索URL

发送HTTP请求获取页面

是否需要处理反爬?

添加请求头/使用代理/延迟请求

解析HTML提取论文信息

是否有下一页?

获取下一页URL

数据清洗与格式化

生成Excel文献管理表

可选:自动下载PDF

这个流程很清晰,从输入关键词到最终生成Excel表,全程自动化。我会一步步拆解每个环节,重点讲我遇到的坑和解决方案。

技术选型

我没有用什么复杂的框架,就用了最基础也最实用的几个库:

  • requests:发送HTTP请求,获取网页内容
  • BeautifulSoup4:解析HTML,提取论文信息
  • pandas:数据处理和生成Excel文件
  • selenium:处理动态加载的页面(有些网站用JavaScript渲染)
  • fake_useragent:生成随机User-Agent,绕过简单的反爬
  • time:添加请求延迟,避免被封IP

这些库都是Python爬虫的标配,安装也很简单,一条pip命令就能搞定。

目标网站分析

我主要爬取了三个网站:中国知网(CNKI)、IEEE Xplore和ScienceDirect。这三个网站基本覆盖了大部分中英文文献。

每个网站的结构都不一样,需要分别分析。我先从最简单的IEEE Xplore开始讲,因为它的反爬措施相对宽松,HTML结构也比较清晰。

IEEE Xplore分析

IEEE Xplore的搜索URL格式很规范:

https://ieeexplore.ieee.org/search/searchresult.jsp?newsearch=true&queryText=关键词&pageNumber=页码

比如搜索"industrial vision",第一页的URL就是:

https://ieeexplore.ieee.org/search/searchresult.jsp?newsearch=true&queryText=industrial%20vision&pageNumber=1

每篇论文的信息都在一个class为"List-results-items"的div标签里。我们需要提取的信息包括:

  • 论文标题
  • 作者列表
  • 期刊/会议名称
  • 发表年份
  • 摘要
  • 论文链接
  • DOI号

我写了一个简单的函数来提取这些信息:

defextract_ieee_paper_info(paper_div):paper_info={}# 提取标题title_tag=paper_div.find('h3',class_='text-md-md-lh')iftitle_tag:paper_info['title']=title_tag.get_text(strip=True)link_tag=title_tag.find('a')iflink_tag:paper_info['link']='https://ieeexplore.ieee.org'+link_tag['href']# 从链接中提取DOIdoi_part=link_tag['href'].split('/')[-2:]paper_info['doi']='/'.join(doi_part)# 提取作者authors_tag=paper_div.find('div',class_='authors')ifauthors_tag:authors=[author.get_text(strip=True)forauthorinauthors_tag.find_all('span')]paper_info['authors']=', '.join(authors)# 提取期刊和年份pub_info_tag=paper_div.find('div',class_='publisher-info-container')ifpub_info_tag:pub_text=pub_info_tag.get_text(strip=True)# 提取年份importre year_match=re.search(r'\b(20\d{2}|19\d{2})\b',pub_text)ifyear_match:paper_info['year']=year_match.group(1)# 提取期刊名journal_match=re.search(r'\| (.*?) \|',pub_text)ifjournal_match:paper_info['journal']=journal_match.group(1)# 提取摘要abstract_tag=paper_div.find('div',class_='abstract-text')ifabstract_tag:paper_info['abstract']=abstract_tag.get_text(strip=True)returnpaper_info

这个函数看起来简单,但我调试了半个多小时。因为IEEE的HTML结构经常会有一些小变化,比如class名称可能会多一个空格,或者某些标签的嵌套方式会改变。我一开始用了太具体的选择器,结果一运行就报错。后来我改成了更通用的选择器,并且加了很多if判断,确保即使某个字段提取失败,整个程序也不会崩溃。

中国知网(CNKI)分析

知网就麻烦多了。首先,它的反爬措施非常严格,直接用requests请求会返回403错误。其次,它的页面是动态加载的,很多内容都是通过JavaScript渲染的。最后,它的HTML结构非常混乱,到处都是嵌套的div和table,提取信息非常困难。

我一开始尝试用requests直接请求,结果不管怎么改请求头,都返回403。后来我查了一下,发现知网会检查请求的Cookie和Referer,而且还会验证User-Agent。更坑的是,知网的Cookie是动态生成的,每次访问都会变化。

没办法,我只能用selenium来模拟浏览器访问。这样虽然速度慢一点,但至少能绕过大部分反爬措施。

fromseleniumimportwebdriverfromselenium.webdriver.chrome.optionsimportOptionsfromselenium.webdriver.common.byimportByfromselenium.webdriver.support.uiimportWebDriverWaitfromselenium.webdriver.supportimportexpected_conditionsasEC# 配置Chrome选项chrome_options=Options()chrome_options.add_argument('--headless')# 无头模式,不显示浏览器窗口chrome_options.add_argument('--disable-gpu')chrome_options.add_argument('--no-sandbox')chrome_options.add_argument(f'user-agent={UserAgent().random}')# 启动浏览器driver=webdriver.Chrome(options=chrome_options)# 访问知网搜索页面driver.get('https://kns.cnki.net/kns8s/defaultresult/index')# 等待搜索框加载完成search_box=WebDriverWait(driver,10).until(EC.presence_of_element_located((By.ID,'txt_search')))# 输入关键词并搜索search_box.send_keys('工业视觉')search_button=driver.find_element(By.ID,'btn_search')search_button.click()# 等待搜索结果加载完成WebDriverWait(driver,10).until(EC.presence_of_element_located((By.CLASS_NAME,'result-table-list')))

用selenium打开页面后,提取信息就相对简单了。知网的搜索结果是一个table,每一行对应一篇论文。我们可以通过XPath来提取每一行的信息。

这里有个坑:知网的表格里有很多空列和隐藏列,而且有些字段的位置会变化。比如,有些论文有"基金"字段,有些没有,这就导致作者、期刊、年份等字段的列索引不固定。

我一开始用了固定的列索引,结果提取出来的信息全乱了。后来我改成了先获取表头,然后根据表头的文字来确定每个字段的列索引,这样就稳定多了。

# 获取表头headers=[]header_cells=driver.find_elements(By.XPATH,'//table[@class="result-table-list"]/thead/tr/th')forcellinheader_cells:headers.append(cell.text.strip())# 获取所有论文行paper_rows=driver.find_elements(By.XPATH,'//table[@class="result-table-list"]/tbody/tr')# 提取每篇论文的信息papers=[]forrowinpaper_rows:paper_info={}cells=row.find_elements(By.TAG_NAME,'td')fori,headerinenumerate(headers):ifi>=len(cells):continuecell_text=cells[i].text.strip()ifheader=='题名':paper_info['title']=cell_text# 提取链接link_tag=cells[i].find_element(By.TAG_NAME,'a')paper_info['link']=link_tag.get_attribute('href')elifheader=='作者':paper_info['authors']=cell_textelifheader=='来源':paper_info['journal']=cell_textelifheader=='发表时间':paper_info['year']=cell_text.split('-')[0]elifheader=='摘要':paper_info['abstract']=cell_textelifheader=='DOI':paper_info['doi']=cell_text papers.append(paper_info)

反爬处理

爬取学术网站最头疼的就是反爬。这些网站都不希望被爬虫大量访问,因为会占用他们的服务器资源。我在爬取过程中遇到了各种反爬措施,也总结了一些应对方法。

请求头伪装

这是最基本的反爬措施。网站会检查请求的User-Agent,如果发现是爬虫的User-Agent,就会拒绝访问。我们可以用fake_useragent库来生成随机的User-Agent,模拟不同的浏览器。

fromfake_useragentimportUserAgent headers={'User-Agent':UserAgent().random,'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,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','Accept-Encoding':'gzip, deflate','Connection':'keep-alive','Upgrade-Insecure-Requests':'1',}

请求延迟

如果我们的爬虫请求速度太快,网站很容易检测到异常。我们可以在每次请求之间添加一个随机的延迟,模拟人类的浏览行为。

importtimeimportrandom# 每次请求延迟1-3秒time.sleep(random.uniform(1,3))

我一开始用了0.5秒的延迟,结果爬了不到10页就被知网封了IP,两个小时后才解封。后来我改成了1-3秒的随机延迟,就再也没被封过。

使用代理IP

如果你的爬虫需要爬取大量数据,或者需要频繁访问某个网站,最好使用代理IP。这样即使某个IP被封了,你还可以切换到其他IP继续爬取。

我用的是免费的代理IP池,虽然稳定性差一点,但对于个人使用来说足够了。你也可以购买付费的代理IP服务,稳定性会好很多。

importrequests# 获取代理IPdefget_proxy():try:response=requests.get('http://localhost:5010/get/')ifresponse.status_code==200:proxy=response.json()return{'http':f'http://{proxy["proxy"]}','https':f'http://{proxy["proxy"]}'}except:returnNone# 使用代理发送请求proxy=get_proxy()ifproxy:response=requests.get(url,headers=headers,proxies=proxy,timeout=10)else:response=requests.get(url,headers=headers,timeout=10)

处理验证码

有些网站在检测到异常访问时,会弹出验证码。这时候我们就需要处理验证码了。

对于简单的数字字母验证码,我们可以用pytesseract库来识别。对于复杂的验证码,比如滑动验证码、点选验证码,就需要用更复杂的方法,比如机器学习或者打码平台。

我在爬取知网的时候遇到过一次验证码,后来我增加了请求延迟,就再也没遇到过了。所以,最好的处理验证码的方法就是避免触发验证码。

数据清洗与格式化

爬取到的原始数据往往有很多问题,比如:

  • 标题前后有多余的空格和换行
  • 作者列表格式不统一
  • 摘要里有多余的空白字符
  • 有些字段缺失

我们需要对这些数据进行清洗和格式化,确保生成的Excel表整洁规范。

importpandasaspd# 将数据转换为DataFramedf=pd.DataFrame(papers)# 去除所有字段前后的空格和换行df=df.applymap(lambdax:x.strip()ifisinstance(x,str)elsex)# 处理缺失值df['authors']=df['authors'].fillna('未知作者')df['journal']=df['journal'].fillna('未知期刊')df['year']=df['year'].fillna('未知年份')df['abstract']=df['abstract'].fillna('无摘要')df['doi']=df['doi'].fillna('无DOI')# 统一作者列表格式df['authors']=df['authors'].str.replace(';',', ')# 按发表年份降序排序df['year']=pd.to_numeric(df['year'],errors='coerce')df=df.sort_values(by='year',ascending=False)# 重置索引df=df.reset_index(drop=True)

生成文献管理表

数据清洗完成后,我们就可以生成Excel文献管理表了。我用pandas的to_excel方法来生成Excel文件,并且设置了一些格式,让表格看起来更美观。

# 创建ExcelWriter对象writer=pd.ExcelWriter('文献管理表.xlsx',engine='openpyxl')# 将DataFrame写入Exceldf.to_excel(writer,sheet_name='文献列表',index=False)# 获取工作表workbook=writer.book worksheet=writer.sheets['文献列表']# 设置列宽column_widths={'A':50,# 标题'B':40,# 作者'C':30,# 期刊'D':10,# 年份'E':100,# 摘要'F':50,# 链接'G':30# DOI}forcolumn,widthincolumn_widths.items():worksheet.column_dimensions[column].width=width# 设置自动换行fromopenpyxl.stylesimportAlignmentforrowinworksheet.iter_rows():forcellinrow:cell.alignment=Alignment(wrap_text=True,vertical='top')# 保存文件writer.close()

生成的Excel表包含了我们需要的所有字段,而且格式整齐,直接就可以用来写论文了。我还在表格里加了一个"阅读状态"列和一个"笔记"列,方便我后续管理文献。

进阶功能:自动下载PDF

既然都写了爬虫,不如再进一步,自动下载论文的PDF文件。这样就不用一篇一篇手动下载了。

IEEE Xplore的PDF下载链接很有规律,就是在论文链接后面加上"/pdf"。比如:

论文链接:https://ieeexplore.ieee.org/document/12345678 PDF链接:https://ieeexplore.ieee.org/document/12345678/pdf

知网的PDF下载链接就复杂多了,需要从论文详情页提取。而且知网的PDF下载需要登录账号,所以我们需要先在selenium里登录知网,然后再下载。

我写了一个简单的函数来下载PDF:

defdownload_pdf(pdf_url,save_path,headers=None):try:response=requests.get(pdf_url,headers=headers,stream=True)ifresponse.status_code==200:withopen(save_path,'wb')asf:forchunkinresponse.iter_content(chunk_size=1024):ifchunk:f.write(chunk)print(f"下载成功:{save_path}")returnTrueelse:print(f"下载失败,状态码:{response.status_code}")returnFalseexceptExceptionase:print(f"下载出错:{e}")returnFalse

这里有个注意事项:下载PDF的时候一定要用stream=True,这样可以边下载边写入文件,避免占用太多内存。

踩坑记录

整个开发过程中,我踩了无数的坑,这里挑几个印象最深的讲一下。

第一个坑是知网的反爬。我一开始用requests直接请求,结果怎么都返回403。我改了请求头,加了Cookie,甚至用了代理,都没用。后来才发现,知网会检查请求的TLS指纹,requests的TLS指纹和真实浏览器的不一样,所以会被识别出来。没办法,我只能改用selenium。

第二个坑是动态加载的内容。有些网站的搜索结果不是一次性加载完的,而是当你滚动到页面底部时,才会加载下一页的内容。这时候用requests就只能获取到第一页的内容。我一开始不知道,爬了半天只爬了20篇论文,还以为是我的代码有问题。后来我用浏览器的开发者工具看了一下网络请求,才发现是动态加载的。解决方法是用selenium模拟滚动页面,或者找到AJAX请求的URL直接请求。

第三个坑是编码问题。有些网站的页面编码不是UTF-8,而是GBK或者GB2312。如果我们直接用response.text来获取页面内容,就会出现乱码。解决方法是先检查response.encoding,如果不是UTF-8,就手动设置正确的编码。

response=requests.get(url,headers=headers)ifresponse.encoding=='ISO-8859-1':response.encoding=response.apparent_encoding html=response.text

第四个坑是网站结构变化。我写好爬虫的第二天,IEEE Xplore就更新了他们的网站,class名称全变了,我的爬虫直接就不能用了。我只能重新分析HTML结构,修改代码。这也是为什么我在代码里加了很多if判断,就是为了应对网站结构的小变化。

写在最后

这个爬虫虽然功能简单,但确实帮了我大忙。原来需要半天时间的工作,现在几分钟就搞定了。我用它爬了150多篇中英文文献,生成了一个完整的文献管理表,大大提高了我的工作效率。

当然,这个爬虫还有很多可以改进的地方。比如,可以增加多线程爬取,提高爬取速度;可以增加更多的网站支持,比如万方、SpringerLink等;可以增加自动生成参考文献格式的功能,支持GB/T 7714、APA、MLA等多种格式。

不过,对于我目前的需求来说,这个爬虫已经足够用了。如果你有类似的需求,可以参考我的代码,根据自己的需要进行修改。

需要提醒大家的是,爬虫只是一个工具,我们要合理使用它。不要爬取敏感信息,不要对网站造成过大的压力。爬取学术文献的时候,最好控制好请求速度,避免被封IP。

最后,祝大家都能顺利完成自己的论文!

http://www.jsqmd.com/news/873842/

相关文章:

  • Claude不是在模仿人,是在重构认知:3个被忽略的递归反思协议(附企业级调优checklist)
  • 5个技巧让你用Python零成本获取A股专业数据
  • Python、BMA-Stacking融合LightGBM、GBDT、KNN多模型电商交易欺诈风险预警研究|附代码数据
  • Apple ID身份协商协议全解析:rO/scnt/m动态参数生成原理
  • 三亚夜市哪家最有特色 - 资讯纵览
  • pycryptodome导入失败的四大底层原因与诊断方案
  • 非球面高精加高精密恒温恒湿空调机组选哪家 - 资讯纵览
  • 清远厂房搬家公司哪家专业靠谱?TOP5收费标准与避坑指南 - 从来都是英雄出少年
  • PostgreSQL 性能优化:从 3 秒到 30 毫秒,我做了这 5 件事
  • Meta裁了8000人,员工拖着行李箱抢可乐
  • 满帮季报图解:营收28亿,净利10亿 派息8750万美元
  • 碳化硅衬底与器件:怎么分辨有真产能的原厂和贸易商
  • eVTOL 结构件供应商,怎么从 480 万家工厂里找到真产能
  • 计算机组成原理 期末复习知识点总结
  • MoE稀疏激活原理与工程落地实战
  • Dell服务器数据恢复实战:RAID故障诊断与只读抢救指南
  • 无监督跌倒检测:基于IMU时序建模的异常识别工程实践
  • Windows电脑自带软件全部无法使用?亲测有效的解决办法!
  • 2026廊坊奢侈品回收哪家靠谱?本地TOP1核心优选:典典佳汇联盟 - 诚鑫名品
  • 强化学习工业落地五篇核心论文实战解析
  • 5分钟搞定Windows 11安卓应用安装:WSA Toolbox完全指南
  • PCB 厂遍地,真能做高阶 HDI 与 IC 载板的没几家
  • Mythos如何实现大模型在漏洞挖掘中的因果推理跃迁
  • 2026年人形机器人灵巧手行业报告:产业链与市场空间|附100+报告、数据合集下载
  • 清远厂房搬家收费标准 靠谱搬厂公司怎么选?2026 全攻略 - 从来都是英雄出少年
  • 工业级房价预测实战:从数据清洗到可解释模型部署
  • 广州花都驾校哪个值得信赖 - 资讯纵览
  • 【AI入门知识点】告别繁琐配置!Claude Code + DeepSeek 直连方案打造最强 VSCode 编程助手
  • Burp Suite安全部署:可审计、可复现的标准化实践
  • Dell服务器数据恢复:RAID拓扑识别与无损镜像实战指南