写在前面
有的时候需要某个领域的所有论文数据,此时web of science数据库检索的论文结果可能动辄上万甚至几十万,然而网站限制单次导出条数为1000(如果需要引文字段则仅500,仅导出为txt可包含引用详细信息),需要导出几十上百次,手动做太费神,因此写一个爬虫脚本自动导出。
2022.1.6旧版web of science正式下线了,这里是对新版网站重新开发的自动化导出代码。
使用本代码需要:
- 国内大学学生账号(登录wos使用)
- 火狐浏览器
- python以及selenium包
- geckodriver 0.24.0 (与浏览器版本对应,放在爬虫代码同一个文件夹下)
严格来说本代码属于半自动化导出,考虑到开发效率等因素,有两处在首次导出时需要手动操作,后文细说。
遇到“selenium.common.exceptions.NoSuchElementException: Message: Unable to locate element: …”的报错首先排查网络问题,可以把对应代码行之前的浏览器等待时间加长。
正文
代码情况:
- 输入:wos检索结果网址、需要导出的条数、导出结果存储路径
- 输出:导出文件(格式自选,一般txt/excel)
1、需要导入的包,以及测试入口。
其中url是在完成wos检索之后的检索页面网址。
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import time
import os
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
if __name__=='__main__':
# WOS“检索结果”页面的网址
url = 'https://www.webofscience.com/wos/woscc/summary/64c4e5ff-832d-476d-8112-51e908a600b1-1d5405d5/relevance/1'
# 导出到本地的存储路径(自行修改)
download_path = '/Users/username/folder'
startdownload(url,80195, download_path,record_format='excel',reverse=False) # 主要函数
print('Done')
2、主要函数
两次手动操作:
- 首次打开wos必须登录, 在学校统一身份认证处需要手动输入信息并点击登录。(20220306更新:发现在有的电脑上用的时候并不需要登录…按需选择吧…不用登录的话把login函数注释掉就行);
- 第一次导出时需要手动修改文件处理方式为"保存文件", 并勾选"以后都采用相同动作处理此类文件"
输入参数见函数说明。
-
选择导出格式处给出了excel和txt两种,默认excel,可自选。
-
windows系统把flag变量初始值改为1。
def startdownload(url,record_num,SAVE_TO_DIRECTORY,record_format=‘excel’,reverse=False):
‘’'url -> 检索结果网址;record_num -> 需要导出的记录条数(检索结果数); SAVE_TO_DIRECTORY -> 记录导出存储路径(文件夹); reverse -> 是否设置检索结果降序排列, default=False ---------------------------------------------------- tip1:首次打开wos必须登录,在学校统一身份认证处需要手动输入验证码并点击登录; tip2:第一次导出时需要手动修改文件处理方式为"保存文件",并勾选"以后都采用相同动作处理此类文件" ''' # SAVE_TO_DIRECTORY = '/Users/chenzijing/Desktop/研/毕业论文/毕设研/代码/论文数据'#/firefox' fp = webdriver.FirefoxProfile() fp.set_preference('browser.download.dir', SAVE_TO_DIRECTORY) fp.set_preference("browser.download.folderList", 2) fp.set_preference("browser.download.manager.showWhenStarting", False) fp.set_preference("browser.helperApps.neverAsk.saveToDisk", "text/plain") browser = webdriver.Firefox(executable_path=r'geckodriver',firefox_profile=fp) browser.get(url) time.sleep(4) login(browser) browser.get(url) # 登陆后会跳转到首页,这里直接重新打开检索结果页面 time.sleep(5) # 获取需要导出的文献数量 # record_num = int(browser.find_element_by_css_selector('.brand-blue').text) # 按时间降序排列 if reverse: browser.find_element_by_css_selector('.top-toolbar wos-select:nth-child(1) button:nth-child(1) span:nth-child(2)').click() browser.find_element_by_css_selector("div.wrap-mode:nth-child(2) span:nth-child(1)").click() time.sleep(3) # 叉掉弹窗。网站弹窗时常会改,报错的话可以自己重新获取一下节点哦。 browser.find_element_by_css_selector('#onetrust-accept-btn-handler').click() time.sleep(1) browser.find_element_by_css_selector('#pendo-close-guide-ecbac349').click() # 开始导出 start = 1 # 起始记录 i = 0 # 导出记录的数字框id随导出次数递增 flag = 1 # mac文件夹默认有一个'.DS_Store'文件 while start<record_num: browser.find_element_by_css_selector('button.cdx-but-md:nth-child(2) span:nth-child(1)').click() # 导出 if record_format=='excel': browser.find_element_by_css_selector('#exportToExcelButton').click() # 选择导出格式为excel browser.find_element_by_css_selector('#radio3 label:nth-child(1) span:nth-child(1)').click() # 选择自定义记录条数 send_key(browser,'#mat-input-%d'%i,start)#mat-input-2 send_key(browser,'#mat-input-%d'%(i+1),start+999) browser.find_element_by_css_selector('.margin-top-5 button:nth-child(1)').click() # 更改导出字段 browser.find_element_by_css_selector('div.wrap-mode:nth-child(3) span:nth-child(1)').click() # 选择所需字段(excel:3完整/4自定义; txt:3完整/4完整+引文) browser.find_element_by_css_selector('div.flex-align:nth-child(3) button:nth-child(1)').click() # 点击导出 while len(os.listdir(SAVE_TO_DIRECTORY))==flag: time.sleep(1) # 等待下载完毕 # 导出文件按照包含的记录编号重命名 rename_file(SAVE_TO_DIRECTORY,'record-'+str(start)+'-'+str(start+999),record_format=record_format) start = start + 1000 else: browser.find_element_by_css_selector('#exportToFieldTaggedButton').click() # 选择导出格式为txt browser.find_element_by_css_selector('#radio3 label:nth-child(1) span:nth-child(1) span:nth-child(1)').click() # 选择自定义记录条数 send_key(browser,'#mat-input-%d'%i,start)#mat-input-2 send_key(browser,'#mat-input-%d'%(i+1),start+499) browser.find_element_by_css_selector('.margin-top-5 button:nth-child(1)').click() # 更改导出字段 browser.find_element_by_css_selector('div.wrap-mode:nth-child(4) span:nth-child(1)').click() # 选择所需字段(excel:3完整/4自定义; txt:3完整/4完整+引文) browser.find_element_by_css_selector('div.flex-align:nth-child(3) button:nth-child(1)').click() # 点击导出 while len(os.listdir(SAVE_TO_DIRECTORY))==flag: time.sleep(1) # 等待下载完毕 # 导出文件按照包含的记录编号重命名 rename_file(SAVE_TO_DIRECTORY,'record-'+str(start)+'-'+str(start+499),record_format=record_format) start = start + 500 i = i + 2 flag = flag + 1 time.sleep(10) browser.quit()
3、主要函数中调用的其他函数
login函数中“学校的统一身份验证”部分可以选择手动,或者根据学校网站自行修改。
其他无需修改。
def login(browser):
'''登录wos'''
# 通过CHINA CERNET Federation登录
browser.find_element_by_css_selector('.mat-select-arrow').click()
browser.find_element_by_css_selector('#mat-option-9 span:nth-child(1)').click()
browser.find_element_by_css_selector('button.wui-btn--login:nth-child(4) span:nth-child(1) span:nth-child(1)').click()
time.sleep(3)
login = browser.find_element_by_css_selector('#show')
login.send_keys('xxxx大学') # 改成你的学校名
time.sleep(0.5)
browser.find_element_by_css_selector('.dropdown-item strong:nth-child(1)').click()
browser.find_element_by_css_selector('#idpSkipButton').click()
time.sleep(1)
#! 跳转到学校的统一身份验证(想自动输入账号密码就把下面两行注释解除,按照自己学校的网址修改一下css选择器路径)
# browser.find_element_by_css_selector('input#un').send_keys('你的学号') # 改成你的学号/账号
# browser.find_element_by_css_selector('input#pd').send_keys('你的密码') # 改成你的密码
time.sleep(20) #! 手动输入账号、密码、验证码,点登录
def send_key(browser,path,value):
'''browser -> browser;
path -> css选择器;
value -> 填入值
'''
markto=browser.find_element_by_css_selector(path)
markto.clear()
markto.send_keys(value)
def rename_file(SAVE_TO_DIRECTORY,name,record_format='excel'):
'''导出文件重命名
SAVE_TO_DIRECTORY -> 导出记录存储位置(文件夹);
name -> 重命名为
'''
# files = list(filter(lambda x:'savedrecs' in x and len(x.split('.'))==2,os.listdir(SAVE_TO_DIRECTORY)))
while True:
files = list(filter(lambda x:'savedrecs' in x and len(x.split('.'))==2,os.listdir(SAVE_TO_DIRECTORY)))
if len(files)>0:
break
files = [os.path.join(SAVE_TO_DIRECTORY, f) for f in files] # add path to each file
files.sort(key=lambda x: os.path.getctime(x))
newest_file = files[-1]
# newest_file=os.path.join(SAVE_TO_DIRECTORY,'savedrecs.txt')
if record_format=='excel':
os.rename(newest_file, os.path.join(SAVE_TO_DIRECTORY, name+".xls"))
else:
os.rename(newest_file, os.path.join(SAVE_TO_DIRECTORY, name+".txt"))
4、导出结果
部分结果,展示导出形式。
5、写在最后
代码使用:
- 复制上面所有代码,修改其中的url、存储路径,并满足1、中的四条条件。
有不明白的地方欢迎私信交流,有错误也欢迎指出,大家共同进步呀。
(私信不太经常看,可能回复不及时,但看到一定会回复,见谅!)