Python: 批量爬取下载中国知网(CNKI) PDF论文

发布时间:2020-03-04 阅读 508

作者:左从江
邮箱:zuocj9700@163.com

Stata连享会   主页 || 视频 || 推文

连享会 - Stata 暑期班

线上直播 9 天:2020.7.28-8.7
主讲嘉宾:连玉君 (中山大学) | 江艇 (中国人民大学)
课程主页https://gitee.com/arlionn/PX | 微信版
助教招聘: 15 名,免费听课,详见课程主页


目录


这篇文章介绍获取 PDF 格式的论文。

在知网页面的 html 中有下载链接,复制到搜索栏,确实是可以下载论文的,只需要获得作者,时间,题目以及下载链接就可以用循环结构批量下载论文。

当然前提是,您本来就可以下载论文,不管是用 VPN 还是校园网。

爬取网页后,只需要解析出来即可。我选择的方法是 正则搜索,虽然有点笨拙,但好在不管是什么信息,只要想搜索,总可以搜索到。

1. 总体思路

首先,获取源码,库:selenium,time ,用 webdriver 搜索按钮和输入栏,提交等等,遇到验证码手动输入即可,笔者输入了 8 次验证码,获取 6000 条论文
其次,从源码中解析出作者,时间,Title,下载链接,储存到 Excel 中留存,日后可能有用,用到 re,pandas
再次,利用 pandas,读取论文的链接,Title,用 requests 获取论文,利用 open 函数储存到 PDF 格式,在实践中发现,如果直接用解析的链接获取,下载得到的往往是 caj 格式文件,但是把 url 中的 ';' 换为 '&' 就可以正常下载 PDF 格式的文件了。 用到 re,pandas
有了总的思路,相信各位也可以自己写出定制的爬虫

2. 解析前奏:获取页面的 html

  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
from selenium import webdriverimport timeimport pandas as pd
url = r'http://new.gb.oversea.cnki.net/kns/brief/result.aspx?dbprefix=CJFQ' #给出链接driver = webdriver.Firefox()driver.get(url)
blank_ISSN = driver.find_element_by_id('magazine_value1')#找到输入框。 id是我手动打开html,查看输入框源代码找到的,想提交别的条件一样操作即可
blank_ISSN.send_keys('0577-9154') #输入内容,期刊得SSN号码buttom_search = driver.find_element_by_id('btnSearch') #找到搜索按钮buttom_search.click() #点击搜索
time.sleep(2) #停一小会儿
driver.switch_to.default_content() #找到子页面driver.switch_to.frame('iframeResult') #切换到iframe
#选择50个论文在一面显示button_50=driver.find_element_by_xpath(r'/html/body/form/table/tbody/tr[1]/td/table/tbody/tr[1]/td/table/tbody/tr/td[2]/div[2]/a[3]')button_50.click()
htmls = [] #遍历所有子页面,储存到这个列表b = 1 #while True: try: soup = BeautifulSoup(driver.page_source,'html.parser') htmls.append(soup) #储存好,点击下一页 time.sleep(random.randint(3,6)) #暂停一小会儿,这样封IP的概率会小一点,也少输入几次验证码 button_next = driver.find_element_by_id('Page_next') button_next.click()
except : print('Error{}'.format(b)) time.sleep(60) b = b+1

3. 解析

一个 tr 标签的结构如下,其包含了一篇文章的全部信息:

在这里插入图片描述
在这里插入图片描述
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
transfer_list=[]   #存储html源码的中转列表for soups in htmls:    text = str(soups)    for i in soups.find_all('tr')[7:57]:   #在soup搜索出来的tr标签中,列表头尾都有冗余信息,删掉不要        transfer_list.append(i)
len(htmls) #看一下爬出来多少的html,我的结果是135个html页面
raw_paper_infos = [] #用re匹配的思路是,第一步先缩小范围,第二步,精确搜索并删除多余的字符,下面是第一步for i in transfer_list: #遍历transfer_list中的每一个tr标签,其结构:[[一个tr标签包含的源码],[].……] o=[] #中转列表,储存第一步搜索出来的title,authors,发布时间,下载链接四个大致的匹配结果 paper = str(i) #下面正则的表达式,都是我自己试出来的,有更好的方法欢迎留言 title = re.findall('target="_blank">.*</a>',paper) authors = re.findall('target="knet">.*</a>',paper) pub_year = re.findall('....-..-..',paper) download_url = re.findall('briefDl_D" href=".*PDFdown',paper) quoted_num1 = re.findall('scrollbars=yes.*</span',paper) download_num = re.findall('onclick="SubCountDownLoad.*</a>',paper) o=[title,authors,pub_year,download_url,quoted_num1,download_num] raw_paper_infos.append(o) #初步储存了全部的搜索信息

