批量抓取網頁pdf檔案

justchenhao發表於2019-02-16

任務:批量抓取網頁pdf檔案

有一個excel,裡面有數千條指向pdf下載連結的網頁地址,現在,需要批量抓取這些網頁地址中的pdf檔案。
python環境:

anaconda3
openpyxl
beautifulsoup4

讀取excel,獲取網頁地址

使用openpyxl庫,讀取.xslx檔案;
(曾嘗試使用xlrd庫讀取.xsl檔案,但無法獲取超連結)

  1. 安裝openpyxl

    pip install openpyxl
  2. 提取xslx檔案中的超連結

    示例檔案構造

公告日期 證券程式碼 公告標題
2018-04-20 603999.SH 讀者傳媒:2017年年度報告
2018-04-28 603998.SH 方盛製藥:2017年年度報告
def  readxlsx(path):
    workbook = openpyxl.load_workbook(path)
    Data_sheet = workbook.get_sheet_by_name(`sheet1`)
    rowNum = Data_sheet.max_row #讀取最大行數
    c =  3  # 第三列是所需要提取的資料
    server =  `http://news.windin.com/ns/`
    for  row  in  range(1, rowNum  +  1):
        link = Data_sheet.cell(row=row, column=c).value
        url = re.split(r`"`, link)[1]
        print(url)
        downEachPdf(url, server)

獲取網頁pdf下載地址

進入讀者傳媒:2017年年度報告,在chrome瀏覽器中可以按F12檢視網頁原始碼,以下擷取部分原始碼:

<div class="box4"><div style=`float:left;width:40px;background-color:#ffffff;`>附件:</div>  <div style=float:left;width:660px;background-color:#f3f3f3;`>  <a href=[getatt.php?id=91785868&att_id=32276645](http://news.windin.com/ns/getatt.php?id=91785868&att_id=32276645) class=`big` title=603999讀者傳媒2017年年度報告.pdf>603999讀者傳媒2017年年度報告.pdf </a>&nbsp;&nbsp; (2.00M) &nbsp;&nbsp</div></div>

可見,herf下載連結在a標籤中,可以通過解析html原始碼獲取下載連結。
這裡使用BeautifulSoup解析html。

Beautiful Soup 是用Python寫的一個HTML/XML的解析器,它可以很好的處理不規範標記並生成剖析樹(parse tree)。 它提供簡單又常用的導航(navigating),搜尋以及修改剖析樹的操作。它可以大大節省你的程式設計時間。

  1. 安裝BeautifulSoup4
pip install beautifulsoup4
  1. 獲取pdf下載連結並下載
def  downEachPdf(target, server):
    req = requests.get(url=target)
    html = req.text
    bf = BeautifulSoup(html, features="lxml")
    a = bf.find_all(`a`)
    for each in a:
        url = server + each.get(`href`)
        print("downloading:", each.string, url)
        urllib.request.urlretrieve(url, `./report/` + each.string)

同一ip重複訪問同一伺服器被拒絕

利用以上方法已經能夠實現批量網頁pdf的下載了,但是,在實際操作過程中,會發現如果同一ip頻繁地訪問某一伺服器,訪問會被拒絕(可能被誤判為DOS攻擊,通常做了Rate-limit的網站都會停止響應一段時間,你可以Catch這個Exception,sleep一段時間,參考)。因此,對下載邏輯進行了調整。
利用try-catch,具體邏輯是:正常情況下,按次序下載檔案,如果同一檔案,下載失敗次數超過10,則跳過,下載下一個檔案,並記錄錯誤資訊。

import os
import time
def  downloadXml(flag_exists, file_dir, file_name, xml_url):
    if  not flag_exists:
        os.makedirs(file_dir)
        local = os.path.join(file_dir, file_name)
    try:
        urllib.request.urlretrieve(xml_url, local)
    except  Exception  as e:
        print(`the first error: `, e)
        cur_try =  0
        total_try =  10
        if cur_try < total_try:
            cur_try +=  1
            time.sleep(15)
            return downloadXml(flag_exists, file_dir, file_name, xml_url)
    else:
        print(`the last error: `)
        with  open(test_dir +  `error_url.txt`, `a`) as f:
            f.write(xml_url)
        raise  Exception(e)

相關文章