1. 程式人生 > >網頁請求data引數構造及巧用js指令碼製作簡易爬取進度

網頁請求data引數構造及巧用js指令碼製作簡易爬取進度

  小爬最近隨著對python中字串、json等理解進一步加深,發現先前我隨筆中提到的data構造和傳參方法略複雜,原本有更簡單的方法,Mark如下。

先前小爬我使用的requests.post請求中data構造的程式碼如下:

data_search={
    'page':1,
    'rows':15,
    'condition':
    """[\
        {"column":"BPM_DEF_NAME","exp":"like","value":""},\
        {"column":"DELETE_STATUS","exp":"=","value":0},\
        {"column":"TO_CHAR(TO_DATE(CREATE_DATE,'YYYY-MM-DD HH24:MI:SS'),'YYYY-MM-DD')","exp":">=","value":"YYYY-MM-DD"},\
        {"column":"TO_CHAR(TO_DATE(CREATE_DATE,'YYYY-MM-DD HH24:MI:SS'),'YYYY-MM-DD')","exp":"<=","value":"YYYY-MM-DD"},\
        {"column":"CHECK_TYPE","exp":"like","value":"2"},\
        {"column":"LOCKED_STATUS","exp":"=","value":0},\
        {"column":"DELETE_STATUS","orderType":"default","orderKey":"","direction":"ASC"}\
    ]"""
, #考慮到該欄位已經有單引號、雙引號,所以只能用三引號來包住這部分代表字串 'additionalParams':'{}' } data_search_condition=json.loads(data_search['condition']) #將字串轉為列表,方便更新列表(列表中每個元素都是一個單個字典)元素 #重新整理字典 data_search_condition[0]['value']=businessName data_search_condition[2]['value']=str(startDate) data_search_condition[3]['value
']=str(endDate) data_search['condition']=json.dumps(data_search_condition) #將列表重新轉回字串,作為data_search字典中鍵“condition”對應的“value”,然後更新字典

  該方法主要通過json的dumps、loads方法來完成“字串→字典列表→列表或字典值更新→字典、列表轉回str字串”,程式碼複雜且可讀性差。

後細想下,上面的程式碼中紅色部分(即data_search['condition']對應值)看上去,既有單引號、雙引號、也有三引號,但其作為整體,本質上就是三引號包著的字串,所以原則上它可以使用字串的傳參方法來載入變數,於是程式碼可以改為:

data_search={
    'page':1,
    'rows':15,
    'condition':
    """[\
        {"column":"BPM_DEF_NAME","exp":"like","value":"%s"},\
        {"column":"DELETE_STATUS","exp":"=","value":0},\
        {"column":"TO_CHAR(TO_DATE(CREATE_DATE,'YYYY-MM-DD HH24:MI:SS'),'YYYY-MM-DD')","exp":">=","value":"%s"},\
        {"column":"TO_CHAR(TO_DATE(CREATE_DATE,'YYYY-MM-DD HH24:MI:SS'),'YYYY-MM-DD')","exp":"<=","value":"%s"},\
        {"column":"CHECK_TYPE","exp":"like","value":"2"},\
        {"column":"LOCKED_STATUS","exp":"=","value":0},\
        {"column":"DELETE_STATUS","orderType":"default","orderKey":"","direction":"ASC"}\
    ]"""%(businessName,str(startDate),str(endDate)),   
    'additionalParams':'{}'
}

再次證明程式設計達到目的的方法遠不止一次,但是各種方法之間在可讀性、效能、複雜度上卻存有差別。小爬也是告誡自己,永遠要本著化繁為簡的思想去程式設計。

 

  另外,小爬我給部門同事製作了一個內網資料爬取到excel的小工具,其中需要用到python中網頁附件的下載、excel儲存、txt儲存,excel超連結生成等功能,經過摸索,終於搞定!

主要思路是,post請求(引數:“編號”)得到json檔案,將json中主要欄位儲存到列表中,取出“附件”欄位值,再去表單主頁面原始碼中看“附件”的url,進而構造出對應的附件url地址。略去不表,下面重點講如何下載附件、判斷伺服器中附件的名稱和檔案字尾等。

判斷檔名和字尾的程式碼如下:

#定義fileType方法,得到檔案型別
def get_fileType(response):
    #fileType=response.headers['Content-Type']  #  image/jpeg;charset=UTF-8    #Content-Type: application/pdf;charset=UTF-8
    fileType=response.headers['Content-Disposition']  #Content-Disposition: attachment; filename=%E6%9C%96%B0%E8%90%A5%E4%B8%9A%E6%89%A7%E7%85%A7.pdf
    #fileType=re.search(".*?/(.*?);.*?",fileType)
    fileType=os.path.splitext(fileType)[-1][1:].lower()
    return fileType

可以看到我們請求附件對應的url地址時,伺服器返回的Response Headers標頭檔案中,Content-Disposition和Content-Type欄位能看到檔名和字尾,需要注意的是,實際使用時,小爬發現Content-Type欄位並不總是存在,此時可能需要使用try……except方法對兩個欄位進行嘗試,提升程式的容錯能力。

下載附件、寫入excel並生成超連結用到的示例程式碼如下:

response=requests.session().get(url) fileType=get_fileType(response) with open(".\\Attachment\\附件.%s"%(fileType), "wb") as code:   code.write(response.content) #下載附件 sheet['A1'].hyperlink = ".\\Attachment\\附件.%s"%(fileType)

 

 

  小爬再說說製作簡易進度條這件事兒:如果我們要製作很酷炫、多功能的GUI使用者介面,當然首選pyqt5、wxPython、tkinter等著名GUI庫。但是筆者如果只是想把指令碼封裝為exe,給一般使用者使用,只是需要一個簡單的進度提醒,如果對美觀等沒有特別的要求,則用Selenium+js的方法更容易實現。

小爬我的爬蟲工具首先用selenium的driver方法打開了瀏覽器,之後的爬取過程,都是儘可能呼叫requests方法,此時網頁並不會跟著重新整理。原始的網頁左上角如下圖所示:

小爬通過selenium載入js的方法,可以更改“抽查記錄資訊”這個div標籤在本地瀏覽器顯示的文字為“我想要輸出的進度資訊”,且不會對伺服器造成任何變化。巧妙達到製作進度的要求。

該div的html資訊,可以通過查詢網頁原始碼得到:“<div class="haf-form-title">抽查記錄資訊</div>”,那麼讓這個頁面元素對應的文字更改需要的程式碼很簡單,先用querySelector方法定位,再更改attr屬性,示例程式碼如下:

driver.execute_script('document.querySelector("div.haf-form-title").textContent="%s 已完成%d行資料."'%(name,Num)) 

是的,這行程式碼足夠顯示基本的進度了,你可以傳入更多引數來顯示總數、實時計數和百分比等,靈活運用該方法即可。實際效果如下:

 

                                            方法很多,我們只要做到“活學活用”即可!