初步搜索出来的结果如下:

  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
raw_paper_infos[7]   #结构:[[trs],[],……][['target="_blank">消费行为在个人信用风险识别中的信息含量研究</a>'], ['target="knet">王正位</a>; <a class="KnowledgeNetLink" href="/kns/popup/knetsearchNew.aspx?sdb=CJFQ&sfield=%e4%bd%9c%e8%80%85&skey=%e5%91%a8%e4%bb%8e%e6%84%8f&scode=08239051%3b34827180%3b08822321%3b08186170%3b" target="knet">周从意</a>; <a class="KnowledgeNetLink" href="/kns/popup/knetsearchNew.aspx?sdb=CJFQ&sfield=%e4%bd%9c%e8%80%85&skey=%e5%bb%96%e7%90%86&scode=08239051%3b34827180%3b08822321%3b08186170%3b" target="knet">廖理</a>; <a class="KnowledgeNetLink" href="/kns/popup/knetsearchNew.aspx?sdb=CJFQ&sfield=%e4%bd%9c%e8%80%85&skey=%e5%bc%a0%e4%bc%9f%e5%bc%ba&scode=08239051%3b34827180%3b08822321%3b08186170%3b" target="knet">张伟强</a>'], ['2020-01-16'], ['briefDl_D" href="../download.aspx?filename=4kXaYNFW0VEa4UzTFZXdJVlSvB3cHdXWrU0cKZ0VXllatB3ZaZVeUdESlxEePJHV3clQuVneGNkQSRXSKdHMvklS6Vzbv9WVwQWaENTdXJ0aOpFd4FzUSRGd3okW0Z1dx90SGljM5JVRwczRTdnSVl3Z3ImMrlVM&tablename=CAPJLAST&dflag=PDFdown'], [], ['onclick="SubCountDownLoad(0,this)">264</a>']]

接下来继续完成匹配工作:精确匹配和删除多余字符:

  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
papers = []   #干净的匹配结果存放处ilegal_word = ['/','\',''',':','|','?','*']   #考虑到后续下载时,保存文件会有一些非法字符导致文件名生成失败(windows不允许这些字符出现在文件名中)for i in raw_paper_infos:    if not i == [[], [], [], [], [], []]:   #初步搜索时候,会有一些tr标签不是我们的论文标签,不符合初步搜索的要求,其结果就是空列表,过滤掉        raw_title = i[0][0].strip('target="_blank>~</a>')        chars = []        for x in raw_title:            if not x in ilegal_word:                chars.append(x)        title2 = ''.join(c for c in chars)        authors2 = ','.join(j for j in re.findall('[\u2E80-\u9FFF]+',str(i[1])))   #在join里面加一个符号就可以用这个符号链接加入进来的各个str了,nice try!        pub_year2 = i[2][0]        download_url2 = (i[3][0].strip('briefDl_D" href="..')).replace(';','&')   #按照';'连接就是caj格式的,'&'连接就是PDF格式的        if i[4] == []:            quoted_num2 = int(0)        else:            quoted_num2 = int(re.findall(r'>.*</a',str(i[4][0]))[0].strip('></a'))            #被引次数对于发表不久的论文,可能没有这一项,所以对于没有这一项的给0
download_num2 = int(re.findall(r'>.*<',i[5][0])[0].strip('><')) #论文得下载次数 papers.append([title2,authors2,pub_year2,download_url2,quoted_num2,download_num2])
#到此为止,我们有了全部的所需要的信息#储存到excel,以待候用pd.DataFrame(papers).to_excel(root+r'\JJYJ论文信息汇总.xlsx')

输出的 Excel 文档长这样:

:和代码部分有一点不一样,笔者自行输入了标题行,并且按照发表日期排序

在这里插入图片描述
在这里插入图片描述

