1. 程式人生 > >python爬蟲 | 爬取開放伺服器的檔案

python爬蟲 | 爬取開放伺服器的檔案

1.任務背景

       現已提供資料檔案,其中兩個欄位是ftp連結,每一條資料有兩個連結,連結對應開放伺服器的檔案列表,該項任務主要把檔案列表中指定的壓縮包檔案下載下來。

資料如圖所示:

在瀏覽器中開啟對應的某個ftp連結,如下圖所示,目標是將其中紅框中的壓縮包下載下來,一個ftp下載一個,一條資料對應下載兩個壓縮包:

2.資料預處理

        由於python爬蟲的requests庫請求的url都是以http/https打頭,所有首先做的操作是將每個ftp連結字首轉換為http/https,程式碼如下:

def changePre(data):  #更換url字首為https
    hurlsGen=[]       #存放所有轉換完成的Gen FTP連結
    hurlsRef=[]       #存放所有轉換完成的Ref FTP連結
    i=0
    while i<len(data):  #迴圈遍歷所有資料進行轉換
        data=data.astype(str)
        furlGen = data['GenBank FTP'][i].strip()[3:]
        furlRef = data['RefSeq FTP'][i].strip()[3:]
        hurlGen = 'https' + furlGen+'/'
        hurlRef = 'https' + furlRef+'/'
        hurlsGen.append(hurlGen)
        hurlsRef.append(hurlRef)
        i+=1
    return hurlsGen,hurlsRef

3.得到每條轉換後的url對應的HTML程式碼

def getHTMLText(url, code="utf-8"):   #得到轉換後的每條url對應的HTML程式碼
    try:
        r = requests.get(url)
        r.raise_for_status()
        r.encoding = code
        return r.text
    except:
        return ""

4.分析網頁原始碼

如上圖所示,可以發現程式碼非常簡單,所有檔案連結都在a標籤中。

5.解析HTML程式碼,提取指定下載檔案的檔名。

def parseHTMLText(html):   #解析網頁原始碼,提取指定下載檔案的檔名
    doc=pq(html)           #用pyquery提取a標籤
    a=doc('a')              
    filename='RNG'         #預設檔名為RNG
    for item in a.items():    #遍歷所有提取的a標籤,根據href屬性值,找到指定的下載檔案的檔名
        if 'protein.gpff.gz' in item.attr('href'): 
            filename=item.attr('href')
            print(filename)
    return filename

6.提取待下載的檔案,並寫在本地資料夾中

def writeFile(basicUrl,filename,filepath,count): 
        filepath1='{0}/{1}'.format(filepath,str(count)+'_'+filename)#本地寫入路徑
        if not os.path.exists(filepath1):
            with open(filepath1,'wb') as f:
                file=requests.get(basicUrl+filename) #指定檔案的下載連結
                if file.status_code==200:            #可能有的連結不含指定檔案 此時會生成一個空檔案,檔名為:序號_RNG
                    f.write(file.content)

7.全部程式碼:

#-*- coding:utf-8 -*-
import requests
import os
from pyquery import PyQuery as pq
import pandas as pd
from multiprocessing import Pool


def getHTMLText(url, code="utf-8"):   #得到轉換後的每條url對應的HTML程式碼
    try:
        r = requests.get(url)
        r.raise_for_status()
        r.encoding = code
        return r.text
    except:
        return ""

def parseHTMLText(html):   #解析網頁原始碼,提取指定下載檔案的檔名
    doc=pq(html)           #用pyquery提取a標籤
    a=doc('a')              
    filename='RNG'         #預設檔名為RNG
    for item in a.items():    #遍歷所有提取的a標籤,根據href屬性值,找到指定的下載檔案的檔名
        if 'protein.gpff.gz' in item.attr('href'): 
            filename=item.attr('href')
            print(filename)
    return filename


def writeFile(basicUrl,filename,filepath,count): 
        filepath1='{0}/{1}'.format(filepath,str(count)+'_'+filename)#本地寫入路徑
        if not os.path.exists(filepath1):
            with open(filepath1,'wb') as f:
                file=requests.get(basicUrl+filename) #指定檔案的下載連結
                if file.status_code==200:            #可能有的連結不含指定檔案 此時會生成一個空檔案,檔名為:序號_RNG
                    f.write(file.content)
               


def changePre(data):  #更換url字首為https
    hurlsGen=[]       #存放所有轉換完成的Gen FTP連結
    hurlsRef=[]       #存放所有轉換完成的Ref FTP連結
    i=0
    while i<len(data):  #迴圈遍歷所有資料進行轉換
        data=data.astype(str)
        furlGen = data['GenBank FTP'][i].strip()[3:]
        furlRef = data['RefSeq FTP'][i].strip()[3:]
        hurlGen = 'https' + furlGen+'/'
        hurlRef = 'https' + furlRef+'/'
        hurlsGen.append(hurlGen)
        hurlsRef.append(hurlRef)
        i+=1
    return hurlsGen,hurlsRef

def Write(urls,title):
    count=1
    for url in urls:
        if not os.path.exists(title):
            os.mkdir(title)
        html = getHTMLText(url)
        #print(html)
        filename = parseHTMLText(html)
        filepath = title
        writeFile(url, filename, filepath,count)
        count+=1


hurlsGen=[]
hurlsReq=[]
def main():
    data=pd.read_csv('prokaryotes.csv')
    #data=data.head()
    hurlsGen,hurlsReq=changePre(data)
    #hurlsGen=["https://ftp.ncbi.nlm.nih.gov/genomes/all/GCA/000/504/085/GCA_000504085.1_ASM50408v1"]
    Write(hurlsGen,'Gen')    
    Write(hurlsReq,'Req')

if __name__=='__main__':
    main()

















8.問題:

        資料檔案總共有1w多條資料,對應2w多條連結,發現利用上述方式下載檔案的速度很慢。不知道是網路原因,還是程式碼本身有問題...費解...