項目名稱:登錄考勤管理系統爬取我的考勤信息並寫入excel表格html
編寫目的:python
公司常常要統計員工的考勤信息,而員工每次都要登錄考勤系統,再複製相關信息出來,貼到EXCEL,再轉給統計人員,統計人員再挨個覈對,麻煩無比,實在是看不下去了。我擦。。。。。ajax
因爲登錄的是內網的考勤系統,出了公司就登錄不了,因此本篇文章僅作參考,來體驗一下cookie、post與get登錄使用。編程
先說用用到哪些知識吧:json
一、tkinter Gui編程,寫爬蟲沒有GUI怎麼能行cookie
二、cookiesession
三、post,getapp
其實很少是吧,簡單。ide
要爬取一個網站,總得要矢爬的網站登錄地址,及登錄信息吧。分析一下看看。。。函數
好的,咱們獲取了以下信息:
登錄地址:LoginUrl = 'http://17.xx.xx.xx/j_acegi_security_check'
post提交:post_data = {'j_username':'your_username','j_password':'your_password'}
那就開工 ,寫一下登錄代碼吧
#!/usr/bin/env python
# _*_ coding:utf-8 _*_
import urllib
import urllib2
import cookielib
LoginUrl = 'http://17.xx.xx.xx/j_acegi_security_check'
post_data = {'j_username':'your_username','j_password':'your_password'}
# 定義一個類
class kaoqin_login(object):
def __init__(self):
self.cj = cookielib.CookieJar() # 初始化一個cookie補全,用於存儲cookie
self.handler = urllib2.HTTPCookieProcessor(self.cj) # 建立一個cookie處理器
self.opener = urllib2.build_opener(self.handler) # 建立一個功能強大的opener
def login(self,url,post): # post提交
post_data = urllib.urlencode(post) # 編碼post數據爲標準格式
req = urllib2.Request(url,post_data) # 作爲data參數傳給Request對象,此處也能夠寫成data=post_data
response = self.opener.open(req) # 登錄網站,獲取返回結果
print response.url
if __name__ == '__main__':
cls = kaoqin_login()
cls.login(LoginUrl,post_data)
返回信息以下:
http://17.xx.xx.xx/;jsessionid=7AC236C4B9C5E653208D59ECCE55E8EF
好,登錄成功了,以後怎麼辦呢?嗯,對了,找一下考勤頁面在哪裏,分析一下吧
瞧,真實頁面的信息就這些了。本身把url和post信息整理出來吧,注意,提交表單信息要寫成字典,url呢,問號以前的都是了。
示例代碼
#!/usr/bin/env python # _*_ coding:utf-8 _*_ import urllib import urllib2 import cookielib import json LoginUrl = 'http://17.xx.xx.xx/j_acegi_security_check' post_data = {'j_username':'your_username','j_password':'your_password'} # 定義一個類 class kaoqin_login(object): def __init__(self): self.cj = cookielib.CookieJar() # 初始化一個cookie補全,用於存儲cookie self.handler = urllib2.HTTPCookieProcessor(self.cj) # 建立一個cookie處理器 self.opener = urllib2.build_opener(self.handler) # 建立一個功能強大的opener def login(self,url,post): # post提交 post_data = urllib.urlencode(post) # 編碼post數據爲標準html格式 req = urllib2.Request(url,post_data) # 作爲data參數傳給Request對象,由request作post數據隱式提交,此處也能夠寫成data=post_data response = self.opener.open(req) # 登錄網站,獲取返回結果 print response.url def get_response(self,url,post): # get方式提交數據 get = urllib.urlencode(post) # 將提交的數據編碼成html標準格式 response = self.opener.open(url,get) # 將標準的編碼數據放到url後面,變成真正的url地址 try: JsData = json.loads(response.read()) return JsData['datas'] except Exception as e: return False if __name__ == '__main__': cls = kaoqin_login() cls.login(LoginUrl,post_data) Login = 'http://17.xx.xx.xx/km/attendance/km_attendance_main/kmAttendanceMain.do' data ={ 'method':'data' ,'categoryId':'' ,'q.s_raq':0.5949037911774411 ,'pageno':2 ,'rowsize':15 ,'orderby':'fdAttendanceDate' ,'ordertype':'down' ,'s_ajax':'true' } jsdata = cls.get_response(Login,data) print jsdata
好了,數據取到了,發一下所有的代碼吧.
上面的代碼是我重點想說的,下面的代碼就不是那麼重要了,關於excel的讀取,博客裏有詳細的解釋,GUI開發也有相關文檔。
#!/usr/bin/env python # _*_ coding:utf-8 _*_ import urllib import urllib2 import cookielib import json,re,time ''' 由於腳本只取了前4頁數據,因此最好用來爬取本月的考勤信息 如需爬取其它月的信息,須要更改代碼 for i in range(1,5) 將5改成更大,最大15 ''' # ==============框口區================== from Tkinter import * from ScrolledText import ScrolledText import tkFileDialog root = Tk() root.iconbitmap('../data/spider_128px_1169260_easyicon.net.ico') root.title('郵儲我的考勤記錄爬蟲') # 第一行 Label(root,text='考勤日期',fg='#8F8C8F').grid(row=0,column=0) var_date1 = StringVar() var_date1.set('2016-01-01') var_date2 = StringVar() var_date2.set('2016-01-31') date1 = Entry(root,fg='red',bg='#FFFACD',textvariable=var_date1) date1.grid(row=0,column=1) Label(root,text='至',fg='#8F8C8F').grid(row=0,column=2) date2 =Entry(root,fg='red',bg='#FFFACD',textvariable=var_date2) date2.grid(row=0,column=3) # 第二行 Label(root,text='用戶密碼文件',fg='#8F8C8F').grid(row=1,column=0) var = StringVar() def get_file(): filename = tkFileDialog.askopenfilename(initialdir='c:') var.set(filename) def get_file_des(): filename = tkFileDialog.askopenfilename(initialdir='c:') ent_des.set(filename) var.set(r'C:\spider_dev\data\kaoqin_user_pwd.txt') Ent = Entry(root,textvariable=var).grid(row=1,column=1) Button(root,text='選擇文件',command=get_file,fg='#006400').grid(row=1,column=2) ent_des = StringVar() timpsta = '%d'%(time.time()*1000) ent_des.set(r'C:\spider_dev\data\kaoqin_%s.xls'%str(timpsta)) Ent_d = Entry(root,textvariable=ent_des).grid(row=2,column=1,sticky=N) Button(root,text='目標文件',command=get_file_des,fg='#006400').grid(row=2,column=2,sticky=N) T_logi_info = ScrolledText(root,width=20) T_logi_info.grid(row=2,column=0) # 標籤 v_lable = StringVar() v_lable.set('錯誤記錄...') Label(root,textvariable=v_lable,fg='red').grid(row=3,column=0) # 信息框 text = ScrolledText(root,bg='#87CEFA') text.grid(row=0,column=4,rowspan=3) # ==============框口區================== # --------------爬蟲區----------------- class kaoqin_login(object): def __init__(self): self.cj = cookielib.CookieJar() self.handler = urllib2.HTTPCookieProcessor(self.cj) self.opener = urllib2.build_opener(self.handler) def login(self,url,post): post_data = urllib.urlencode(post) req = urllib2.Request(url,post_data) response = self.opener.open(req) if response.code == 200: return True else: return False def get_response(self,url,post): get = urllib.urlencode(post) response = self.opener.open(url,get) try: JsData = json.loads(response.read()) return JsData['datas'] except Exception as e: return False def post_page(self,pages): get={ 'method':'data' ,'categoryId':'' ,'q.s_raq':0.9518796035349586 ,'pageno':pages ,'rowsize':15 ,'orderby':'fdAttendanceDate' ,'ordertype':'down' ,'s_ajax':'true' } return get def get_data_file(self,filename): with open(filename,'rb') as f: data = f.read().split('\r\n') return data # --------------爬蟲區----------------- # <------------Excel文件數據寫入--------> from openpyxl.workbook import Workbook from openpyxl.writer.excel import ExcelWriter from openpyxl.cell import get_column_letter wb = Workbook() ew = ExcelWriter(workbook=wb) ws = wb.worksheets[0] ws.title = u'第一個sheet' # 數據開始寫入的行、列、無組數據及文件名 def write_2_excel(r,c,t_data,FileName): i = r for record in t_data: for x in range(c,len(record)+c): col = get_column_letter(x) ws.cell('%s%s'%(col,i)).value ='%s'%record[x-c] i+=1 ew.save(filename=FileName) # <------------Excel文件數據寫入--------> # ************主函數***************** if __name__ == '__main__': def Spider(): #初始化實例 cls = kaoqin_login() if var.get(): List_username = cls.get_data_file(var.get()) else: v_lable.set('密碼文件對嗎???') #出勤狀態,如正常、遲到 Real_Data = [] #按用戶獲取數據 for each_user in List_username: #標題數據,好比excel的頭部,日期,星期、上下午 Title_Data = [] #網站登錄用戶信息 Pno,Pname,username,password = each_user.split(',')[0],each_user.split(',')[1],each_user.split(',')[2],each_user.split(',')[3] LoginUrl = 'http://17.xx.xx.xx/j_acegi_security_check' LoginPost ="{'j_username':'%s','j_password':'%s'}"%(username,password) LoginPost = eval(LoginPost) if cls.login(LoginUrl,LoginPost): #進入考勤頁面 Kq_Url = 'http://17.xx.xx.xx/km/attendance/km_attendance_main/kmAttendanceMain.do' tmp1=[] tmp2=[] tmp3=[] tmp4=[] tmp4.append(Pno) tmp4.append(Pname) #考勤post列表,第一頁到第四頁數據 for i in range(1,5): jsret = cls.get_response(Kq_Url,cls.post_page(i)) if jsret: pass else: T_logi_info.insert(END,Pname+'登錄失敗'+ '\n') T_logi_info.see(END) break #對考勤數據處理 for each_day in jsret: v_date=v_week=v_Bc=v_status=v_name='' start_date = var_date1.get() end_date = var_date2.get() if start_date and end_date: for item_dic in each_day: col = item_dic['col'] if col == 'fdAttendanceDate': v_date = item_dic['value'].strip() if col == 'fdWeek': v_week = item_dic['value'].strip() if col == 'fdBc': v_Bc = item_dic['value'].strip() if col == 'fdStatus': v_status = item_dic['value'].strip() v_status = re.search('>(.*?)<',v_status).group(1) if col == 'fdPerson.fdName': v_name = item_dic['value'] if v_date >= start_date and v_date <= end_date: tmp1.append(v_date) tmp2.append(v_week) tmp3.append(v_Bc) tmp4.append(v_status) text.insert(END, v_name +',' + v_date+','+v_week+','+v_Bc+','+v_status+'\n') text.see(END) text.update() else: v_lable.set('時間不對吧...') pass Title_Data.append(tmp1) Title_Data.append(tmp2) Title_Data.append(tmp3) Real_Data.append(tmp4) write_2_excel(1,3,Title_Data,ent_des.get()) write_2_excel(4,1,Real_Data,ent_des.get()) #第三行 Button(root,text='開始爬取',fg='#3CB371',command=Spider).grid(row=3,column=4) root.mainloop()
好了,看看一下實際效果吧