在做學術、搞科研的過程中,我們往往需要針對一個特定的主題下載海量的文獻。在把幾百篇文獻下載到電腦的過程中,假如遇到不夠友好的數據庫不提供批量下載的功能,怎么辦?我恰好遇到了這樣的批量下載的科研任務和批量下載功能受限的數據庫網站……
做了幾天,覺得有點無聊……這個時候,我們多希望自己的瀏覽器可以變得聰明一點,幫我們完成這個無聊又機械的過程。如何讓瀏覽器替我們搬磚呢?萬能的谷歌給我找到了一篇教程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("http://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("http://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基礎不扎實改編個現成的代碼都顯得吃力,嗯……我需要提高的地方還有很多。希望這篇文章能夠幫到同在學術半道上的你。