本次工具主要利用python easygui模塊的inputbox讓用戶首次輸入登陸信息,作為網站requests-post請求的data字段,觀察XHR(異步加載)的數據包,構造post請求,利用requests庫的session功能保持登陸狀態,進而請求其他子頁下的所需信息,最終爬取到本地excel文件中。
我們手工登陸后,網站會進行跳轉,通過瀏覽器F12查看network頁簽,logindo頁面可以看到登陸后服務器在response headers欄 有set-cookie:
但是網站登陸redirect后的頁面並沒有看到:response.cookies;
如果利用response.cookies將得到一個空的RequestsCookieJar對象,無法為后續的信息爬取提供cookies字段放入headers欄,此時可以考慮用response.session保持首次登陸狀態,后續服務器端在session有效期內不會再要求頁面傳入登陸信息,主要代碼如下,:
import requests,json,easygui,os,sys,math,time from openpyxl import load_workbook msg = "請輸入OA用戶名和密碼" title = "用戶登錄入口" user_info = [] user_info = easygui.multpasswordbox(msg,title,("用戶名","密碼")) start = time.time() pwd = os.getcwd() wb = load_workbook(filename=pwd+u"\\info_list.xlsx") sheet=wb[u"參數"] base_url='http://******.com/srm/supplier/Criteria.do' loginData={'redirect':'','username':user_info[0],'password':user_info[1]}
#下面的data-search字典中,condition鍵其實就是Oracle數據庫的select條件在網頁中的集成形式,通過設置exp表達式以及value等,可以靈活的查詢,突破頁面集成的查詢默認條件限制。 data_search={ 'page':1,#控制請求的頁面數 'rows':100,#控制每頁顯示的行數 'condition':'[{"orConditionList":[{"column":"S.S_SUPPLIER_NO","exp":"like","value":"00001"}]},{"column":"S.S_SUPPLIER_NO","orderType":"default","orderKey":"","direction":"DESC"}]', 'additionalParams':'{}' } s=requests.session() def login(s,loginData,data_search): try: response=s.post('http://******.com/portal/u/a/login.do',loginData) if response.status_code==200: print("login_success") except requests.ConnectionError as e: print('Error',e.args) def getjson(s,base_url,data_search): try: response=s.post(base_url,data_search) if response.status_code==200: #print("vendor_info_yes") return response.json() except requests.ConnectionError as e: print('Error',e.args) if __name__ == "__main__": ss=login(s,loginData,data_search) page=getjson(s,base_url,data_search) maxNum=math.ceil(page['total']/100) #計算出總的信息顯示所需頁面數 for pageNum in range(1,500): if pageNum==maxNum+1: wb.save(filename=pwd+u"\\info_list.xlsx") #最后一頁寫完后,進行保存excel操作 end = time.time() time.sleep(2) sys.exit(0) data_search['page']=pageNum #修改字典的‘page’鍵對應值,逐頁請求服務器數據 page=getjson(s,base_url,data_search) listlen=len(page['rows']) #由於最后一次得到的行數不見得是100行,所以需要動態獲取列表長度,作為循環次數的依據。 for i in range(listlen): #對請求后得到的json文件進行解析,類似於字典,字典中含有列表,需要注意,當部分字段為空時,字典中部分元素可能不存在,需要判斷字典。 sheet['A%d' %((pageNum-1)*100+i+2)].value = page['rows'][i]['supplierNo'] sheet['B%d' %((pageNum-1)*100+i+2)].value = page['rows'][i]['companyName'] if 'linkMan1' in page['rows'][i].keys(): sheet['C%d' %((pageNum-1)*100+i+2)].value = page['rows'][i]['linkMan1'] if 'phone1' in page['rows'][i].keys(): sheet['D%d' %((pageNum-1)*100+i+2)].value = page['rows'][i]['phone1'] if 'email1' in page['rows'][i].keys(): sheet['E%d' %((pageNum-1)*100+i+2)].value = page['rows'][i]['email1'] if 'legalRepresentative' in page['rows'][i].keys(): sheet['F%d' %((pageNum-1)*100+i+2)].value = page['rows'][i]['legalRepresentative'] if 'email2' in page['rows'][i].keys(): sheet['G%d' %((pageNum-1)*100+i+2)].value = page['rows'][i]['email2'] print(pageNum)
該程序還有一個可以完善的地方:就是封裝后給用戶使用時不夠直觀,需要利用Tkinter等制作簡易gui進度條百分比及剩余時間展示。