小爬最近隨着對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並生成超鏈接用到的示例代碼如下:
小爬再說說制作簡易進度條這件事兒:如果我們要制作很酷炫、多功能的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))
是的,這行代碼足夠顯示基本的進度了,你可以傳入更多參數來顯示總數、實時計數和百分比等,靈活運用該方法即可。實際效果如下:

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