注意: 下载链接不完整,下载时需要在前面加:http://new.gb.oversea.cnki.net/kns

4. 下载论文的代码

  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
  • ounter(line
import pandas as pdimport requests,os
content = pd.read_excel(content_JJYJ) #读取excelcontent = content.drop(columns = ['Unnamed: 0','作者','被引次数','下载次数','截止日期:2020-2-6',"要下载论文,链接前接:'http://new.gb.oversea.cnki.net/kns'"])#只保留title和下载链接,其余删掉
for i in range(len(content['题目'])): #这是DataFrame中列的访问方式 title = content['题目'][i] #第i篇论文的题目 text = requests.get(content['下载链接'][i]) #下载第i个论文 with open(root + '\\' + title + '.PDF' ,'wb') as f: #给出保存地址以及open的模式是wb,写入字节 #因为下载的是字节,所以写入字节:wb f.write(text.content) f.close()
size = float(os.path.getsize(save_path)) kb = size/1024 #判断是不是下载成功了,小于7字节应该就是没下载到论文而是别的东西 if kb<7: os.remove(save_path) #如果是,删除,以备后面重新下载 print('封IP了,暂停10min') exceptions.append(paper) time.sleep(300) #下载失败的原因是封ip了,这时候暂停5-10min比较好

下载论文的主体部分就是这些了,后面可以加入 try/except 结构、跳过已经下载的论文等功能,但是程序主体就是这些,文章已经很长,再长不大好,所以写到这里,更多功能请大家依据需求添加。

相关课程

连享会-直播课 上线了!
http://lianxh.duanshu.com

免费公开课:


课程一览

支持回看,所有课程可以随时购买观看。

专题 嘉宾 直播/回看视频
Stata暑期班 连玉君
江艇
线上直播 9 天
2020.7.28-8.7
效率分析-专题 连玉君
鲁晓东
张 宁
视频-TFP-SFA-DEA
已上线,3天
文本分析/爬虫 游万海
司继春
视频-文本分析与爬虫
已上线,4天
空间计量系列 范巧 空间全局模型, 空间权重矩阵
空间动态面板, 空间DID
研究设计 连玉君 我的特斯拉-实证研究设计-幻灯片-
面板模型 连玉君 动态面板模型-幻灯片-
直击面板数据模型 [免费公开课,2小时]

Note: 部分课程的资料,PPT 等可以前往 连享会-直播课 主页查看,下载。


关于我们

  • Stata连享会 由中山大学连玉君老师团队创办,定期分享实证分析经验。直播间 有很多视频课程,可以随时观看。
  • 连享会-主页知乎专栏,300+ 推文,实证分析不再抓狂。
  • 公众号推文分类: 计量专题 | 分类推文 | 资源工具。推文分成 内生性 | 空间计量 | 时序面板 | 结果输出 | 交乘调节 五类,主流方法介绍一目了然:DID, RDD, IV, GMM, FE, Probit 等。
  • 公众号关键词搜索/回复 功能已经上线。大家可以在公众号左下角点击键盘图标,输入简要关键词,以便快速呈现历史推文,获取工具软件和数据下载。常见关键词:
    • 课程, 直播, 视频, 客服, 模型设定, 研究设计, 暑期班
    • stata, plus,Profile, 手册, SJ, 外部命令, profile, mata, 绘图, 编程, 数据, 可视化
    • DID,RDD, PSM,IV,DID, DDD, 合成控制法,内生性, 事件研究, 交乘, 平方项, 缺失值, 离群值, 缩尾, R2, 乱码, 结果
    • Probit, Logit, tobit, MLE, GMM, DEA, Bootstrap, bs, MC, TFP, 面板, 直击面板数据, 动态面板, VAR, 生存分析, 分位数
    • 空间, 空间计量, 连老师, 直播, 爬虫, 文本, 正则, python
    • Markdown, Markdown幻灯片, marp, 工具, 软件, Sai2, gInk, Annotator, 手写批注, 盈余管理, 特斯拉, 甲壳虫, 论文重现, 易懂教程, 码云, 教程, 知乎

连享会主页  lianxh.cn
连享会主页 lianxh.cn

连享会小程序:扫一扫,看推文,看视频……


扫码加入连享会微信群,提问交流更方便

✏ 连享会学习群-常见问题解答汇总:
https://gitee.com/arlionn/WD