python+selenium批量爬取IEEExplore論文
原文出處:https://blog.csdn.net/qq_25072387/article/details/78588173
一、環境搭建
首先下載安裝selenium包,推薦直接使用pip
之後還要下載對應瀏覽器的驅動(driver),這裡使用的是chrome瀏覽器,注意驅動與瀏覽器的版本要相對應。下載的驅動直接複製到python和chrome的安裝目錄下。
python+selenium的環境搭建教程很多,這裡不做贅述。
二、觀察一下
我們以:
http://ieeexplore.ieee.org/search/searchresult.jsp?reload=true&queryText=SLAM&ranges=2014_2018_Year&sortType=desc_p_Citation_Count
為目標頁面,爬取其中pdf。
手動下載的話,點選pdf圖示就可以進入下載頁面。
我們先隨便進入一個下載頁面,暗中觀察:
發現這個url後面有一串奇怪的引數,這個引數值和檔名一樣。再回到上一頁,右鍵→檢查元素:
發現這篇文章的pdf的圖示是一個a標籤,標籤裡也有這串數字。
再觀察一下其他論文,發現它們的下載頁面url只是替換了這個引數,而url的前半部分都是相同的:
'http://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber='
也就是說,這個引數是論文的一個編號,只要拿到每篇論文的這個編號,再和以上字串拼接,就能得到下載頁面的url。
而每篇論文的pdf圖示a標籤裡,就有一個data-artnum屬性,屬性值就是我們要的論文編號。
那麼只要爬出每個data-artnum的值就行了
三、ok,開始爬蟲
我們在編輯器裡寫下這樣的程式碼:
from selenium import webdriver import time
browser = webdriver.Chrome() # 驅動chrome
url = “http://ieeexplore.ieee.org/search/searchresult.jsp?queryText=SLAM&ranges=2014_2018_Year&sortType=desc_p_Citation_Count
browser.get(url) # 跳轉到目標頁面
time.sleep(5) #象徵性地等一下
link_list = browser.find_elements_by_xpath("//*[@data-artnum]") #使用selenium的xpath定位到每個具有data-artnum元素
for link in link_list:
ele_num = link.get_attribute(‘data-artnum’)
print(ele_num)
執行一下,chrome自動啟動並跳轉到了ieeexplore,控制檯也打出了一堆數字:
誒,不對啊,怎麼每個編號都重複了一次,而且只爬出了10個編號,第一頁明明有25篇論文呢。
再去目標頁面檢查一下元素:
原來pdf圖示前面還有個html圖示,裡面也有data-artnum屬性,爬蟲的時候把html圖示的這個屬性也給爬進來了。
這個問題解決起來很容易,我們只要在結果中做一下去重,或者加一些其他的判別條件,不爬html圖示就好了。
那什麼會少15篇論文呢?
觀察了一下滾動條,終於發現
滾動條向下滾動的時候,變短了!
這就說明,後面的論文是一邊滾動一邊動態載入的,也就是採用的“懶載入”的方式。
我們用selenium開啟頁面後,沒有去做拖動滾動條的操作,後面的論文當然不會載入啦。
要解決這個問題,也很簡單,我們可以在頁面開啟後,在time.sleep的時間裡手動把滾動條滾動到底。
當然不推薦這麼做,要是我爬60頁,每重新整理一次頁面,都要自己滾來滾去的,那也太傻了。我們還是用selenium執行js操作來控制滾動條。
在程式碼中加上這麼幾句(加在開啟頁面後和使用xpath定位之前):
time.sleep(5) js = 'window.scrollTo(0, document.body.scrollHeight);' browser.execute_script(js) time.sleep(5) browser.execute_script(js)這裡要執行兩次滾動操作,第一次滾動加載出20條內容,第二次滾動加載出全部25條。
這次就沒問題了,已經能跑出第一頁的所有論文的編號了。
有了編號還要下載,於是稍微修改一下程式碼,變成這樣:
# -*- coding: utf-8 -*- import requests from bs4 import BeautifulSoup from selenium import webdriver import time
# 執行函式
def work(browser,url):
browser.get(url)
ele_nums = []
time.sleep(<span style="color:#6897bb;">10</span>)
js = <span style="color:#008080;">'window.scrollTo(0, document.body.scrollHeight);'
browser.execute_script(js)
time.sleep(5)
browser.execute_script(js)
<span style="color:#cc7832;"><strong>try</strong></span>:
<span style="color:#cc7832;"><strong>for </strong></span>link <span style="color:#cc7832;"><strong>in </strong></span>browser.find_elements_by_xpath(<span style="color:#008080;">"//*[@data-artnum]"</span>):
<span style="color:#cc7832;"><strong>if </strong></span>isContainClass(link.get_attribute(<span style="color:#008080;">'className'</span>)<span style="color:#cc7832;">,</span><span style="color:#008080;">'icon-pdf'</span>):
ele_num = link.get_attribute(<span style="color:#008080;">'data-artnum'</span>)
ele_nums.append(ele_num)
<span style="color:#cc7832;"><strong>return </strong></span>ele_nums
<span style="color:#cc7832;"><strong>except</strong></span>:
<span style="color:#8888c6;">print</span>(<span style="color:#008080;">"failure"</span>)
#用於判斷某元素是否具有某class
def isContainClass(allClass,targetClass):
#解析allClass,判斷是否包含targetClass
classArr = allClass.split(’ ')
result = False
for str in classArr:
if str == targetClass:
result = True
break
return result
def getHtml(url):
# Mozilla/5.0 (Windows NT 10.0; WOW64; rv:57.0) Gecko/20100101 Firefox/57.0
headers = {‘user-agent’: ‘Mozilla/5.0 (Windows NT 10.0; WOW64; rv:57.0) Gecko/20100101 Firefox/57.0’}
try:
response = requests.get(url,timeout=40,headers=headers)
response.raise_for_status()
response.encoding = response.apparent_encoding
<span style="color:#cc7832;"><strong>return </strong></span>response.text
<span style="color:#cc7832;"><strong>except</strong></span>:
<span style="color:#cc7832;"><strong>import </strong></span>traceback
traceback.print_exc()
def getSoup(html):
soup = BeautifulSoup(html,‘html.parser’)
print(soup.body.find_all(‘a’,attrs={‘class’:r’icon-pdf’}))
def downloadPaper(url):
try:
soup = BeautifulSoup(getHtml(url), ‘html.parser’)
result = soup.body.find_all(‘iframe’)
downloadUrl = result[-<span style="color:#6897bb;">1</span>].attrs[<span style="color:#008080;">'src'</span>].split(<span style="color:#008080;">'?'</span>)[<span style="color:#6897bb;">0</span>]
headers = {<span style="color:#008080;">'user-agent'</span>: <span style="color:#008080;">'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:57.0) Gecko/20100101 Firefox/57.0'</span>}
response = requests.get(downloadUrl<span style="color:#cc7832;">, </span><span style="color:#aa4926;">timeout</span>=<span style="color:#6897bb;">80</span><span style="color:#cc7832;">, </span><span style="color:#aa4926;">headers</span>=headers)
fname = downloadUrl[-<span style="color:#6897bb;">12</span>:]
<span style="color:#8888c6;">print</span>(fname)
<span style="color:#cc7832;"><strong>with </strong></span><span style="color:#8888c6;">open</span>(fname<span style="color:#cc7832;">,</span><span style="color:#008080;">'ab+'</span>) <span style="color:#cc7832;"><strong>as </strong></span>f:
<span style="color:#8888c6;">print</span>(<span style="color:#008080;">'start download file '</span><span style="color:#cc7832;">,</span>fname)
f.write(response.content)
<span style="color:#cc7832;"><strong>except</strong></span>:
<span style="color:#cc7832;"><strong>import </strong></span>traceback
<span style="color:#cc7832;"><strong>with </strong></span><span style="color:#8888c6;">open</span>(<span style="color:#008080;">'errorLog'</span><span style="color:#cc7832;">,</span><span style="color:#008080;">'ab+'</span>) <span style="color:#cc7832;"><strong>as </strong></span>f:
traceback.print_exc(<span style="color:#aa4926;">file</span>=f)
if name == ‘main’:
url = <span style="color:#008080;">'http://ieeexplore.ieee.org/search/searchresult.jsp'</span>+\
<span style="color:#008080;">'?queryText=SLAM&ranges=2014_2018_Year&sortType=desc_p_Citation_Count'
baseUrl = ‘http://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=’
maxPageNumber = 3
browser = webdriver.Chrome()
<span style="color:#cc7832;"><strong>if </strong></span>maxPageNumber >= <span style="color:#6897bb;">1</span>:
eleNums = work(browser<span style="color:#cc7832;">,</span>url)
eleNums = <span style="color:#8888c6;">list</span>(<span style="color:#8888c6;">set</span>(eleNums))
<span style="color:#cc7832;"><strong>for </strong></span>eleNum <span style="color:#cc7832;"><strong>in </strong></span>eleNums:
newUrl = baseUrl+<span style="color:#8888c6;">str</span>(eleNum)
downloadPaper(newUrl)
<span style="color:#cc7832;"><strong>else</strong></span>:
<span style="color:#cc7832;"><strong>for </strong></span>i <span style="color:#cc7832;"><strong>in </strong></span><span style="color:#8888c6;">range</span>(<span style="color:#6897bb;">2</span><span style="color:#cc7832;">,</span>maxPageNumber+<span style="color:#6897bb;">1</span>):
url = url+<span style="color:#008080;">'&pageNumber='</span>+<span style="color:#8888c6;">str</span>(i)
eleNums = work(browser<span style="color:#cc7832;">,</span>url)
eleNums = <span style="color:#8888c6;">list</span>(<span style="color:#8888c6;">set</span>(eleNums))
<span style="color:#cc7832;"><strong>for </strong></span>eleNum <span style="color:#cc7832;"><strong>in </strong></span>eleNums:
newUrl = baseUrl + <span style="color:#8888c6;">str</span>(eleNum)
downloadPaper(newUrl)
就可以爬取指定頁數的論文編號,並下載了!