Python爬蟲批量下載文獻


最近在看NeurIPS的文章,但是一篇篇下載太繁瑣,希望能快速批量下載下來。
於是想到了之前一直聽說的python爬蟲,初次學着弄一下。
參考了python爬蟲入門教程:http://c.biancheng.net/view/2011.html ;
用到了requestsBeautifulSoupurllib.request
先放最終運行的程序:

結果程序

import requests
import pandas as pd
from bs4 import BeautifulSoup
from urllib.request import urlretrieve
import os

BASE_URL = 'https://proceedings.neurips.cc/'


# 打開網站並下載
def openAndDownload(url, title):
    str_subhtml = requests.get(url)
    soup1 = BeautifulSoup(str_subhtml.text, 'lxml')
    subdata = soup1.select('body > div.container-fluid > div > div > a:nth-child(4)')
    # print('subdata:', subdata)
    downloadUrl = BASE_URL + subdata[0].get('href')
    print(downloadUrl)
    getFile(downloadUrl, title)


# 下載文件
def getFile(url, title):
    title = replaceIllegalStr(title)
    filename = title + '.pdf'
    urlretrieve(url, './essay/%s' % filename.split('/')[-1])
    print("Sucessful to download " + title)


# 替換非法命名字符
def replaceIllegalStr(str):
    str = str.replace(':', '')
    str = str.replace('?', '')
    str = str.replace('/', '')
    str = str.replace('\\', '')
    return str


def main():
    url = 'https://proceedings.neurips.cc/paper/2020'
    strhtml = requests.get(url)
    soup = BeautifulSoup(strhtml.text, 'lxml')
    data = soup.select('body > div.container-fluid > div > ul > li > a')

    list = []
    for item in data:
        list.append([item.get_text(), item.get('href')])

    name = ['title', 'link']
    test = pd.DataFrame(columns=name, data=list)
    print(test)
    test.to_csv('./essayList.csv')
    # 檢查是否下載過
    file_dir = os.path.join(os.getcwd(), 'essay')
    downloaded_list = []
    for root, dirs, files in os.walk(file_dir):
        downloaded_list = files

    for et, el in zip(test[name[0]], test[name[1]]):
        essay_url = BASE_URL + el
        checkname = et + '.pdf'
        checkname = replaceIllegalStr(checkname)
        if (checkname in downloaded_list):
            print(checkname + ' has been downloaded! ')
        else:
            openAndDownload(essay_url, et)


if __name__ == '__main__':
    main()

結果:

對於NeurIPS網頁的文獻批量下載編程

1. 對網頁進行分析

目標是從NeurIPS2020會議的列表下載論文,2020年會議文章地址:https://proceedings.neurips.cc/paper/2020
首先分析網頁構成:打開網頁后按F12調出開發者界面,可以看到網頁的源碼。
把鼠標放到右側Elements代碼里不同位置,左側會有不同的控件高亮,以此找到一篇文章的所在位置,如下圖所示

python中,使用BeautifulSoup來打開網頁

Beautiful Soup 是 python 的一個庫,其最主要的功能是從網頁中抓取數據。Beautiful Soup 目前已經被移植到 bs4 庫中,也就是說在導入 Beautiful Soup 時需要先安裝 bs4 庫。安裝好 bs4 庫以后,還需安裝 lxml 庫。盡管 Beautiful Soup 既支持 Python 標准庫中的 HTML 解析器又支持一些第三方解析器 lxml 庫具有功能更加強大、速度更快的特點。
首先,HTML 文檔將被轉換成 Unicode 編碼格式,然后 Beautiful Soup 選擇最合適的解析器來解析這段文檔,此處指定 lxml 解析器進行解析。解析后便將復雜的 HTML 文檔轉換成樹形結構,並且每個節點都是 Python 對象。這里將解析后的文檔存儲到新建的變量 soup 中

import requests  
from bs4 import BeautifulSoup

url = 'https://proceedings.neurips.cc/paper/2020'
strhtml = requests.get(url)
soup = BeautifulSoup(strhtml.text, 'lxml')
print(soup)

結果:

可以看到文獻都是以某種列表的格式整齊排列。
通過BeautifulSoupselect函數將相關字段選出,select函數所需路徑從開發者界面中使用Copy selector復制得到,如圖所示:

復制得

body > div.container-fluid > div > ul > li:nth-child(1) > a

其中li:nth-child(1),表示某一項。要獲取整個列,只選li,代碼結果如下:

data = soup.select('body > div.container-fluid > div > ul > li > a')
print(data)

結果:

可以看到,每一個元素里面,有文章的名字和鏈接,正好是我們需要的。
文章名在標簽< a >中,使用get_text()獲取;鏈接在< a >標簽的href屬性中,使用get('href')獲取。
將其全部提出來並保存為csv格式,以便之后查詢使用。

list = []
for item in data:
    list.append([item.get_text(), item.get('href')])

name = ['title', 'link']
test = pd.DataFrame(columns=name, data=list)
test.to_csv('./essaylist.csv')

結果:

2. 單個文件下載

由於這個界面的超鏈接並不是文件的下載鏈接,打開后而是文章的詳情頁面:

可以從這個頁面爬出所需要的信息如摘要等,但目前我們只想下載paper,因此用與前文相同的Copy selector的方式選出文件下載地址的路徑:


得到

body > div.container-fluid > div > div > a:nth-child(4)

此時不再需要去除nth-child(4),因為我們只需要這一項。獲得了鏈接后還得與網站主地址組合起來形成完整的地址:

essay_url = 'https://proceedings.neurips.cc/' + test['link'][0]
str_subhtml = requests.get(essay_url)
soup1 = BeautifulSoup(str_subhtml.text, 'lxml')
subdata = soup1.select('body > div.container-fluid > div > div > a:nth-child(4)')
downloadUrl = 'https://proceedings.neurips.cc/' + subdata[0].get('href')  # 拼接成完整url
print(downloadUrl)

結果:

接下來通過urlretrieve進行下載操作。

filename = test['title'][0] + '.pdf'  # 補全文件格式
urlretrieve(downloadUrl, './%s' % filename.split('/')[-1])
print("Sucessful to download: " + test['title'][0])

即可下載成功:

3. 全部文件下載與改錯

全部文件的下載加個循環即可,具體如最前面的結果程序所示。

另外在運行過程中發現了一些問題:

  1. 文件命名問題
    下載過程中某些文件名只有前面幾個單詞,且文件不完整。
    經過觀察發現,出錯的是文章名字帶有':' , '?' , '\' 或 '/' 的,這些是文件命名所不允許的字符,因此在程序中將這些字符替換掉。
  2. 下載重復
    文章實在有點多,一次可能下不完(或者有更高效的批量下載方式)。
    於是修改了程序,通過遍歷本地文件獲得下載了的文獻列表,使用checkname in downloaded_list的方式判斷文獻是否已經下載過,避免重復下載。
    具體實現如最前面的結果程序所示。

待補充與改進

初次寫爬蟲,也許多了一些不必要的工作,下載方式和顯示方式也還有待優化。
后面可以更有針對性的下載,如:根據文章關鍵詞進行篩選后下載。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM