在做学术、搞科研的过程中,我们往往需要针对一个特定的主题下载海量的文献。在把几百篇文献下载到电脑的过程中,假如遇到不够友好的数据库不提供批量下载的功能,怎么办?我恰好遇到了这样的批量下载的科研任务和批量下载功能受限的数据库网站……
做了几天,觉得有点无聊……这个时候,我们多希望自己的浏览器可以变得聪明一点,帮我们完成这个无聊又机械的过程。如何让浏览器替我们搬砖呢?万能的谷歌给我找到了一篇教程python 批量下载知网(CNKI)论文,嗯,使用python+selenium,就把浏览器调教成我们想要的样子,让它自动帮我们下文献。感谢前人提供巨人的肩膀!在这篇文章、以及这篇文章作者提供的代码的基础上,通过学习和改造,就可以将其适用于外文数据库。这里以Chrome浏览器和SpringLink数据库为例子进行说明。
一、需求分析
搞科研很重要的一步就是找文献,其中最基础的工作是先在特定主题词下找到文献。那我们需要浏览器做的事情就清楚了,就是帮我们下文献,特别是海量的文献。
二、流程分析
我们知道,在输入主题词后,下载文献的过程重重复复就是那几个步骤:
- 点击下载按钮;
- 开始下载,下载完成;
- 回到列表页面;
- 点击下一个文献,继续下载;
- 完成这一个页面的下载流程后,点击下一页,重复上述过程。
这么简单的流程,为啥不能交给电脑呢?点击下载按钮,实质上就是打开下载链接,那么我们可以将上述过程简化为两步:
- 获取所有下载链接;
- 分别点击每一个下载链接进行下载。
三、编程实现
1、Python
编程需要选择一种编程语言,这里我选择的语言是简单、容易上手的Python,本文所有代码均为Python。关于Python的安装、使用和语法规则可以参考廖雪峰的Python教程;运行环境我用的是jupytor notebook,关于这个可以参考Jupyter Notebook介绍、安装及使用教程。这里都不再进行赘述了,因为我也不怎么懂……
2、Selenium
在开始编程之前,我们需要先了解一个能够自动控制浏览器的工具——Selenium。Selenium是一个用于Web应用程序测试的工具,直接运行在浏览器中,就像真正的用户在操作一样。(引自:Selenium百度百科)
安装和启动,我觉得比较好的、能用的参考资料是selenium webdriver 启动三大浏览器Firefox,Chrome,IE、Python爬虫环境常用库安装等。注意一定要根据自己的浏览器下载浏览器驱动,我用的是Chrome浏览器,需要先看好自己的自己浏览器的版本,具体方法是在导航栏输入chrome://version/,我的版本是70.0.3538。
之后进入http://chromedriver.storage.googleapis.com/index.html下载最近版本的chromedriver(selenium webdriver 启动三大浏览器Firefox,Chrome,IE这篇文章里的下载链接失效了)。
在解压、安装完成后,需要把这个.exe放到python的lib文件夹,我的文件夹路径是:F:\SOFTWARE\Anaconda3\Library\bin。之后,使用如下代码测试是否Selenuim能用。
from selenium import webdriver
driver = webdriver.Chrome()
driver.get("http://www.baidu.com")
3、网站分析
这里以SpringerLink数据库为例进行说明。批量下载文献的工作本质上属于爬虫,在进行爬虫之前,我们首先需要分析起点网页和目标网站的结构(这里需要有HTML的知识基础,可以参考w3school的HTML 教程)。对于我这种半吊子编程选手,当然是希望涉及到编程的部分越少越好,所以我选择的起始页是输入关键词、约束好条件之后的页面。在进入数据库,输入关键词higher education,选择学科为education,选择时间为2018-2019之后,得到了文章开头的那张图,嗯,3430篇文献数据,恰好你有某项科研任务要把它们都下下来,网站还不提供批量下载的按钮。嗯,感觉…还可行。我们把这个页面的链接https://link.springer.com/search?just-selected-from-overlay-value=%22Education%22&date-facet-mode=between&just-selected-from-overlay=facet-discipline&facet-start-year=2018&facet-discipline=%22Education%22&facet-end-year=2019&facet-content-type=%22Article%22&query=higher+education复制下来。
接下来,分析网站结构。我们发现,在SpringerLink数据库中,只要有权限,点击Download PDF就可以下载。那么我们只要把这些链接获取到,就可以实现批量下载。
一般按F12可以进入浏览器的开发者工具,选取这个元素,发现还真是。
之后,我们选取“下一页”的元素。
4、阅读文档
在Selenium中文文档中,我们可以看到要实现我们的想法,需要什么命令。主要用的部分列举如下:
1)等待页面加载完成
等待页面加载完成(Waits)可以分为显式等待和隐式等待。显式等待就像我们等网页加载好再操作一样,浏览器等待网页加载完再进行操作。
#显式等待
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
driver = webdriver.Firefox()
driver.get("http://somedomain/url_that_delays_loading")
try:
element = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, "myDynamicElement"))
)
finally:
driver.quit()
2)查找元素
经过分析,本次编程使用到的元素主要是<a>,css选择器主要是class和id,那么可以通过xpath、class_name、id_name、css_selector等方式查找元素。代码如下:
driver.find_element_by_xpath("//form[@id='loginForm']")
driver.find_elements(By.XPATH, '//button')
driver.find_element_by_class_name('content')
driver.find_element_by_id('loginForm')
driver.find_element_by_css_selector('p.content')
3)点击效果
要实现点击效果,只需要在查找的元素之后,加上.click()。
#例如
driver.find_element_by_xpath("//form[@id='loginForm']").click()
5、编程过程
首先,是要引进我们用到的库。
import os
from time import sleep
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
按照我们设计的流程编写程序的主干部分,涉及到具体函数先编个名字取代。
if __name__ == "__main__":
#1、初始化
browser = browser_init(True)
openPage(browser)
paper_downloadLinks = []
#2、翻页,批量选取链接
pageNum = 10
curPage = 1
while curPage < pageNum:
switchNextPage(browser)
get_download_page(browser,paper_downloadLinks)
print("第%d页"% curPage)
curPage += 1
browser.quit()
print("采集了%d条数据"% len(paper_downloadLinks))
#3、下载
driver=browser_init(False)
fail_downLoadUrl=[]
do_download(driver,paper_downloadLinks,fail_downLoadUrl)
具体函数如下:
def browser_init(isWait):
options = webdriver.ChromeOptions()
prefs = {
'profile.default_content_settings_popups': 0,
'download.default_directory': 'F:/desktop_data/元分析文献数据/wiley'
}
options.add_experimental_option('prefs', prefs)
browser = webdriver.Chrome()
if isWait:
browser.implicitly_wait(10)
return browser
def openPage(browser):
browser.get("https://link.springer.com/search?just-selected-from-overlay-value=%22Education%22&date-facet-mode=between&just-selected-from-overlay=facet-discipline&facet-start-year=2018&query=high+education&facet-discipline=%22Education%22&facet-end-year=2019&facet-content-type=%22Article%22")
def get_download_page(browser, paper_downloadLinks):
for link in browser.find_elements_by_css_selector('a[href^=\/content\/pdf]'):
dlink=link.get_attribute('href')
url = dlink
paper_downloadLinks.append(url)
def switchNextPage(browser):
browser.find_element(By.XPATH, '//a[@class="next"]').click()
def do_download(driver,urls,fail_downLoadUrl):
for url in urls:
print(url)
try:
sleep(5)
driver.get(url)
print("download success")
except Exception as e:
print("download fail")
fail_downLoadUrl.append(url)
四、结果
嗯,写好代码之后,就该干嘛干嘛,让Chrome自动帮你下载文献吧,中间可以打把游戏什么的(逃)。python基础不扎实改编个现成的代码都显得吃力,嗯……我需要提高的地方还有很多。希望这篇文章能够帮到同在学术半道上的你。